diff options
577 files changed, 12478 insertions, 7068 deletions
diff --git a/components/layout/display_list/builder.rs b/components/layout/display_list/builder.rs index 17f946f7187..2c0f6d612e1 100644 --- a/components/layout/display_list/builder.rs +++ b/components/layout/display_list/builder.rs @@ -60,10 +60,10 @@ use style::logical_geometry::{LogicalMargin, LogicalPoint, LogicalRect}; use style::properties::{style_structs, ComputedValues}; use style::servo::restyle_damage::ServoRestyleDamage; use style::values::computed::effects::SimpleShadow; -use style::values::computed::image::{Image, ImageLayer}; +use style::values::computed::image::Image; use style::values::computed::{ClipRectOrAuto, Gradient, LengthOrAuto}; use style::values::generics::background::BackgroundSize; -use style::values::generics::image::{GradientKind, PaintWorklet}; +use style::values::generics::image::PaintWorklet; use style::values::specified::ui::CursorKind; use style::values::RGBA; use style_traits::ToCss; @@ -732,12 +732,8 @@ impl Fragment { // http://www.w3.org/TR/CSS21/colors.html#background let background = style.get_background(); for (i, background_image) in background.background_image.0.iter().enumerate().rev() { - let background_image = match *background_image { - ImageLayer::None => continue, - ImageLayer::Image(ref image) => image, - }; - match *background_image { + Image::None => {}, Image::Gradient(ref gradient) => { self.build_display_list_for_background_gradient( state, @@ -975,15 +971,15 @@ impl Fragment { display_list_section, ); - let display_item = match gradient.kind { - GradientKind::Linear(angle_or_corner) => { - let (gradient, stops) = gradient::linear( - style, - placement.tile_size, - &gradient.items[..], - angle_or_corner, - gradient.repeating, - ); + let display_item = match gradient { + Gradient::Linear { + ref direction, + ref items, + ref repeating, + compat_mode: _, + } => { + let (gradient, stops) = + gradient::linear(style, placement.tile_size, items, *direction, *repeating); let item = webrender_api::GradientDisplayItem { gradient, bounds: placement.bounds.to_f32_px(), @@ -993,14 +989,20 @@ impl Fragment { }; DisplayItem::Gradient(CommonDisplayItem::with_data(base, item, stops)) }, - GradientKind::Radial(ref shape, ref center) => { + Gradient::Radial { + ref shape, + ref position, + ref items, + ref repeating, + compat_mode: _, + } => { let (gradient, stops) = gradient::radial( style, placement.tile_size, - &gradient.items[..], + items, shape, - center, - gradient.repeating, + position, + *repeating, ); let item = webrender_api::RadialGradientDisplayItem { gradient, @@ -1011,6 +1013,7 @@ impl Fragment { }; DisplayItem::RadialGradient(CommonDisplayItem::with_data(base, item, stops)) }, + Gradient::Conic { .. } => unimplemented!(), }; state.add_display_item(display_item); }); @@ -1122,22 +1125,20 @@ impl Fragment { let border_radius = border::radii(bounds, border_style_struct); let border_widths = border.to_physical(style.writing_mode); - if let ImageLayer::Image(ref image) = border_style_struct.border_image_source { - if self - .build_display_list_for_border_image( - state, - style, - base.clone(), - bounds, - image, - border_widths, - ) - .is_some() - { - return; - } - // Fallback to rendering a solid border. + if self + .build_display_list_for_border_image( + state, + style, + base.clone(), + bounds, + &border_style_struct.border_image_source, + border_widths, + ) + .is_some() + { + return; } + if border_widths == SideOffsets2D::zero() { return; } @@ -1224,30 +1225,37 @@ impl Fragment { height = image.height; NinePatchBorderSource::Image(image.key?) }, - Image::Gradient(ref gradient) => match gradient.kind { - GradientKind::Linear(angle_or_corner) => { - let (wr_gradient, linear_stops) = gradient::linear( - style, - border_image_area, - &gradient.items[..], - angle_or_corner, - gradient.repeating, - ); + Image::Gradient(ref gradient) => match **gradient { + Gradient::Linear { + ref direction, + ref items, + ref repeating, + compat_mode: _, + } => { + let (wr_gradient, linear_stops) = + gradient::linear(style, border_image_area, items, *direction, *repeating); stops = linear_stops; NinePatchBorderSource::Gradient(wr_gradient) }, - GradientKind::Radial(ref shape, ref center) => { + Gradient::Radial { + ref shape, + ref position, + ref items, + ref repeating, + compat_mode: _, + } => { let (wr_gradient, radial_stops) = gradient::radial( style, border_image_area, - &gradient.items[..], + items, shape, - center, - gradient.repeating, + position, + *repeating, ); stops = radial_stops; NinePatchBorderSource::RadialGradient(wr_gradient) }, + Gradient::Conic { .. } => unimplemented!(), }, _ => return None, }; diff --git a/components/layout/display_list/gradient.rs b/components/layout/display_list/gradient.rs index e683bbb963c..b816bca753f 100644 --- a/components/layout/display_list/gradient.rs +++ b/components/layout/display_list/gradient.rs @@ -7,8 +7,8 @@ use app_units::Au; use euclid::default::{Point2D, Size2D, Vector2D}; use style::properties::ComputedValues; use style::values::computed::image::{EndingShape, LineDirection}; -use style::values::computed::{Angle, GradientItem, LengthPercentage, Percentage, Position}; -use style::values::generics::image::{Circle, ColorStop, Ellipse, ShapeExtent}; +use style::values::computed::{Angle, Color, LengthPercentage, Percentage, Position}; +use style::values::generics::image::{Circle, ColorStop, Ellipse, GradientItem, ShapeExtent}; use webrender_api::{ExtendMode, Gradient, GradientBuilder, GradientStop, RadialGradient}; /// A helper data structure for gradients. @@ -78,7 +78,7 @@ fn ellipse_size_keyword( fn convert_gradient_stops( style: &ComputedValues, - gradient_items: &[GradientItem], + gradient_items: &[GradientItem<Color, LengthPercentage>], total_length: Au, ) -> GradientBuilder { // Determine the position of each stop per CSS-IMAGES § 3.4. @@ -237,7 +237,7 @@ fn position_to_offset(position: &LengthPercentage, total_length: Au) -> f32 { pub fn linear( style: &ComputedValues, size: Size2D<Au>, - stops: &[GradientItem], + stops: &[GradientItem<Color, LengthPercentage>], direction: LineDirection, repeating: bool, ) -> (Gradient, Vec<GradientStop>) { @@ -303,7 +303,7 @@ pub fn linear( pub fn radial( style: &ComputedValues, size: Size2D<Au>, - stops: &[GradientItem], + stops: &[GradientItem<Color, LengthPercentage>], shape: &EndingShape, center: &Position, repeating: bool, diff --git a/components/layout_2020/display_list/gradient.rs b/components/layout_2020/display_list/gradient.rs index f1e5c1a3c1a..09f5be610c2 100644 --- a/components/layout_2020/display_list/gradient.rs +++ b/components/layout_2020/display_list/gradient.rs @@ -4,9 +4,8 @@ use style::properties::ComputedValues; use style::values::computed::image::{EndingShape, Gradient, LineDirection}; -use style::values::computed::{GradientItem, Length, Position}; -use style::values::generics::image::GenericGradientKind as Kind; -use style::values::generics::image::{Circle, ColorStop, Ellipse, ShapeExtent}; +use style::values::computed::{Color, Length, LengthPercentage, Position}; +use style::values::generics::image::{Circle, ColorStop, Ellipse, GradientItem, ShapeExtent}; use webrender_api::{self as wr, units}; pub(super) fn build( @@ -15,36 +14,51 @@ pub(super) fn build( layer: &super::background::BackgroundLayer, builder: &mut super::DisplayListBuilder, ) { - let extend_mode = if gradient.repeating { - wr::ExtendMode::Repeat - } else { - wr::ExtendMode::Clamp - }; - match &gradient.kind { - Kind::Linear(line_direction) => build_linear( + match gradient { + Gradient::Linear { + ref items, + ref direction, + ref repeating, + compat_mode: _, + } => build_linear( style, - &gradient.items, - line_direction, - extend_mode, + items, + direction, + if *repeating { + wr::ExtendMode::Repeat + } else { + wr::ExtendMode::Clamp + }, &layer, builder, ), - Kind::Radial(ending_shape, center) => build_radial( + Gradient::Radial { + ref shape, + ref position, + ref items, + ref repeating, + compat_mode: _, + } => build_radial( style, - &gradient.items, - ending_shape, - center, - extend_mode, + items, + shape, + position, + if *repeating { + wr::ExtendMode::Repeat + } else { + wr::ExtendMode::Clamp + }, &layer, builder, ), + Gradient::Conic { .. } => unimplemented!(), } } /// https://drafts.csswg.org/css-images-3/#linear-gradients pub(super) fn build_linear( style: &ComputedValues, - items: &[GradientItem], + items: &[GradientItem<Color, LengthPercentage>], line_direction: &LineDirection, extend_mode: wr::ExtendMode, layer: &super::background::BackgroundLayer, @@ -144,7 +158,7 @@ pub(super) fn build_linear( /// https://drafts.csswg.org/css-images-3/#radial-gradients pub(super) fn build_radial( style: &ComputedValues, - items: &[GradientItem], + items: &[GradientItem<Color, LengthPercentage>], shape: &EndingShape, center: &Position, extend_mode: wr::ExtendMode, @@ -244,7 +258,7 @@ pub(super) fn build_radial( /// https://drafts.csswg.org/css-images-4/#color-stop-fixup fn fixup_stops( style: &ComputedValues, - items: &[GradientItem], + items: &[GradientItem<Color, LengthPercentage>], gradient_line_length: Length, ) -> Vec<wr::GradientStop> { // Remove color transititon hints, which are not supported yet. diff --git a/components/layout_2020/display_list/mod.rs b/components/layout_2020/display_list/mod.rs index dccee5ea71a..af0797d30b6 100644 --- a/components/layout_2020/display_list/mod.rs +++ b/components/layout_2020/display_list/mod.rs @@ -333,7 +333,7 @@ impl<'a> BuilderForBoxFragment<'a> { } fn build_background(&mut self, builder: &mut DisplayListBuilder) { - use style::values::computed::image::{Image, ImageLayer}; + use style::values::computed::image::Image; let b = self.fragment.style.get_background(); let background_color = self.fragment.style.resolve_color(b.background_color); if background_color.alpha > 0 { @@ -345,85 +345,80 @@ impl<'a> BuilderForBoxFragment<'a> { builder.wr.push_rect(&common, rgba(background_color)) } // Reverse because the property is top layer first, we want to paint bottom layer first. - for (index, layer) in b.background_image.0.iter().enumerate().rev() { - match layer { - ImageLayer::None => {}, - ImageLayer::Image(image) => match image { - Image::Gradient(gradient) => { - let intrinsic = IntrinsicSizes { - width: None, - height: None, - ratio: None, - }; - if let Some(layer) = - &background::layout_layer(self, builder, index, intrinsic) - { - gradient::build(&self.fragment.style, gradient, layer, builder) - } - }, - Image::Url(image_url) => { - // FIXME: images won’t always have in intrinsic width or height - // when support for SVG is added. - // Or a WebRender `ImageKey`, for that matter. - let (width, height, key) = match image_url.url() { - Some(url) => { - match builder.context.get_webrender_image_for_url( - self.fragment.tag, - url.clone(), - UsePlaceholder::No, - ) { - Some(WebRenderImageInfo { - width, - height, - key: Some(key), - }) => (width, height, key), - _ => continue, - } - }, - None => continue, - }; - - // FIXME: https://drafts.csswg.org/css-images-4/#the-image-resolution - let dppx = 1.0; - - let intrinsic = IntrinsicSizes { - width: Some(Length::new(width as f32 / dppx)), - height: Some(Length::new(height as f32 / dppx)), - // FIXME https://github.com/w3c/csswg-drafts/issues/4572 - ratio: Some(width as f32 / height as f32), - }; - - if let Some(layer) = - background::layout_layer(self, builder, index, intrinsic) - { - let image_rendering = - image_rendering(self.fragment.style.clone_image_rendering()); - if layer.repeat { - builder.wr.push_repeating_image( - &layer.common, - layer.bounds, - layer.tile_size, - layer.tile_spacing, - image_rendering, - wr::AlphaType::PremultipliedAlpha, - key, - wr::ColorF::WHITE, - ) - } else { - builder.wr.push_image( - &layer.common, - layer.bounds, - image_rendering, - wr::AlphaType::PremultipliedAlpha, - key, - wr::ColorF::WHITE, - ) + for (index, image) in b.background_image.0.iter().enumerate().rev() { + match image { + Image::None => {}, + Image::Gradient(ref gradient) => { + let intrinsic = IntrinsicSizes { + width: None, + height: None, + ratio: None, + }; + if let Some(layer) = &background::layout_layer(self, builder, index, intrinsic) + { + gradient::build(&self.fragment.style, &gradient, layer, builder) + } + }, + Image::Url(ref image_url) => { + // FIXME: images won’t always have in intrinsic width or height + // when support for SVG is added. + // Or a WebRender `ImageKey`, for that matter. + let (width, height, key) = match image_url.url() { + Some(url) => { + match builder.context.get_webrender_image_for_url( + self.fragment.tag, + url.clone(), + UsePlaceholder::No, + ) { + Some(WebRenderImageInfo { + width, + height, + key: Some(key), + }) => (width, height, key), + _ => continue, } + }, + None => continue, + }; + + // FIXME: https://drafts.csswg.org/css-images-4/#the-image-resolution + let dppx = 1.0; + + let intrinsic = IntrinsicSizes { + width: Some(Length::new(width as f32 / dppx)), + height: Some(Length::new(height as f32 / dppx)), + // FIXME https://github.com/w3c/csswg-drafts/issues/4572 + ratio: Some(width as f32 / height as f32), + }; + + if let Some(layer) = background::layout_layer(self, builder, index, intrinsic) { + let image_rendering = + image_rendering(self.fragment.style.clone_image_rendering()); + if layer.repeat { + builder.wr.push_repeating_image( + &layer.common, + layer.bounds, + layer.tile_size, + layer.tile_spacing, + image_rendering, + wr::AlphaType::PremultipliedAlpha, + key, + wr::ColorF::WHITE, + ) + } else { + builder.wr.push_image( + &layer.common, + layer.bounds, + image_rendering, + wr::AlphaType::PremultipliedAlpha, + key, + wr::ColorF::WHITE, + ) } - }, - // Gecko-only value, represented as a (boxed) empty enum on non-Gecko. - Image::Rect(rect) => match **rect {}, + } }, + // Gecko-only value, represented as a (boxed) empty enum on non-Gecko. + Image::Rect(ref rect) => match **rect {}, } } } diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index 040b4c3f3cf..c129582a358 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -303,7 +303,11 @@ impl InlineFormattingContext { panic!("display:none does not generate an abspos box") }, }; - let hoisted_box = box_.clone().to_hoisted(initial_start_corner, tree_rank); + let hoisted_box = AbsolutelyPositionedBox::to_hoisted( + box_.clone(), + initial_start_corner, + tree_rank, + ); let hoisted_fragment = hoisted_box.fragment.clone(); ifc.push_hoisted_box_to_positioning_context(hoisted_box); ifc.current_nesting_level.fragments_so_far.push( @@ -786,7 +790,7 @@ impl TextRun { glyphs, text_decoration_line: ifc.current_nesting_level.text_decoration_line, })); - if runs.is_empty() { + if runs.as_slice().is_empty() { break; } else { // New line diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 33bba78de96..eb4a03be62e 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -315,7 +315,8 @@ impl BlockLevelBox { )) }, BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { - let hoisted_box = box_.clone().to_hoisted(Vec2::zero(), tree_rank); + let hoisted_box = + AbsolutelyPositionedBox::to_hoisted(box_.clone(), Vec2::zero(), tree_rank); let hoisted_fragment = hoisted_box.fragment.clone(); positioning_context.push(hoisted_box); Fragment::AbsoluteOrFixedPositioned(AbsoluteOrFixedPositionedFragment { diff --git a/components/layout_2020/lib.rs b/components/layout_2020/lib.rs index 6b7a08ec29b..be5008035a5 100644 --- a/components/layout_2020/lib.rs +++ b/components/layout_2020/lib.rs @@ -3,8 +3,6 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #![deny(unsafe_code)] -#![feature(arbitrary_self_types)] -#![feature(exact_size_is_empty)] #[macro_use] extern crate serde; diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index 899b2b39e61..cb71ad521c4 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -100,7 +100,7 @@ impl AbsolutelyPositionedBox { } pub(crate) fn to_hoisted( - self: Arc<Self>, + self_: Arc<Self>, initial_start_corner: Vec2<Length>, tree_rank: usize, ) -> HoistedAbsolutelyPositionedBox { @@ -124,7 +124,7 @@ impl AbsolutelyPositionedBox { } } - let box_offsets = self.contents.style.box_offsets(); + let box_offsets = self_.contents.style.box_offsets(); HoistedAbsolutelyPositionedBox { tree_rank, box_offsets: Vec2 { @@ -140,7 +140,7 @@ impl AbsolutelyPositionedBox { ), }, fragment: ArcRefCell::new(None), - absolutely_positioned_box: self, + absolutely_positioned_box: self_, } } } diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 064ceb5148e..1ec4c92fcf0 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -914,10 +914,6 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> { false } - fn exported_part(&self, _: &Atom) -> Option<Atom> { - None - } - fn imported_part(&self, _: &Atom) -> Option<Atom> { None } @@ -1441,11 +1437,6 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> { false } - fn exported_part(&self, _: &Atom) -> Option<Atom> { - debug!("ServoThreadSafeLayoutElement::exported_part called"); - None - } - fn imported_part(&self, _: &Atom) -> Option<Atom> { debug!("ServoThreadSafeLayoutElement::imported_part called"); None diff --git a/components/layout_thread_2020/dom_wrapper.rs b/components/layout_thread_2020/dom_wrapper.rs index 92a9f3f005b..7b1da3454a0 100644 --- a/components/layout_thread_2020/dom_wrapper.rs +++ b/components/layout_thread_2020/dom_wrapper.rs @@ -922,10 +922,6 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> { false } - fn exported_part(&self, _: &Atom) -> Option<Atom> { - None - } - fn imported_part(&self, _: &Atom) -> Option<Atom> { None } @@ -1447,11 +1443,6 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> { false } - fn exported_part(&self, _: &Atom) -> Option<Atom> { - debug!("ServoThreadSafeLayoutElement::exported_part called"); - None - } - fn imported_part(&self, _: &Atom) -> Option<Atom> { debug!("ServoThreadSafeLayoutElement::imported_part called"); None diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 3c9555ba659..021757a4ad1 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -3992,8 +3992,8 @@ class CGMemberJITInfo(CGThing): protoID: PrototypeList::ID::${name} as u16, }, __bindgen_anon_3: JSJitInfo__bindgen_ty_3 { depth: ${depth} }, - _bitfield_1: unsafe { - mem::transmute(new_jsjitinfo_bitfield_1!( + _bitfield_1: __BindgenBitfieldUnit::new( + new_jsjitinfo_bitfield_1!( JSJitInfo_OpType::${opType} as u8, JSJitInfo_AliasSet::${aliasSet} as u8, JSValueType::${returnType} as u8, @@ -4004,8 +4004,8 @@ class CGMemberJITInfo(CGThing): ${isLazilyCachedInSlot}, ${isTypedMethod}, ${slotIndex}, - )) - }, + ).to_ne_bytes() + ), } """, opName=opName, @@ -5988,6 +5988,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::error::throw_type_error', 'js::error::throw_internal_error', 'js::rust::wrappers::Call', + 'js::jsapi::__BindgenBitfieldUnit', 'js::jsapi::CallArgs', 'js::jsapi::CurrentGlobalOrNull', 'js::rust::wrappers::GetPropertyKeys', diff --git a/components/script/dom/bindings/root.rs b/components/script/dom/bindings/root.rs index 4f4d376e951..59f9b964564 100644 --- a/components/script/dom/bindings/root.rs +++ b/components/script/dom/bindings/root.rs @@ -383,7 +383,7 @@ where #[allow(unrooted_must_root)] pub unsafe fn from_box(value: Box<T>) -> Self { Self { - ptr: Box::into_raw_non_null(value), + ptr: Box::leak(value).into(), } } } diff --git a/components/script/dom/cssrulelist.rs b/components/script/dom/cssrulelist.rs index 18a41857923..812434fd180 100644 --- a/components/script/dom/cssrulelist.rs +++ b/components/script/dom/cssrulelist.rs @@ -17,7 +17,9 @@ use crate::stylesheet_loader::StylesheetLoader; use dom_struct::dom_struct; use servo_arc::Arc; use style::shared_lock::Locked; -use style::stylesheets::{CssRules, CssRulesHelpers, KeyframesRule, RulesMutateError}; +use style::stylesheets::{ + AllowImportRules, CssRules, CssRulesHelpers, KeyframesRule, RulesMutateError, +}; #[allow(unsafe_code)] unsafe_no_jsmanaged_fields!(RulesSource); @@ -116,6 +118,7 @@ impl CSSRuleList { index, nested, Some(&loader), + AllowImportRules::Yes, ) })?; diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 2fd6780cab0..baccc4e65aa 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -682,10 +682,7 @@ impl<'dom> LayoutElementHelpers<'dom> for LayoutDom<'dom, Element> { hints.push(from_declaration( shared_lock, PropertyDeclaration::BackgroundImage(background_image::SpecifiedValue( - vec![specified::ImageLayer::Image(specified::Image::for_cascade( - url.into(), - ))] - .into(), + vec![specified::Image::for_cascade(url.into())].into(), )), )); } @@ -3164,10 +3161,6 @@ impl<'a> SelectorsElement for DomRoot<Element> { false } - fn exported_part(&self, _: &Atom) -> Option<Atom> { - None - } - fn imported_part(&self, _: &Atom) -> Option<Atom> { None } diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index b4118e234c3..9e04585168c 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -41,7 +41,6 @@ use js::error::throw_type_error; use js::rust::HandleValue; use profile_traits::ipc; use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource}; -use servo_config::pref; use style::attr::{AttrValue, LengthOrPercentageOrAuto}; const DEFAULT_WIDTH: u32 = 300; @@ -222,7 +221,8 @@ impl HTMLCanvasElement { cx: JSContext, options: HandleValue, ) -> Option<DomRoot<WebGL2RenderingContext>> { - if !pref!(dom.webgl2.enabled) { + if !WebGL2RenderingContext::is_webgl2_enabled(cx, self.global().reflector().get_jsobject()) + { return None; } if let Some(ctx) = self.context() { diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index afa99d8d86b..6d10b0838f7 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -26,7 +26,7 @@ use servo_arc::Arc; use std::cell::Cell; use style::media_queries::MediaList; use style::parser::ParserContext as CssParserContext; -use style::stylesheets::{CssRuleType, Origin, Stylesheet}; +use style::stylesheets::{AllowImportRules, CssRuleType, Origin, Stylesheet}; use style_traits::ParsingMode; #[dom_struct] @@ -119,6 +119,7 @@ impl HTMLStyleElement { css_error_reporter, doc.quirks_mode(), self.line_number as u32, + AllowImportRules::Yes, ); let sheet = Arc::new(sheet); diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs index 62af18d1002..8e967fbcb86 100644 --- a/components/script/dom/webgl2renderingcontext.rs +++ b/components/script/dom/webgl2renderingcontext.rs @@ -16,6 +16,7 @@ use crate::dom::bindings::reflector::DomObject; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom}; use crate::dom::bindings::str::DOMString; +use crate::dom::globalscope::GlobalScope; use crate::dom::htmlcanvaselement::HTMLCanvasElement; use crate::dom::htmliframeelement::HTMLIFrameElement; use crate::dom::webglactiveinfo::WebGLActiveInfo; @@ -50,12 +51,14 @@ use ipc_channel::ipc; use js::jsapi::{JSObject, Type}; use js::jsval::{BooleanValue, DoubleValue, Int32Value, UInt32Value}; use js::jsval::{JSVal, NullValue, ObjectValue, UndefinedValue}; -use js::rust::CustomAutoRooterGuard; +use js::rust::{CustomAutoRooterGuard, HandleObject}; use js::typedarray::{ArrayBufferView, CreateWith, Float32, Int32Array, Uint32, Uint32Array}; use script_layout_interface::HTMLCanvasDataSource; +use servo_config::pref; use std::cell::Cell; use std::cmp; use std::ptr::{self, NonNull}; +use url::Host; #[unrooted_must_root_lint::must_root] #[derive(JSTraceable, MallocSizeOf)] @@ -178,8 +181,26 @@ impl WebGL2RenderingContext { WebGL2RenderingContext::new_inherited(window, canvas, size, attrs) .map(|ctx| reflect_dom_object(Box::new(ctx), window)) } + + #[allow(unsafe_code)] + pub fn is_webgl2_enabled(_cx: JSContext, global: HandleObject) -> bool { + if pref!(dom.webgl2.enabled) { + return true; + } + + let global = unsafe { GlobalScope::from_object(global.get()) }; + let origin = global.origin(); + let host = origin.host(); + WEBGL2_ORIGINS + .iter() + .any(|origin| host == Host::parse(origin).ok().as_ref()) + } } +/// List of domains for which WebGL 2 is enabled automatically, regardless +/// of the status of the dom.webgl2.enabled preference. +static WEBGL2_ORIGINS: &[&str] = &["www.servoexperiments.com"]; + impl WebGL2RenderingContext { pub fn recreate(&self, size: Size2D<u32>) { self.base.recreate(size) diff --git a/components/script/dom/webidls/WebGL2RenderingContext.webidl b/components/script/dom/webidls/WebGL2RenderingContext.webidl index e7f94cb9a3c..f6278370cce 100644 --- a/components/script/dom/webidls/WebGL2RenderingContext.webidl +++ b/components/script/dom/webidls/WebGL2RenderingContext.webidl @@ -542,7 +542,7 @@ interface mixin WebGL2RenderingContextBase void bindVertexArray(WebGLVertexArrayObject? array); }; -[Exposed=Window, Pref="dom.webgl2.enabled"] +[Exposed=Window, Func="WebGL2RenderingContext::is_webgl2_enabled"] interface WebGL2RenderingContext { }; diff --git a/components/script/dom/xrview.rs b/components/script/dom/xrview.rs index 14309dfc99c..8aa0b0adc58 100644 --- a/components/script/dom/xrview.rs +++ b/components/script/dom/xrview.rs @@ -3,6 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::dom::bindings::codegen::Bindings::XRViewBinding::{XREye, XRViewMethods}; +use crate::dom::bindings::reflector::DomObject; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::utils::create_typed_array; @@ -24,17 +25,24 @@ pub struct XRView { proj: Heap<*mut JSObject>, #[ignore_malloc_size_of = "mozjs"] view: Heap<*mut JSObject>, + proj_array: Vec<f32>, transform: Dom<XRRigidTransform>, } impl XRView { - fn new_inherited(session: &XRSession, transform: &XRRigidTransform, eye: XREye) -> XRView { + fn new_inherited( + session: &XRSession, + transform: &XRRigidTransform, + eye: XREye, + proj_array: Vec<f32>, + ) -> XRView { XRView { reflector_: Reflector::new(), session: Dom::from_ref(session), eye, proj: Heap::default(), view: Heap::default(), + proj_array, transform: Dom::from_ref(transform), } } @@ -55,13 +63,18 @@ impl XRView { let transform = pose.pre_transform(&offset); let transform = XRRigidTransform::new(global, cast_transform(transform)); + // row_major since euclid uses row vectors + let proj = view.projection.to_row_major_array(); let ret = reflect_dom_object( - Box::new(XRView::new_inherited(session, &transform, eye)), + Box::new(XRView::new_inherited( + session, + &transform, + eye, + (&proj).to_vec(), + )), global, ); - // row_major since euclid uses row vectors - let proj = view.projection.to_row_major_array(); let cx = global.get_cx(); create_typed_array(cx, &proj, &ret.proj); ret @@ -80,6 +93,10 @@ impl XRViewMethods for XRView { /// https://immersive-web.github.io/webxr/#dom-xrview-projectionmatrix fn ProjectionMatrix(&self, _cx: JSContext) -> NonNull<JSObject> { + if self.proj.get().is_null() { + let cx = self.global().get_cx(); + create_typed_array(cx, &self.proj_array, &self.proj); + } NonNull::new(self.proj.get()).unwrap() } diff --git a/components/script/lib.rs b/components/script/lib.rs index 07090f4716b..4eeca229e01 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -2,12 +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/. */ -#![feature(box_into_raw_non_null)] #![feature(const_fn)] -#![feature(const_transmute)] #![feature(core_intrinsics)] #![feature(drain_filter)] -#![feature(inner_deref)] #![feature(plugin)] #![feature(register_tool)] #![deny(unsafe_code)] diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index 651c0815f9f..374c650986d 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -7,7 +7,6 @@ //! to depend on script. #![deny(unsafe_code)] -#![feature(box_into_raw_non_null)] #[macro_use] extern crate html5ever; diff --git a/components/selectors/matching.rs b/components/selectors/matching.rs index 8993a5ea003..e8fd8afebca 100644 --- a/components/selectors/matching.rs +++ b/components/selectors/matching.rs @@ -676,19 +676,22 @@ where None => return false, }; - loop { - let outer_host = host.containing_shadow_host(); - if outer_host.as_ref().map(|h| h.opaque()) == context.shared.current_host { - break; + let current_host = context.shared.current_host; + if current_host != Some(host.opaque()) { + loop { + let outer_host = host.containing_shadow_host(); + if outer_host.as_ref().map(|h| h.opaque()) == current_host { + break; + } + let outer_host = match outer_host { + Some(h) => h, + None => return false, + }; + // TODO(emilio): if worth it, we could early return if + // host doesn't have the exportparts attribute. + hosts.push(host); + host = outer_host; } - let outer_host = match outer_host { - Some(h) => h, - None => return false, - }; - // TODO(emilio): if worth it, we could early return if - // host doesn't have the exportparts attribute. - hosts.push(host); - host = outer_host; } // Translate the part into the right scope. diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index 92a5b039b90..0f7cb9c6055 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -2013,27 +2013,48 @@ where input.skip_whitespace(); let mut empty = true; - if !parse_type_selector(parser, input, builder)? { - if let Some(url) = parser.default_namespace() { - // If there was no explicit type selector, but there is a - // default namespace, there is an implicit "<defaultns>|*" type - // selector. - builder.push_simple_selector(Component::DefaultNamespace(url)) - } - } else { + if parse_type_selector(parser, input, builder)? { empty = false; } let mut state = SelectorParsingState::empty(); loop { - let parse_result = match parse_one_simple_selector(parser, input, state)? { + let result = match parse_one_simple_selector(parser, input, state)? { None => break, Some(result) => result, }; + if empty { + if let Some(url) = parser.default_namespace() { + // If there was no explicit type selector, but there is a + // default namespace, there is an implicit "<defaultns>|*" type + // selector. Except for :host, where we ignore it. + // + // https://drafts.csswg.org/css-scoping/#host-element-in-tree: + // + // When considered within its own shadow trees, the shadow + // host is featureless. Only the :host, :host(), and + // :host-context() pseudo-classes are allowed to match it. + // + // https://drafts.csswg.org/selectors-4/#featureless: + // + // A featureless element does not match any selector at all, + // except those it is explicitly defined to match. If a + // given selector is allowed to match a featureless element, + // it must do so while ignoring the default namespace. + // + if !matches!( + result, + SimpleSelectorParseResult::SimpleSelector(Component::Host(..)) + ) { + builder.push_simple_selector(Component::DefaultNamespace(url)); + } + } + } + empty = false; - match parse_result { + match result { SimpleSelectorParseResult::SimpleSelector(s) => { builder.push_simple_selector(s); }, diff --git a/components/selectors/tree.rs b/components/selectors/tree.rs index d6198c5a5f5..ac90fa1f00c 100644 --- a/components/selectors/tree.rs +++ b/components/selectors/tree.rs @@ -117,13 +117,6 @@ pub trait Element: Sized + Clone + Debug { case_sensitivity: CaseSensitivity, ) -> bool; - /// Returns the mapping from the `exportparts` attribute in the regular - /// direction, that is, inner-tree -> outer-tree. - fn exported_part( - &self, - name: &<Self::Impl as SelectorImpl>::PartName, - ) -> Option<<Self::Impl as SelectorImpl>::PartName>; - /// Returns the mapping from the `exportparts` attribute in the reverse /// direction, that is, in an outer-tree -> inner-tree direction. fn imported_part( diff --git a/components/style/animation.rs b/components/style/animation.rs index d734acd6d7b..402c281a388 100644 --- a/components/style/animation.rs +++ b/components/style/animation.rs @@ -12,14 +12,13 @@ use crate::bezier::Bezier; use crate::context::SharedStyleContext; use crate::dom::{OpaqueNode, TElement}; use crate::font_metrics::FontMetricsProvider; -use crate::properties::animated_properties::AnimatedProperty; +use crate::properties::animated_properties::{AnimatedProperty, TransitionPropertyIteration}; use crate::properties::longhands::animation_direction::computed_value::single_value::T as AnimationDirection; use crate::properties::longhands::animation_play_state::computed_value::single_value::T as AnimationPlayState; use crate::properties::{self, CascadeMode, ComputedValues, LonghandId}; use crate::stylesheets::keyframes_rule::{KeyframesAnimation, KeyframesStep, KeyframesStepValue}; use crate::stylesheets::Origin; use crate::timer::Timer; -use crate::values::computed::box_::TransitionProperty; use crate::values::computed::Time; use crate::values::computed::TimingFunction; use crate::values::generics::box_::AnimationIterationCount; @@ -271,52 +270,6 @@ impl PropertyAnimation { self.property.name() } - /// Creates a new property animation for the given transition index and old - /// and new styles. Any number of animations may be returned, from zero (if - /// the property did not animate) to one (for a single transition property) - /// to arbitrarily many (for `all`). - pub fn from_transition( - transition_index: usize, - old_style: &ComputedValues, - new_style: &mut ComputedValues, - ) -> Vec<PropertyAnimation> { - let mut result = vec![]; - let box_style = new_style.get_box(); - let transition_property = box_style.transition_property_at(transition_index); - let timing_function = box_style.transition_timing_function_mod(transition_index); - let duration = box_style.transition_duration_mod(transition_index); - - match transition_property { - TransitionProperty::Custom(..) | TransitionProperty::Unsupported(..) => result, - TransitionProperty::Shorthand(ref shorthand_id) => shorthand_id - .longhands() - .filter_map(|longhand| { - PropertyAnimation::from_longhand( - longhand, - timing_function, - duration, - old_style, - new_style, - ) - }) - .collect(), - TransitionProperty::Longhand(longhand_id) => { - let animation = PropertyAnimation::from_longhand( - longhand_id, - timing_function, - duration, - old_style, - new_style, - ); - - if let Some(animation) = animation { - result.push(animation); - } - result - }, - } - } - fn from_longhand( longhand: LonghandId, timing_function: TimingFunction, @@ -414,56 +367,70 @@ pub fn start_transitions_if_applicable( running_and_expired_transitions: &[PropertyAnimation], ) -> bool { let mut had_animations = false; - for i in 0..new_style.get_box().transition_property_count() { - // Create any property animations, if applicable. - let property_animations = - PropertyAnimation::from_transition(i, old_style, Arc::make_mut(new_style)); - for property_animation in property_animations { - // Set the property to the initial value. - // - // NB: get_mut is guaranteed to succeed since we called make_mut() - // above. - property_animation.update(Arc::get_mut(new_style).unwrap(), 0.0); + let transitions: Vec<TransitionPropertyIteration> = new_style.transition_properties().collect(); + for transition in &transitions { + let property_animation = match PropertyAnimation::from_longhand( + transition.longhand_id, + new_style + .get_box() + .transition_timing_function_mod(transition.index), + new_style + .get_box() + .transition_duration_mod(transition.index), + old_style, + Arc::make_mut(new_style), + ) { + Some(property_animation) => property_animation, + None => continue, + }; - // Per [1], don't trigger a new transition if the end state for that - // transition is the same as that of a transition that's already - // running on the same node. - // - // [1]: https://drafts.csswg.org/css-transitions/#starting + // Set the property to the initial value. + // + // NB: get_mut is guaranteed to succeed since we called make_mut() + // above. + property_animation.update(Arc::get_mut(new_style).unwrap(), 0.0); + + // Per [1], don't trigger a new transition if the end state for that + // transition is the same as that of a transition that's already + // running on the same node. + // + // [1]: https://drafts.csswg.org/css-transitions/#starting + debug!( + "checking {:?} for matching end value", + running_and_expired_transitions + ); + if running_and_expired_transitions + .iter() + .any(|animation| animation.has_the_same_end_value_as(&property_animation)) + { debug!( - "checking {:?} for matching end value", - running_and_expired_transitions + "Not initiating transition for {}, other transition \ + found with the same end value", + property_animation.property_name() ); - if running_and_expired_transitions - .iter() - .any(|animation| animation.has_the_same_end_value_as(&property_animation)) - { - debug!( - "Not initiating transition for {}, other transition \ - found with the same end value", - property_animation.property_name() - ); - continue; - } + continue; + } - // Kick off the animation. - debug!("Kicking off transition of {:?}", property_animation); - let box_style = new_style.get_box(); - let now = timer.seconds(); - let start_time = now + (box_style.transition_delay_mod(i).seconds() as f64); - new_animations_sender - .send(Animation::Transition( - opaque_node, - start_time, - AnimationFrame { - duration: box_style.transition_duration_mod(i).seconds() as f64, - property_animation, - }, - )) - .unwrap(); + // Kick off the animation. + debug!("Kicking off transition of {:?}", property_animation); + let box_style = new_style.get_box(); + let now = timer.seconds(); + let start_time = now + (box_style.transition_delay_mod(transition.index).seconds() as f64); + let duration = box_style + .transition_duration_mod(transition.index) + .seconds() as f64; + new_animations_sender + .send(Animation::Transition( + opaque_node, + start_time, + AnimationFrame { + duration, + property_animation, + }, + )) + .unwrap(); - had_animations = true; - } + had_animations = true; } had_animations diff --git a/components/style/build.rs b/components/style/build.rs index 4477e648ac9..1d5211d690b 100644 --- a/components/style/build.rs +++ b/components/style/build.rs @@ -28,11 +28,11 @@ mod build_gecko { } lazy_static! { - pub static ref PYTHON: String = env::var("PYTHON").ok().unwrap_or_else(|| { + pub static ref PYTHON: String = env::var("PYTHON3").ok().unwrap_or_else(|| { let candidates = if cfg!(windows) { - ["python2.7.exe", "python27.exe", "python.exe"] + ["python3.exe"] } else { - ["python2.7", "python2", "python"] + ["python3"] }; for &name in &candidates { if Command::new(name) @@ -45,7 +45,7 @@ lazy_static! { } } panic!( - "Can't find python (tried {})! Try fixing PATH or setting the PYTHON env var", + "Can't find python (tried {})! Try fixing PATH or setting the PYTHON3 env var", candidates.join(", ") ) }); diff --git a/components/style/counter_style/mod.rs b/components/style/counter_style/mod.rs index d131f350393..9c4be49bb91 100644 --- a/components/style/counter_style/mod.rs +++ b/components/style/counter_style/mod.rs @@ -408,7 +408,9 @@ impl ToCss for System { } /// <https://drafts.csswg.org/css-counter-styles/#typedef-symbol> -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)] +#[derive( + Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToCss, ToShmem, +)] #[repr(u8)] pub enum Symbol { /// <string> @@ -554,7 +556,9 @@ impl Parse for Fallback { } /// <https://drafts.csswg.org/css-counter-styles/#descdef-counter-style-symbols> -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)] +#[derive( + Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToCss, ToShmem, +)] #[repr(C)] pub struct Symbols(#[css(iterable)] pub crate::OwnedSlice<Symbol>); diff --git a/components/style/custom_properties.rs b/components/style/custom_properties.rs index 76a72276a44..d0af57886db 100644 --- a/components/style/custom_properties.rs +++ b/components/style/custom_properties.rs @@ -579,7 +579,8 @@ impl<'a> CustomPropertiesBuilder<'a> { match result { Ok(new_value) => Arc::new(new_value), Err(..) => { - map.remove(name); + // Don't touch the map, this has the same effect as + // making it compute to the inherited one. return; }, } @@ -653,16 +654,22 @@ impl<'a> CustomPropertiesBuilder<'a> { None => return self.inherited.cloned(), }; if self.may_have_cycles { - substitute_all(&mut map, self.device); + let inherited = self.inherited.as_ref().map(|m| &***m); + substitute_all(&mut map, inherited, self.device); } Some(Arc::new(map)) } } -/// Resolve all custom properties to either substituted or invalid. +/// Resolve all custom properties to either substituted, invalid, or unset +/// (meaning we should use the inherited value). /// /// It does cycle dependencies removal at the same time as substitution. -fn substitute_all(custom_properties_map: &mut CustomPropertiesMap, device: &Device) { +fn substitute_all( + custom_properties_map: &mut CustomPropertiesMap, + inherited: Option<&CustomPropertiesMap>, + device: &Device, +) { // The cycle dependencies removal in this function is a variant // of Tarjan's algorithm. It is mostly based on the pseudo-code // listed in @@ -698,6 +705,9 @@ fn substitute_all(custom_properties_map: &mut CustomPropertiesMap, device: &Devi /// all unfinished strong connected components. stack: SmallVec<[usize; 5]>, map: &'a mut CustomPropertiesMap, + /// The inherited variables. We may need to restore some if we fail + /// substitution. + inherited: Option<&'a CustomPropertiesMap>, /// to resolve the environment to substitute `env()` variables. device: &'a Device, } @@ -831,17 +841,25 @@ fn substitute_all(custom_properties_map: &mut CustomPropertiesMap, device: &Devi return None; } - // Now we have shown that this variable is not in a loop, and - // all of its dependencies should have been resolved. We can - // start substitution now. + // Now we have shown that this variable is not in a loop, and all of its + // dependencies should have been resolved. We can start substitution + // now. let result = substitute_references_in_value(&value, &context.map, &context.device); - match result { Ok(computed_value) => { context.map.insert(name, Arc::new(computed_value)); }, Err(..) => { - context.map.remove(&name); + // This is invalid, reset it to the unset (inherited) value. + let inherited = context.inherited.and_then(|m| m.get(&name)).cloned(); + match inherited { + Some(computed_value) => { + context.map.insert(name, computed_value); + }, + None => { + context.map.remove(&name); + }, + }; }, } @@ -859,6 +877,7 @@ fn substitute_all(custom_properties_map: &mut CustomPropertiesMap, device: &Devi stack: SmallVec::new(), var_info: SmallVec::new(), map: custom_properties_map, + inherited, device, }; traverse(name, &mut context); diff --git a/components/style/dom.rs b/components/style/dom.rs index d07cac998ae..c1c1f74ef68 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -522,6 +522,14 @@ pub trait TElement: { } + /// Internal iterator for the part names that this element exports for a + /// given part name. + fn each_exported_part<F>(&self, _name: &Atom, _callback: F) + where + F: FnMut(&Atom), + { + } + /// Whether a given element may generate a pseudo-element. /// /// This is useful to avoid computing, for example, pseudo styles for diff --git a/components/style/driver.rs b/components/style/driver.rs index e8dfe7cf3db..aa39f3482f4 100644 --- a/components/style/driver.rs +++ b/components/style/driver.rs @@ -89,7 +89,7 @@ pub fn traverse_dom<E, D>( // ThreadLocalStyleContext on the main thread. If the main thread // ThreadLocalStyleContext has not released its TLS borrow by that point, // we'll panic on double-borrow. - let mut maybe_tls: Option<ScopedTLS<ThreadLocalStyleContext<E>>> = None; + let mut tls_slots = None; let mut tlc = ThreadLocalStyleContext::new(traversal.shared_context()); let mut context = StyleContext { shared: traversal.shared_context(), @@ -129,7 +129,7 @@ pub fn traverse_dom<E, D>( // depth for all the children. if pool.is_some() && discovered.len() > WORK_UNIT_MAX { let pool = pool.unwrap(); - maybe_tls = Some(ScopedTLS::<ThreadLocalStyleContext<E>>::new(pool)); + let tls = ScopedTLS::<ThreadLocalStyleContext<E>>::new(pool); let root_opaque = root.as_node().opaque(); let drain = discovered.drain(..); pool.install(|| { @@ -151,10 +151,12 @@ pub fn traverse_dom<E, D>( scope, pool, traversal, - maybe_tls.as_ref().unwrap(), + &tls, ); }); }); + + tls_slots = Some(tls.into_slots()); break; } nodes_remaining_at_current_depth = discovered.len(); @@ -164,9 +166,9 @@ pub fn traverse_dom<E, D>( // Collect statistics from thread-locals if requested. if dump_stats || report_stats { let mut aggregate = mem::replace(&mut context.thread_local.statistics, Default::default()); - let parallel = maybe_tls.is_some(); - if let Some(tls) = maybe_tls { - for mut slot in tls.into_slots().into_vec() { + let parallel = tls_slots.is_some(); + if let Some(ref mut tls) = tls_slots { + for slot in tls.iter_mut() { if let Some(cx) = slot.get_mut() { aggregate += cx.statistics.clone(); } diff --git a/components/style/element_state.rs b/components/style/element_state.rs index 8165c73ef14..cf943cc3c4e 100644 --- a/components/style/element_state.rs +++ b/components/style/element_state.rs @@ -137,6 +137,10 @@ bitflags! { const IN_AUTOFILL_STATE = 1 << 50; /// Non-standard & undocumented. const IN_AUTOFILL_PREVIEW_STATE = 1 << 51; + /// :focus-visible + /// + /// https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo + const IN_FOCUS_VISIBLE_STATE = 1 << 52; } } diff --git a/components/style/encoding_support.rs b/components/style/encoding_support.rs index 5544487179f..1ba92953bb9 100644 --- a/components/style/encoding_support.rs +++ b/components/style/encoding_support.rs @@ -10,7 +10,7 @@ use crate::context::QuirksMode; use crate::error_reporting::ParseErrorReporter; use crate::media_queries::MediaList; use crate::shared_lock::SharedRwLock; -use crate::stylesheets::{Origin, Stylesheet, StylesheetLoader, UrlExtraData}; +use crate::stylesheets::{AllowImportRules, Origin, Stylesheet, StylesheetLoader, UrlExtraData}; use cssparser::{stylesheet_encoding, EncodingSupport}; use servo_arc::Arc; use std::borrow::Cow; @@ -78,6 +78,7 @@ impl Stylesheet { error_reporter, quirks_mode, 0, + AllowImportRules::Yes, ) } @@ -100,6 +101,7 @@ impl Stylesheet { stylesheet_loader, error_reporter, 0, + AllowImportRules::Yes, ) } } diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index 3deaeacadc8..ea3700a3235 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -10,244 +10,9 @@ #![allow(unsafe_code)] -use crate::gecko_bindings::bindings; -use crate::gecko_bindings::structs::{self, Matrix4x4Components}; -use crate::gecko_bindings::structs::{nsStyleImage, nsresult}; +use crate::gecko_bindings::structs::{nsresult, Matrix4x4Components}; use crate::stylesheets::RulesMutateError; use crate::values::computed::transform::Matrix3D; -use crate::values::computed::{Gradient, Image, TextAlign}; -use crate::values::generics::image::GenericImage; -use crate::values::generics::rect::Rect; - -impl nsStyleImage { - /// Set a given Servo `Image` value into this `nsStyleImage`. - pub fn set(&mut self, image: Image) { - match image { - GenericImage::Gradient(boxed_gradient) => self.set_gradient(boxed_gradient), - GenericImage::Url(ref url) => unsafe { - bindings::Gecko_SetLayerImageImageValue(self, url); - }, - GenericImage::Rect(ref image_rect) => { - unsafe { - bindings::Gecko_SetLayerImageImageValue(self, &image_rect.url); - bindings::Gecko_InitializeImageCropRect(self); - - // Set CropRect - let ref mut rect = *self.mCropRect.mPtr; - *rect = Rect( - image_rect.top, - image_rect.right, - image_rect.bottom, - image_rect.left, - ); - } - }, - GenericImage::Element(ref element) => unsafe { - bindings::Gecko_SetImageElement(self, element.as_ptr()); - }, - } - } - - fn set_gradient(&mut self, gradient: Box<Gradient>) { - unsafe { - bindings::Gecko_SetGradientImageValue(self, Box::into_raw(gradient)); - } - } - - /// Converts into Image. - pub unsafe fn into_image(self: &nsStyleImage) -> Option<Image> { - use crate::gecko_bindings::structs::nsStyleImageType; - use crate::values::computed::MozImageRect; - - match self.mType { - nsStyleImageType::eStyleImageType_Null => None, - nsStyleImageType::eStyleImageType_Image => { - let url = self.__bindgen_anon_1.mImage.as_ref().clone(); - if self.mCropRect.mPtr.is_null() { - Some(GenericImage::Url(url)) - } else { - let rect = &*self.mCropRect.mPtr; - Some(GenericImage::Rect(Box::new(MozImageRect { - url, - top: rect.0, - right: rect.1, - bottom: rect.2, - left: rect.3, - }))) - } - }, - nsStyleImageType::eStyleImageType_Gradient => { - let gradient: &Gradient = &**self.__bindgen_anon_1.mGradient.as_ref(); - Some(GenericImage::Gradient(Box::new(gradient.clone()))) - }, - nsStyleImageType::eStyleImageType_Element => { - use crate::gecko_string_cache::Atom; - let atom = bindings::Gecko_GetImageElement(self); - Some(GenericImage::Element(Atom::from_raw(atom))) - }, - } - } -} - -pub mod basic_shape { - //! Conversions from and to CSS shape representations. - use crate::gecko_bindings::structs::{ - StyleGeometryBox, StyleShapeSource, StyleShapeSourceType, - }; - use crate::values::computed::basic_shape::{BasicShape, ClippingShape, FloatAreaShape}; - use crate::values::computed::motion::OffsetPath; - use crate::values::generics::basic_shape::{GeometryBox, Path, ShapeBox, ShapeSource}; - use crate::values::specified::SVGPathData; - - impl StyleShapeSource { - /// Convert StyleShapeSource to ShapeSource except URL and Image - /// types. - fn into_shape_source<ReferenceBox, ImageOrUrl>( - &self, - ) -> Option<ShapeSource<BasicShape, ReferenceBox, ImageOrUrl>> - where - ReferenceBox: From<StyleGeometryBox>, - { - match self.mType { - StyleShapeSourceType::None => Some(ShapeSource::None), - StyleShapeSourceType::Box => Some(ShapeSource::Box(self.mReferenceBox.into())), - StyleShapeSourceType::Shape => { - let other_shape = unsafe { &*self.__bindgen_anon_1.mBasicShape.as_ref().mPtr }; - let shape = Box::new(other_shape.clone()); - let reference_box = if self.mReferenceBox == StyleGeometryBox::NoBox { - None - } else { - Some(self.mReferenceBox.into()) - }; - Some(ShapeSource::Shape(shape, reference_box)) - }, - StyleShapeSourceType::Image => None, - StyleShapeSourceType::Path => { - let path = self.to_svg_path().expect("expect an SVGPathData"); - let fill = unsafe { &*self.__bindgen_anon_1.mSVGPath.as_ref().mPtr }.mFillRule; - Some(ShapeSource::Path(Path { fill, path })) - }, - } - } - - /// Generate a SVGPathData from StyleShapeSource if possible. - fn to_svg_path(&self) -> Option<SVGPathData> { - match self.mType { - StyleShapeSourceType::Path => { - let gecko_path = unsafe { &*self.__bindgen_anon_1.mSVGPath.as_ref().mPtr }; - Some(SVGPathData(gecko_path.mPath.clone())) - }, - _ => None, - } - } - } - - impl<'a> From<&'a StyleShapeSource> for ClippingShape { - fn from(other: &'a StyleShapeSource) -> Self { - match other.mType { - StyleShapeSourceType::Image => unsafe { - use crate::values::generics::image::Image as GenericImage; - - let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr; - let image = shape_image.into_image().expect("Cannot convert to Image"); - match image { - GenericImage::Url(url) => ShapeSource::ImageOrUrl(url.0), - _ => panic!("ClippingShape doesn't support non-url images"), - } - }, - _ => other - .into_shape_source() - .expect("Couldn't convert to StyleSource!"), - } - } - } - - impl<'a> From<&'a StyleShapeSource> for FloatAreaShape { - fn from(other: &'a StyleShapeSource) -> Self { - match other.mType { - StyleShapeSourceType::Image => unsafe { - let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr; - let image = shape_image.into_image().expect("Cannot convert to Image"); - ShapeSource::ImageOrUrl(image) - }, - _ => other - .into_shape_source() - .expect("Couldn't convert to StyleSource!"), - } - } - } - - impl<'a> From<&'a StyleShapeSource> for OffsetPath { - fn from(other: &'a StyleShapeSource) -> Self { - use crate::values::generics::motion::GenericOffsetPath; - match other.mType { - StyleShapeSourceType::Path => GenericOffsetPath::Path( - other.to_svg_path().expect("Cannot convert to SVGPathData"), - ), - StyleShapeSourceType::None => OffsetPath::none(), - StyleShapeSourceType::Shape | - StyleShapeSourceType::Box | - StyleShapeSourceType::Image => unreachable!("Unsupported offset-path type"), - } - } - } - - impl From<ShapeBox> for StyleGeometryBox { - fn from(reference: ShapeBox) -> Self { - use crate::gecko_bindings::structs::StyleGeometryBox::*; - match reference { - ShapeBox::ContentBox => ContentBox, - ShapeBox::PaddingBox => PaddingBox, - ShapeBox::BorderBox => BorderBox, - ShapeBox::MarginBox => MarginBox, - } - } - } - - impl From<GeometryBox> for StyleGeometryBox { - fn from(reference: GeometryBox) -> Self { - use crate::gecko_bindings::structs::StyleGeometryBox::*; - match reference { - GeometryBox::ShapeBox(shape_box) => From::from(shape_box), - GeometryBox::FillBox => FillBox, - GeometryBox::StrokeBox => StrokeBox, - GeometryBox::ViewBox => ViewBox, - } - } - } - - // Will panic on NoBox - // Ideally these would be implemented on Option<T>, - // but coherence doesn't like that and TryFrom isn't stable - impl From<StyleGeometryBox> for GeometryBox { - fn from(reference: StyleGeometryBox) -> Self { - use crate::gecko_bindings::structs::StyleGeometryBox::*; - match reference { - ContentBox => GeometryBox::ShapeBox(ShapeBox::ContentBox), - PaddingBox => GeometryBox::ShapeBox(ShapeBox::PaddingBox), - BorderBox => GeometryBox::ShapeBox(ShapeBox::BorderBox), - MarginBox => GeometryBox::ShapeBox(ShapeBox::MarginBox), - FillBox => GeometryBox::FillBox, - StrokeBox => GeometryBox::StrokeBox, - ViewBox => GeometryBox::ViewBox, - _ => panic!("Unexpected StyleGeometryBox while converting to GeometryBox"), - } - } - } - - impl From<StyleGeometryBox> for ShapeBox { - fn from(reference: StyleGeometryBox) -> Self { - use crate::gecko_bindings::structs::StyleGeometryBox::*; - match reference { - ContentBox => ShapeBox::ContentBox, - PaddingBox => ShapeBox::PaddingBox, - BorderBox => ShapeBox::BorderBox, - MarginBox => ShapeBox::MarginBox, - _ => panic!("Unexpected StyleGeometryBox while converting to ShapeBox"), - } - } - } -} impl From<RulesMutateError> for nsresult { fn from(other: RulesMutateError) -> Self { @@ -260,39 +25,6 @@ impl From<RulesMutateError> for nsresult { } } -impl TextAlign { - /// Obtain a specified value from a Gecko keyword value - /// - /// Intended for use with presentation attributes, not style structs - pub fn from_gecko_keyword(kw: u32) -> Self { - match kw { - structs::NS_STYLE_TEXT_ALIGN_LEFT => TextAlign::Left, - structs::NS_STYLE_TEXT_ALIGN_RIGHT => TextAlign::Right, - structs::NS_STYLE_TEXT_ALIGN_CENTER => TextAlign::Center, - structs::NS_STYLE_TEXT_ALIGN_JUSTIFY => TextAlign::Justify, - structs::NS_STYLE_TEXT_ALIGN_MOZ_LEFT => TextAlign::MozLeft, - structs::NS_STYLE_TEXT_ALIGN_MOZ_RIGHT => TextAlign::MozRight, - structs::NS_STYLE_TEXT_ALIGN_MOZ_CENTER => TextAlign::MozCenter, - structs::NS_STYLE_TEXT_ALIGN_CHAR => TextAlign::Char, - structs::NS_STYLE_TEXT_ALIGN_END => TextAlign::End, - _ => panic!("Found unexpected value in style struct for text-align property"), - } - } -} - -/// Convert to String from given chars pointer. -pub unsafe fn string_from_chars_pointer(p: *const u16) -> String { - use std::slice; - let mut length = 0; - let mut iter = p; - while *iter != 0 { - length += 1; - iter = iter.offset(1); - } - let char_vec = slice::from_raw_parts(p, length as usize); - String::from_utf16_lossy(char_vec) -} - impl<'a> From<&'a Matrix4x4Components> for Matrix3D { fn from(m: &'a Matrix4x4Components) -> Matrix3D { Matrix3D { diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 25ce9f5b3a1..27cb666fc6f 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -310,6 +310,17 @@ impl Device { /// Returns safe area insets pub fn safe_area_insets(&self) -> SideOffsets2D<f32, CSSPixel> { - SideOffsets2D::zero() + let pc = match self.pres_context() { + Some(pc) => pc, + None => return SideOffsets2D::zero(), + }; + let mut top = 0.0; + let mut right = 0.0; + let mut bottom = 0.0; + let mut left = 0.0; + unsafe { + bindings::Gecko_GetSafeAreaInsets(pc, &mut top, &mut right, &mut bottom, &mut left) + }; + SideOffsets2D::new(top, right, bottom, left) } } diff --git a/components/style/gecko/non_ts_pseudo_class_list.rs b/components/style/gecko/non_ts_pseudo_class_list.rs index 8d9fc3d2d85..ea5db98030a 100644 --- a/components/style/gecko/non_ts_pseudo_class_list.rs +++ b/components/style/gecko/non_ts_pseudo_class_list.rs @@ -30,77 +30,78 @@ macro_rules! apply_non_ts_list { ($apply_macro:ident) => { $apply_macro! { [ - ("-moz-table-border-nonzero", MozTableBorderNonzero, mozTableBorderNonzero, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-browser-frame", MozBrowserFrame, mozBrowserFrame, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("link", Link, link, IN_UNVISITED_STATE, _), - ("any-link", AnyLink, anyLink, IN_VISITED_OR_UNVISITED_STATE, _), - ("visited", Visited, visited, IN_VISITED_STATE, _), - ("active", Active, active, IN_ACTIVE_STATE, _), - ("checked", Checked, checked, IN_CHECKED_STATE, _), - ("defined", Defined, defined, IN_DEFINED_STATE, _), - ("disabled", Disabled, disabled, IN_DISABLED_STATE, _), - ("enabled", Enabled, enabled, IN_ENABLED_STATE, _), - ("focus", Focus, focus, IN_FOCUS_STATE, _), - ("focus-within", FocusWithin, focusWithin, IN_FOCUS_WITHIN_STATE, _), - ("hover", Hover, hover, IN_HOVER_STATE, _), - ("-moz-drag-over", MozDragOver, mozDragOver, IN_DRAGOVER_STATE, _), - ("target", Target, target, IN_TARGET_STATE, _), - ("indeterminate", Indeterminate, indeterminate, IN_INDETERMINATE_STATE, _), - ("-moz-devtools-highlighted", MozDevtoolsHighlighted, mozDevtoolsHighlighted, IN_DEVTOOLS_HIGHLIGHTED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-styleeditor-transitioning", MozStyleeditorTransitioning, mozStyleeditorTransitioning, IN_STYLEEDITOR_TRANSITIONING_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("fullscreen", Fullscreen, fullscreen, IN_FULLSCREEN_STATE, _), + ("-moz-table-border-nonzero", MozTableBorderNonzero, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-browser-frame", MozBrowserFrame, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("link", Link, IN_UNVISITED_STATE, _), + ("any-link", AnyLink, IN_VISITED_OR_UNVISITED_STATE, _), + ("visited", Visited, IN_VISITED_STATE, _), + ("active", Active, IN_ACTIVE_STATE, _), + ("checked", Checked, IN_CHECKED_STATE, _), + ("defined", Defined, IN_DEFINED_STATE, _), + ("disabled", Disabled, IN_DISABLED_STATE, _), + ("enabled", Enabled, IN_ENABLED_STATE, _), + ("focus", Focus, IN_FOCUS_STATE, _), + ("focus-within", FocusWithin, IN_FOCUS_WITHIN_STATE, _), + ("focus-visible", FocusVisible, IN_FOCUS_VISIBLE_STATE, _), + ("hover", Hover, IN_HOVER_STATE, _), + ("-moz-drag-over", MozDragOver, IN_DRAGOVER_STATE, _), + ("target", Target, IN_TARGET_STATE, _), + ("indeterminate", Indeterminate, IN_INDETERMINATE_STATE, _), + ("-moz-devtools-highlighted", MozDevtoolsHighlighted, IN_DEVTOOLS_HIGHLIGHTED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-styleeditor-transitioning", MozStyleeditorTransitioning, IN_STYLEEDITOR_TRANSITIONING_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("fullscreen", Fullscreen, IN_FULLSCREEN_STATE, _), // TODO(emilio): This is inconsistently named (the capital R). - ("-moz-focusring", MozFocusRing, mozFocusRing, IN_FOCUSRING_STATE, _), - ("-moz-broken", MozBroken, mozBroken, IN_BROKEN_STATE, _), - ("-moz-loading", MozLoading, mozLoading, IN_LOADING_STATE, _), - ("-moz-suppressed", MozSuppressed, mozSuppressed, IN_SUPPRESSED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-has-dir-attr", MozHasDirAttr, mozHasDirAttr, IN_HAS_DIR_ATTR_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-dir-attr-ltr", MozDirAttrLTR, mozDirAttrLTR, IN_HAS_DIR_ATTR_LTR_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-dir-attr-rtl", MozDirAttrRTL, mozDirAttrRTL, IN_HAS_DIR_ATTR_RTL_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-dir-attr-like-auto", MozDirAttrLikeAuto, mozDirAttrLikeAuto, IN_HAS_DIR_ATTR_LIKE_AUTO_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-autofill", MozAutofill, mozAutofill, IN_AUTOFILL_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-autofill-preview", MozAutofillPreview, mozAutofillPreview, IN_AUTOFILL_PREVIEW_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-focusring", MozFocusRing, IN_FOCUSRING_STATE, _), + ("-moz-broken", MozBroken, IN_BROKEN_STATE, _), + ("-moz-loading", MozLoading, IN_LOADING_STATE, _), + ("-moz-suppressed", MozSuppressed, IN_SUPPRESSED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-has-dir-attr", MozHasDirAttr, IN_HAS_DIR_ATTR_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-dir-attr-ltr", MozDirAttrLTR, IN_HAS_DIR_ATTR_LTR_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-dir-attr-rtl", MozDirAttrRTL, IN_HAS_DIR_ATTR_RTL_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-dir-attr-like-auto", MozDirAttrLikeAuto, IN_HAS_DIR_ATTR_LIKE_AUTO_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-autofill", MozAutofill, IN_AUTOFILL_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-autofill-preview", MozAutofillPreview, IN_AUTOFILL_PREVIEW_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-handler-clicktoplay", MozHandlerClickToPlay, mozHandlerClickToPlay, IN_HANDLER_CLICK_TO_PLAY_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-handler-vulnerable-updatable", MozHandlerVulnerableUpdatable, mozHandlerVulnerableUpdatable, IN_HANDLER_VULNERABLE_UPDATABLE_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-handler-vulnerable-no-update", MozHandlerVulnerableNoUpdate, mozHandlerVulnerableNoUpdate, IN_HANDLER_VULNERABLE_NO_UPDATE_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-handler-clicktoplay", MozHandlerClickToPlay, IN_HANDLER_CLICK_TO_PLAY_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-handler-vulnerable-updatable", MozHandlerVulnerableUpdatable, IN_HANDLER_VULNERABLE_UPDATABLE_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-handler-vulnerable-no-update", MozHandlerVulnerableNoUpdate, IN_HANDLER_VULNERABLE_NO_UPDATE_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-handler-disabled", MozHandlerDisabled, mozHandlerDisabled, IN_HANDLER_DISABLED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-handler-blocked", MozHandlerBlocked, mozHandlerBlocked, IN_HANDLER_BLOCKED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-handler-crashed", MozHandlerCrashed, mozHandlerCrashed, IN_HANDLER_CRASHED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-math-increment-script-level", MozMathIncrementScriptLevel, mozMathIncrementScriptLevel, IN_INCREMENT_SCRIPT_LEVEL_STATE, _), + ("-moz-handler-disabled", MozHandlerDisabled, IN_HANDLER_DISABLED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-handler-blocked", MozHandlerBlocked, IN_HANDLER_BLOCKED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-handler-crashed", MozHandlerCrashed, IN_HANDLER_CRASHED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-math-increment-script-level", MozMathIncrementScriptLevel, IN_INCREMENT_SCRIPT_LEVEL_STATE, _), - ("required", Required, required, IN_REQUIRED_STATE, _), - ("optional", Optional, optional, IN_OPTIONAL_STATE, _), - ("valid", Valid, valid, IN_VALID_STATE, _), - ("invalid", Invalid, invalid, IN_INVALID_STATE, _), - ("in-range", InRange, inRange, IN_INRANGE_STATE, _), - ("out-of-range", OutOfRange, outOfRange, IN_OUTOFRANGE_STATE, _), - ("default", Default, defaultPseudo, IN_DEFAULT_STATE, _), - ("placeholder-shown", PlaceholderShown, placeholderShown, IN_PLACEHOLDER_SHOWN_STATE, _), - ("-moz-read-only", MozReadOnly, mozReadOnly, IN_MOZ_READONLY_STATE, _), - ("-moz-read-write", MozReadWrite, mozReadWrite, IN_MOZ_READWRITE_STATE, _), - ("-moz-submit-invalid", MozSubmitInvalid, mozSubmitInvalid, IN_MOZ_SUBMITINVALID_STATE, _), - ("-moz-ui-valid", MozUIValid, mozUIValid, IN_MOZ_UI_VALID_STATE, _), - ("-moz-ui-invalid", MozUIInvalid, mozUIInvalid, IN_MOZ_UI_INVALID_STATE, _), - ("-moz-meter-optimum", MozMeterOptimum, mozMeterOptimum, IN_OPTIMUM_STATE, _), - ("-moz-meter-sub-optimum", MozMeterSubOptimum, mozMeterSubOptimum, IN_SUB_OPTIMUM_STATE, _), - ("-moz-meter-sub-sub-optimum", MozMeterSubSubOptimum, mozMeterSubSubOptimum, IN_SUB_SUB_OPTIMUM_STATE, _), + ("required", Required, IN_REQUIRED_STATE, _), + ("optional", Optional, IN_OPTIONAL_STATE, _), + ("valid", Valid, IN_VALID_STATE, _), + ("invalid", Invalid, IN_INVALID_STATE, _), + ("in-range", InRange, IN_INRANGE_STATE, _), + ("out-of-range", OutOfRange, IN_OUTOFRANGE_STATE, _), + ("default", Default, IN_DEFAULT_STATE, _), + ("placeholder-shown", PlaceholderShown, IN_PLACEHOLDER_SHOWN_STATE, _), + ("-moz-read-only", MozReadOnly, IN_MOZ_READONLY_STATE, _), + ("-moz-read-write", MozReadWrite, IN_MOZ_READWRITE_STATE, _), + ("-moz-submit-invalid", MozSubmitInvalid, IN_MOZ_SUBMITINVALID_STATE, _), + ("-moz-ui-valid", MozUIValid, IN_MOZ_UI_VALID_STATE, _), + ("-moz-ui-invalid", MozUIInvalid, IN_MOZ_UI_INVALID_STATE, _), + ("-moz-meter-optimum", MozMeterOptimum, IN_OPTIMUM_STATE, _), + ("-moz-meter-sub-optimum", MozMeterSubOptimum, IN_SUB_OPTIMUM_STATE, _), + ("-moz-meter-sub-sub-optimum", MozMeterSubSubOptimum, IN_SUB_SUB_OPTIMUM_STATE, _), - ("-moz-user-disabled", MozUserDisabled, mozUserDisabled, IN_USER_DISABLED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-user-disabled", MozUserDisabled, IN_USER_DISABLED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-first-node", MozFirstNode, firstNode, _, _), - ("-moz-last-node", MozLastNode, lastNode, _, _), - ("-moz-only-whitespace", MozOnlyWhitespace, mozOnlyWhitespace, _, _), - ("-moz-native-anonymous", MozNativeAnonymous, mozNativeAnonymous, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-native-anonymous-no-specificity", MozNativeAnonymousNoSpecificity, mozNativeAnonymousNoSpecificity, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-use-shadow-tree-root", MozUseShadowTreeRoot, mozUseShadowTreeRoot, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-is-html", MozIsHTML, mozIsHTML, _, _), - ("-moz-placeholder", MozPlaceholder, mozPlaceholder, _, _), - ("-moz-lwtheme", MozLWTheme, mozLWTheme, _, _), - ("-moz-lwtheme-brighttext", MozLWThemeBrightText, mozLWThemeBrightText, _, _), - ("-moz-lwtheme-darktext", MozLWThemeDarkText, mozLWThemeDarkText, _, _), - ("-moz-window-inactive", MozWindowInactive, mozWindowInactive, _, _), + ("-moz-first-node", MozFirstNode, _, _), + ("-moz-last-node", MozLastNode, _, _), + ("-moz-only-whitespace", MozOnlyWhitespace, _, _), + ("-moz-native-anonymous", MozNativeAnonymous, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-native-anonymous-no-specificity", MozNativeAnonymousNoSpecificity, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-use-shadow-tree-root", MozUseShadowTreeRoot, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-is-html", MozIsHTML, _, _), + ("-moz-placeholder", MozPlaceholder, _, _), + ("-moz-lwtheme", MozLWTheme, _, _), + ("-moz-lwtheme-brighttext", MozLWThemeBrightText, _, _), + ("-moz-lwtheme-darktext", MozLWThemeDarkText, _, _), + ("-moz-window-inactive", MozWindowInactive, _, _), ] } } diff --git a/components/style/gecko/pseudo_element.rs b/components/style/gecko/pseudo_element.rs index 8d05dd9bbb1..d989380c02e 100644 --- a/components/style/gecko/pseudo_element.rs +++ b/components/style/gecko/pseudo_element.rs @@ -134,12 +134,6 @@ impl PseudoElement { *self == PseudoElement::FirstLine } - /// Whether this pseudo-element is ::-moz-fieldset-content. - #[inline] - pub fn is_fieldset_content(&self) -> bool { - *self == PseudoElement::FieldsetContent - } - /// Whether this pseudo-element is the ::-moz-color-swatch pseudo. #[inline] pub fn is_color_swatch(&self) -> bool { diff --git a/components/style/gecko/regen_atoms.py b/components/style/gecko/regen_atoms.py index cf7cc77c16f..5c59a5c566c 100755 --- a/components/style/gecko/regen_atoms.py +++ b/components/style/gecko/regen_atoms.py @@ -94,7 +94,7 @@ class FileAvoidWrite(BytesIO): self.name = filename def write(self, buf): - if isinstance(buf, unicode): + if isinstance(buf, str): buf = buf.encode('utf-8') BytesIO.write(self, buf) diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs index 9f5b49c5c13..3c944bbc6eb 100644 --- a/components/style/gecko/selector_parser.rs +++ b/components/style/gecko/selector_parser.rs @@ -42,7 +42,7 @@ bitflags! { pub type Lang = Atom; macro_rules! pseudo_class_name { - ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { + ([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => { /// Our representation of a non tree-structural pseudo-class. #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)] pub enum NonTSPseudoClass { @@ -72,7 +72,7 @@ impl ToCss for NonTSPseudoClass { W: fmt::Write, { macro_rules! pseudo_class_serialize { - ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { + ([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => { match *self { $(NonTSPseudoClass::$name => concat!(":", $css),)* NonTSPseudoClass::Lang(ref s) => { @@ -134,7 +134,7 @@ impl NonTSPseudoClass { /// in a particular state. pub fn parse_non_functional(name: &str) -> Option<Self> { macro_rules! pseudo_class_parse { - ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { + ([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => { match_ignore_ascii_case! { &name, $($css => Some(NonTSPseudoClass::$name),)* "-moz-full-screen" => Some(NonTSPseudoClass::Fullscreen), @@ -156,7 +156,7 @@ impl NonTSPseudoClass { }; } macro_rules! pseudo_class_check_is_enabled_in { - ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { + ([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => { match *self { $(NonTSPseudoClass::$name => check_flag!($flags),)* NonTSPseudoClass::MozLocaleDir(_) | @@ -172,6 +172,9 @@ impl NonTSPseudoClass { /// Returns whether the pseudo-class is enabled in content sheets. #[inline] fn is_enabled_in_content(&self) -> bool { + if matches!(*self, NonTSPseudoClass::FocusVisible) { + return static_prefs::pref!("layout.css.focus-visible.enabled"); + } !self.has_any_flag(NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME) } @@ -186,7 +189,7 @@ impl NonTSPseudoClass { }; } macro_rules! pseudo_class_state { - ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { + ([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => { match *self { $(NonTSPseudoClass::$name => flag!($state),)* NonTSPseudoClass::Dir(..) | diff --git a/components/style/gecko/snapshot.rs b/components/style/gecko/snapshot.rs index fa9914f6222..b2a66f709e2 100644 --- a/components/style/gecko/snapshot.rs +++ b/components/style/gecko/snapshot.rs @@ -194,11 +194,6 @@ impl ElementSnapshot for GeckoElementSnapshot { } #[inline] - fn exported_part(&self, name: &Atom) -> Option<Atom> { - snapshot_helpers::exported_part(&*self.mAttrs, name) - } - - #[inline] fn imported_part(&self, name: &Atom) -> Option<Atom> { snapshot_helpers::imported_part(&*self.mAttrs, name) } diff --git a/components/style/gecko/snapshot_helpers.rs b/components/style/gecko/snapshot_helpers.rs index cb3056e7bd5..bd905870353 100644 --- a/components/style/gecko/snapshot_helpers.rs +++ b/components/style/gecko/snapshot_helpers.rs @@ -83,16 +83,26 @@ pub fn get_id(attrs: &[structs::AttrArray_InternalAttr]) -> Option<&WeakAtom> { } #[inline(always)] -pub(super) fn exported_part( +pub(super) fn each_exported_part( attrs: &[structs::AttrArray_InternalAttr], name: &Atom, -) -> Option<Atom> { - let attr = find_attr(attrs, &atom!("exportparts"))?; - let atom = unsafe { bindings::Gecko_Element_ExportedPart(attr, name.as_ptr()) }; - if atom.is_null() { - return None; + mut callback: impl FnMut(&Atom), +) { + let attr = match find_attr(attrs, &atom!("exportparts")) { + Some(attr) => attr, + None => return, + }; + let mut length = 0; + let atoms = unsafe { bindings::Gecko_Element_ExportedParts(attr, name.as_ptr(), &mut length) }; + if atoms.is_null() { + return; + } + + unsafe { + for atom in std::slice::from_raw_parts(atoms, length) { + Atom::with(*atom, &mut callback) + } } - Some(unsafe { Atom::from_raw(atom) }) } #[inline(always)] diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 2b842e72d9b..a5472fadd66 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -72,7 +72,7 @@ use crate::values::computed::Length; use crate::values::specified::length::FontBaseSize; use crate::CaseSensitivityExt; use app_units::Au; -use atomic_refcell::{AtomicRefCell, AtomicRefMut}; +use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator}; use selectors::attr::{CaseSensitivity, NamespaceConstraint}; use selectors::matching::VisitedHandlingMode; @@ -557,8 +557,9 @@ impl<'le> fmt::Debug for GeckoElement<'le> { } impl<'le> GeckoElement<'le> { + /// Gets the raw `ElementData` refcell for the element. #[inline(always)] - fn get_data(&self) -> Option<&AtomicRefCell<ElementData>> { + pub fn get_data(&self) -> Option<&AtomicRefCell<ElementData>> { unsafe { self.0.mServoData.get().as_ref() } } @@ -1281,6 +1282,14 @@ impl<'le> TElement for GeckoElement<'le> { snapshot_helpers::each_class_or_part(attr, callback) } + #[inline] + fn each_exported_part<F>(&self, name: &Atom, callback: F) + where + F: FnMut(&Atom), + { + snapshot_helpers::each_exported_part(self.attrs(), name, callback) + } + fn each_part<F>(&self, callback: F) where F: FnMut(&Atom), @@ -1383,21 +1392,6 @@ impl<'le> TElement for GeckoElement<'le> { panic!("Atomic child count not implemented in Gecko"); } - /// Whether there is an ElementData container. - fn has_data(&self) -> bool { - self.get_data().is_some() - } - - /// Immutably borrows the ElementData. - fn borrow_data(&self) -> Option<AtomicRef<ElementData>> { - self.get_data().map(|x| x.borrow()) - } - - /// Mutably borrows the ElementData. - fn mutate_data(&self) -> Option<AtomicRefMut<ElementData>> { - self.get_data().map(|x| x.borrow_mut()) - } - unsafe fn ensure_data(&self) -> AtomicRefMut<ElementData> { if !self.has_data() { debug!("Creating ElementData for {:?}", self); @@ -1566,9 +1560,7 @@ impl<'le> TElement for GeckoElement<'le> { before_change_style: &ComputedValues, after_change_style: &ComputedValues, ) -> bool { - use crate::gecko_bindings::structs::nsCSSPropertyID; use crate::properties::LonghandIdSet; - use crate::values::computed::TransitionProperty; debug_assert!( self.might_need_transitions_update(Some(before_change_style), after_change_style), @@ -1577,53 +1569,21 @@ impl<'le> TElement for GeckoElement<'le> { ); let after_change_box_style = after_change_style.get_box(); - let transitions_count = after_change_box_style.transition_property_count(); let existing_transitions = self.css_transitions_info(); - - // Check if this property is none, custom or unknown. - let is_none_or_custom_property = |property: nsCSSPropertyID| -> bool { - return property == nsCSSPropertyID::eCSSPropertyExtra_no_properties || - property == nsCSSPropertyID::eCSSPropertyExtra_variable || - property == nsCSSPropertyID::eCSSProperty_UNKNOWN; - }; - let mut transitions_to_keep = LonghandIdSet::new(); - - for i in 0..transitions_count { - let property = after_change_box_style.transition_nscsspropertyid_at(i); - let combined_duration = after_change_box_style.transition_combined_duration_at(i); - - // We don't need to update transition for none/custom properties. - if is_none_or_custom_property(property) { - continue; - } - - let transition_property: TransitionProperty = property.into(); - - let mut property_check_helper = |property: LonghandId| -> bool { - let property = property.to_physical(after_change_style.writing_mode); - transitions_to_keep.insert(property); - self.needs_transitions_update_per_property( - property, - combined_duration, - before_change_style, - after_change_style, - &existing_transitions, - ) - }; - - match transition_property { - TransitionProperty::Custom(..) | TransitionProperty::Unsupported(..) => {}, - TransitionProperty::Shorthand(ref shorthand) => { - if shorthand.longhands().any(property_check_helper) { - return true; - } - }, - TransitionProperty::Longhand(longhand_id) => { - if property_check_helper(longhand_id) { - return true; - } - }, + for transition_property in after_change_style.transition_properties() { + let physical_longhand = transition_property + .longhand_id + .to_physical(after_change_style.writing_mode); + transitions_to_keep.insert(physical_longhand); + if self.needs_transitions_update_per_property( + physical_longhand, + after_change_box_style.transition_combined_duration_at(transition_property.index), + before_change_style, + after_change_style, + &existing_transitions, + ) { + return true; } } @@ -1634,6 +1594,22 @@ impl<'le> TElement for GeckoElement<'le> { .any(|property| !transitions_to_keep.contains(*property)) } + /// Whether there is an ElementData container. + #[inline] + fn has_data(&self) -> bool { + self.get_data().is_some() + } + + /// Immutably borrows the ElementData. + fn borrow_data(&self) -> Option<AtomicRef<ElementData>> { + self.get_data().map(|x| x.borrow()) + } + + /// Mutably borrows the ElementData. + fn mutate_data(&self) -> Option<AtomicRefMut<ElementData>> { + self.get_data().map(|x| x.borrow_mut()) + } + #[inline] fn lang_attr(&self) -> Option<AttrValue> { let ptr = unsafe { bindings::Gecko_LangValue(self.0) }; @@ -2064,6 +2040,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { NonTSPseudoClass::MozReadOnly | NonTSPseudoClass::MozReadWrite | NonTSPseudoClass::FocusWithin | + NonTSPseudoClass::FocusVisible | NonTSPseudoClass::MozDragOver | NonTSPseudoClass::MozDevtoolsHighlighted | NonTSPseudoClass::MozStyleeditorTransitioning | @@ -2226,11 +2203,6 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { } #[inline] - fn exported_part(&self, name: &Atom) -> Option<Atom> { - snapshot_helpers::exported_part(self.attrs(), name) - } - - #[inline] fn imported_part(&self, name: &Atom) -> Option<Atom> { snapshot_helpers::imported_part(self.attrs(), name) } diff --git a/components/style/gecko_string_cache/namespace.rs b/components/style/gecko_string_cache/namespace.rs index 2dba484e002..72de229f1d7 100644 --- a/components/style/gecko_string_cache/namespace.rs +++ b/components/style/gecko_string_cache/namespace.rs @@ -24,7 +24,18 @@ macro_rules! ns { } /// A Gecko namespace is just a wrapped atom. -#[derive(Clone, Debug, Default, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)] +#[derive( + Clone, + Debug, + Default, + Eq, + Hash, + MallocSizeOf, + PartialEq, + ToComputedValue, + ToResolvedValue, + ToShmem, +)] #[repr(transparent)] pub struct Namespace(pub Atom); diff --git a/components/style/invalidation/element/element_wrapper.rs b/components/style/invalidation/element/element_wrapper.rs index bc74527bf16..1154c136165 100644 --- a/components/style/invalidation/element/element_wrapper.rs +++ b/components/style/invalidation/element/element_wrapper.rs @@ -62,9 +62,6 @@ pub trait ElementSnapshot: Sized { /// called if `has_attrs()` returns true. fn is_part(&self, name: &Atom) -> bool; - /// See Element::exported_part. - fn exported_part(&self, name: &Atom) -> Option<Atom>; - /// See Element::imported_part. fn imported_part(&self, name: &Atom) -> Option<Atom>; @@ -371,13 +368,6 @@ where } } - fn exported_part(&self, name: &Atom) -> Option<Atom> { - match self.snapshot() { - Some(snapshot) if snapshot.has_attrs() => snapshot.exported_part(name), - _ => self.element.exported_part(name), - } - } - fn imported_part(&self, name: &Atom) -> Option<Atom> { match self.snapshot() { Some(snapshot) if snapshot.has_attrs() => snapshot.imported_part(name), diff --git a/components/style/properties/Mako-0.9.1.zip b/components/style/properties/Mako-0.9.1.zip Binary files differdeleted file mode 100644 index b7450e30012..00000000000 --- a/components/style/properties/Mako-0.9.1.zip +++ /dev/null diff --git a/components/style/properties/Mako-1.1.2-py2.py3-none-any.whl b/components/style/properties/Mako-1.1.2-py2.py3-none-any.whl Binary files differnew file mode 100644 index 00000000000..9593025a473 --- /dev/null +++ b/components/style/properties/Mako-1.1.2-py2.py3-none-any.whl diff --git a/components/style/properties/build.py b/components/style/properties/build.py index 45d8fa676ab..92966ce1b2d 100644 --- a/components/style/properties/build.py +++ b/components/style/properties/build.py @@ -8,7 +8,7 @@ import re import sys BASE = os.path.dirname(__file__.replace('\\', '/')) -sys.path.insert(0, os.path.join(BASE, "Mako-0.9.1.zip")) +sys.path.insert(0, os.path.join(BASE, "Mako-1.1.2-py2.py3-none-any.whl")) sys.path.insert(0, BASE) # For importing `data.py` from mako import exceptions @@ -130,7 +130,7 @@ def main(): def abort(message): - sys.stderr.write(message + b"\n") + print(message, file=sys.stderr) sys.exit(1) @@ -146,18 +146,18 @@ def render(filename, **context): strict_undefined=True) # Uncomment to debug generated Python code: # write("/tmp", "mako_%s.py" % os.path.basename(filename), template.code) - return template.render(**context).encode("utf8") + return template.render(**context) except Exception: # Uncomment to see a traceback in generated Python code: # raise - abort(exceptions.text_error_template().render().encode("utf8")) + abort(exceptions.text_error_template().render()) def write(directory, filename, content): if not os.path.exists(directory): os.makedirs(directory) full_path = os.path.join(directory, filename) - open(full_path, "wb").write(content) + open(full_path, "w", encoding="utf-8").write(content) python_addr = RE_PYTHON_ADDR.search(content) if python_addr: diff --git a/components/style/properties/cascade.rs b/components/style/properties/cascade.rs index 50029da8479..e9a34d6bf34 100644 --- a/components/style/properties/cascade.rs +++ b/components/style/properties/cascade.rs @@ -13,7 +13,7 @@ use crate::media_queries::Device; use crate::properties::{ComputedValues, StyleBuilder}; use crate::properties::{LonghandId, LonghandIdSet, CSSWideKeyword}; use crate::properties::{PropertyDeclaration, PropertyDeclarationId, DeclarationImportanceIterator}; -use crate::properties::CASCADE_PROPERTY; +use crate::properties::{CASCADE_PROPERTY, ComputedValueFlags}; use crate::rule_cache::{RuleCache, RuleCacheConditions}; use crate::rule_tree::StrongRuleNode; use crate::selector_parser::PseudoElement; @@ -337,89 +337,80 @@ where context.builder.build() } -/// How should a declaration behave when ignoring document colors? -enum DeclarationApplication { - /// We should apply the declaration. - Apply, - /// We should ignore the declaration. - Ignore, - /// We should apply the following declaration, only if any other declaration - /// hasn't set it before. - ApplyUnlessOverriden(PropertyDeclaration), -} +/// For ignored colors mode, we sometimes want to do something equivalent to +/// "revert-or-initial", where we `revert` for a given origin, but then apply a +/// given initial value if nothing in other origins did override it. +/// +/// This is a bit of a clunky way of achieving this. +type DeclarationsToApplyUnlessOverriden = SmallVec::<[PropertyDeclaration; 2]>; -fn application_when_ignoring_colors( +fn tweak_when_ignoring_colors( builder: &StyleBuilder, longhand_id: LonghandId, origin: Origin, - declaration: &PropertyDeclaration, -) -> DeclarationApplication { + declaration: &mut Cow<PropertyDeclaration>, + declarations_to_apply_unless_overriden: &mut DeclarationsToApplyUnlessOverriden, +) { if !longhand_id.ignored_when_document_colors_disabled() { - return DeclarationApplication::Apply; + return; } let is_ua_or_user_rule = matches!(origin, Origin::User | Origin::UserAgent); if is_ua_or_user_rule { - return DeclarationApplication::Apply; + return; } // Don't override background-color on ::-moz-color-swatch. It is set as an // author style (via the style attribute), but it's pretty important for it // to show up for obvious reasons :) if builder.pseudo.map_or(false, |p| p.is_color_swatch()) && longhand_id == LonghandId::BackgroundColor { - return DeclarationApplication::Apply; + return; } - // Treat background-color a bit differently. If the specified color is - // anything other than a fully transparent color, convert it into the - // Device's default background color. - // Also: for now, we treat background-image a bit differently, too. - // background-image is marked as ignored, but really, we only ignore - // it when backplates are disabled (since then text may be unreadable over - // a background image, if we're ignoring document colors). - // Here we check backplate status to decide if ignoring background-image - // is the right decision. - match *declaration { + // A few special-cases ahead. + match **declaration { + // We honor color and background-color: transparent, and + // "revert-or-initial" otherwise. PropertyDeclaration::BackgroundColor(ref color) => { - if color.is_transparent() { - return DeclarationApplication::Apply; + if !color.is_transparent() { + let color = builder.device.default_background_color(); + declarations_to_apply_unless_overriden.push( + PropertyDeclaration::BackgroundColor(color.into()) + ) } - let color = builder.device.default_background_color(); - DeclarationApplication::ApplyUnlessOverriden( - PropertyDeclaration::BackgroundColor(color.into()) - ) } PropertyDeclaration::Color(ref color) => { + // otherwise. if color.0.is_transparent() { - return DeclarationApplication::Apply; - } - if builder.get_parent_inherited_text().clone_color().alpha != 0 { - return DeclarationApplication::Ignore; + return; } let color = builder.device.default_color(); - DeclarationApplication::ApplyUnlessOverriden( + declarations_to_apply_unless_overriden.push( PropertyDeclaration::Color(specified::ColorPropertyValue(color.into())) ) }, - // In the future, if/when we remove the backplate pref, we can remove this - // special case along with the 'ignored_when_colors_disabled=True' mako line - // for the "background-image" property. + // We honor url background-images if backplating. #[cfg(feature = "gecko")] - PropertyDeclaration::BackgroundImage(..) => { + PropertyDeclaration::BackgroundImage(ref bkg) => { + use crate::values::generics::image::Image; if static_prefs::pref!("browser.display.permit_backplate") { - DeclarationApplication::Apply - } else { - DeclarationApplication::Ignore + if bkg.0.iter().all(|image| matches!(*image, Image::Url(..))) { + return; + } } }, - _ => DeclarationApplication::Ignore, + _ => {}, } + + *declaration.to_mut() = PropertyDeclaration::css_wide_keyword(longhand_id, CSSWideKeyword::Revert); + } struct Cascade<'a, 'b: 'a> { context: &'a mut computed::Context<'b>, cascade_mode: CascadeMode<'a>, seen: LonghandIdSet, + author_specified: LonghandIdSet, reverted: PerOrigin<LonghandIdSet>, } @@ -429,6 +420,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { context, cascade_mode, seen: LonghandIdSet::default(), + author_specified: LonghandIdSet::default(), reverted: Default::default(), } } @@ -491,7 +483,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { let ignore_colors = !self.context.builder.device.use_document_colors(); let mut declarations_to_apply_unless_overriden = - SmallVec::<[PropertyDeclaration; 2]>::new(); + DeclarationsToApplyUnlessOverriden::new(); for (declaration, origin) in declarations { let declaration_id = declaration.id(); @@ -533,26 +525,23 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { continue; } - let declaration = self.substitute_variables_if_needed(declaration); + let mut declaration = self.substitute_variables_if_needed(declaration); // When document colors are disabled, do special handling of // properties that are marked as ignored in that mode. if ignore_colors { - let application = application_when_ignoring_colors( + tweak_when_ignoring_colors( &self.context.builder, longhand_id, origin, - &declaration, + &mut declaration, + &mut declarations_to_apply_unless_overriden, + ); + debug_assert_eq!( + declaration.id(), + PropertyDeclarationId::Longhand(longhand_id), + "Shouldn't change the declaration id!", ); - - match application { - DeclarationApplication::Ignore => continue, - DeclarationApplication::Apply => {}, - DeclarationApplication::ApplyUnlessOverriden(decl) => { - declarations_to_apply_unless_overriden.push(decl); - continue; - } - } } let css_wide_keyword = declaration.get_css_wide_keyword(); @@ -569,6 +558,9 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { } self.seen.insert(physical_longhand_id); + if origin == Origin::Author { + self.author_specified.insert(physical_longhand_id); + } let unset = css_wide_keyword.map_or(false, |css_wide_keyword| { match css_wide_keyword { @@ -691,6 +683,14 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { if let Some(svg) = builder.get_svg_if_mutated() { svg.fill_arrays(); } + + } + + if self.author_specified.contains_any(LonghandIdSet::border_background_properties()) { + builder.add_flags(ComputedValueFlags::HAS_AUTHOR_SPECIFIED_BORDER_BACKGROUND); + } + if self.author_specified.contains_any(LonghandIdSet::padding_properties()) { + builder.add_flags(ComputedValueFlags::HAS_AUTHOR_SPECIFIED_PADDING); } #[cfg(feature = "servo")] @@ -711,12 +711,26 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { None => return false, }; - let cached_style = match cache.find(guards, &self.context.builder) { + let builder = &mut self.context.builder; + + let cached_style = match cache.find(guards, &builder) { Some(style) => style, None => return false, }; - self.context.builder.copy_reset_from(cached_style); + builder.copy_reset_from(cached_style); + + // We're using the same reset style as another element, and we'll skip + // applying the relevant properties. So we need to do the relevant + // bookkeeping here to keep these two bits correct. + // + // Note that all the properties involved are non-inherited, so we don't + // need to do anything else other than just copying the bits over. + let reset_props_bits = + ComputedValueFlags::HAS_AUTHOR_SPECIFIED_BORDER_BACKGROUND | + ComputedValueFlags::HAS_AUTHOR_SPECIFIED_PADDING; + builder.add_flags(cached_style.flags & reset_props_bits); + true } diff --git a/components/style/properties/computed_value_flags.rs b/components/style/properties/computed_value_flags.rs index 4363f3f36e9..221363ba4b1 100644 --- a/components/style/properties/computed_value_flags.rs +++ b/components/style/properties/computed_value_flags.rs @@ -67,6 +67,23 @@ bitflags! { /// Whether this style is the style of the document element. const IS_ROOT_ELEMENT_STYLE = 1 << 11; + + /// Whether this element is inside an `opacity: 0` subtree. + const IS_IN_OPACITY_ZERO_SUBTREE = 1 << 12; + + /// Whether there are author-specified rules for border-* properties + /// (except border-image-*), background-color, or background-image. + /// + /// TODO(emilio): Maybe do include border-image, see: + /// + /// https://github.com/w3c/csswg-drafts/issues/4777#issuecomment-604424845 + const HAS_AUTHOR_SPECIFIED_BORDER_BACKGROUND = 1 << 13; + + /// Whether there are author-specified rules for padding-* properties. + /// + /// FIXME(emilio): Try to merge this with BORDER_BACKGROUND, see + /// https://github.com/w3c/csswg-drafts/issues/4777 + const HAS_AUTHOR_SPECIFIED_PADDING = 1 << 14; } } @@ -74,10 +91,11 @@ impl ComputedValueFlags { /// Flags that are unconditionally propagated to descendants. #[inline] fn inherited_flags() -> Self { - ComputedValueFlags::IS_RELEVANT_LINK_VISITED | - ComputedValueFlags::CAN_BE_FRAGMENTED | - ComputedValueFlags::IS_IN_PSEUDO_ELEMENT_SUBTREE | - ComputedValueFlags::HAS_TEXT_DECORATION_LINES + Self::IS_RELEVANT_LINK_VISITED | + Self::CAN_BE_FRAGMENTED | + Self::IS_IN_PSEUDO_ELEMENT_SUBTREE | + Self::HAS_TEXT_DECORATION_LINES | + Self::IS_IN_OPACITY_ZERO_SUBTREE } /// Flags that may be propagated to descendants. diff --git a/components/style/properties/data.py b/components/style/properties/data.py index 15ab380789b..472d1eb34dd 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -382,6 +382,7 @@ class Longhand(object): "ScrollSnapStrictness", "ScrollSnapType", "TextAlign", + "TextAlignLast", "TextDecorationLine", "TextEmphasisPosition", "TextTransform", @@ -602,7 +603,7 @@ class PropertiesData(object): longhand = Longhand(self.current_style_struct, name, **kwargs) self.add_prefixed_aliases(longhand) - longhand.alias = list(map(lambda xp: Alias(xp[0], longhand, xp[1]), longhand.alias)) + longhand.alias = [Alias(xp[0], longhand, xp[1]) for xp in longhand.alias] self.longhand_aliases += longhand.alias self.current_style_struct.longhands.append(longhand) self.longhands.append(longhand) @@ -620,7 +621,7 @@ class PropertiesData(object): sub_properties = [self.longhands_by_name[s] for s in sub_properties] shorthand = Shorthand(name, sub_properties, *args, **kwargs) self.add_prefixed_aliases(shorthand) - shorthand.alias = list(map(lambda xp: Alias(xp[0], shorthand, xp[1]), shorthand.alias)) + shorthand.alias = [Alias(xp[0], shorthand, xp[1]) for xp in shorthand.alias] self.shorthand_aliases += shorthand.alias self.shorthands.append(shorthand) self.shorthands_by_name[name] = shorthand @@ -669,17 +670,17 @@ def _remove_common_first_line_and_first_letter_properties(props, engine): class PropertyRestrictions: @staticmethod def logical_group(data, group): - return map(lambda p: p.name, data.longhands_by_logical_group[group]) + return [p.name for p in data.longhands_by_logical_group[group]] @staticmethod def shorthand(data, shorthand): if shorthand not in data.shorthands_by_name: return [] - return map(lambda p: p.name, data.shorthands_by_name[shorthand].sub_properties) + return [p.name for p in data.shorthands_by_name[shorthand].sub_properties] @staticmethod def spec(data, spec_path): - return map(lambda p: p.name, filter(lambda p: spec_path in p.spec, data.longhands)) + return [p.name for p in data.longhands if spec_path in p.spec] # https://drafts.csswg.org/css-pseudo/#first-letter-styling @staticmethod diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 6cfb4c859b4..f3db987d8f9 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -22,16 +22,14 @@ use crate::gecko_bindings::bindings::Gecko_CopyConstruct_${style_struct.gecko_ff use crate::gecko_bindings::bindings::Gecko_Destroy_${style_struct.gecko_ffi_name}; % endfor use crate::gecko_bindings::bindings::Gecko_CopyCounterStyle; -use crate::gecko_bindings::bindings::Gecko_CopyCursorArrayFrom; use crate::gecko_bindings::bindings::Gecko_CopyFontFamilyFrom; -use crate::gecko_bindings::bindings::Gecko_CopyImageValueFrom; use crate::gecko_bindings::bindings::Gecko_EnsureImageLayersLength; use crate::gecko_bindings::bindings::Gecko_nsStyleFont_SetLang; use crate::gecko_bindings::bindings::Gecko_nsStyleFont_CopyLangFrom; -use crate::gecko_bindings::bindings::Gecko_SetNullImageValue; use crate::gecko_bindings::structs; use crate::gecko_bindings::structs::nsCSSPropertyID; use crate::gecko_bindings::structs::mozilla::PseudoStyleType; +use crate::gecko::data::PerDocumentStyleData; use crate::gecko::values::round_border_to_device_pixels; use crate::logical_geometry::WritingMode; use crate::media_queries::Device; @@ -43,11 +41,9 @@ use std::mem::{forget, MaybeUninit}; use std::{cmp, ops, ptr}; use crate::values::{self, CustomIdent, Either, KeyframesName, None_}; use crate::values::computed::{Percentage, TransitionProperty}; -use crate::values::computed::url::ComputedImageUrl; use crate::values::computed::BorderStyle; use crate::values::computed::font::FontSize; use crate::values::generics::column::ColumnCount; -use crate::values::generics::image::ImageLayer; pub mod style_structs { @@ -392,112 +388,6 @@ def set_gecko_property(ffi_name, expr): } </%def> -<%def name="impl_svg_length(ident, gecko_ffi_name)"> - // When context-value is used on an SVG length, the corresponding flag is - // set on mContextFlags, and the length field is set to the initial value. - - pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { - use crate::values::generics::svg::SVGLength; - use crate::gecko_bindings::structs::nsStyleSVG_${ident.upper()}_CONTEXT as CONTEXT_VALUE; - let length = match v { - SVGLength::LengthPercentage(length) => { - self.gecko.mContextFlags &= !CONTEXT_VALUE; - length - } - SVGLength::ContextValue => { - self.gecko.mContextFlags |= CONTEXT_VALUE; - match longhands::${ident}::get_initial_value() { - SVGLength::LengthPercentage(length) => length, - _ => unreachable!("Initial value should not be context-value"), - } - } - }; - self.gecko.${gecko_ffi_name} = length; - } - - pub fn copy_${ident}_from(&mut self, other: &Self) { - use crate::gecko_bindings::structs::nsStyleSVG_${ident.upper()}_CONTEXT as CONTEXT_VALUE; - self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name}.clone(); - self.gecko.mContextFlags = - (self.gecko.mContextFlags & !CONTEXT_VALUE) | - (other.gecko.mContextFlags & CONTEXT_VALUE); - } - - pub fn reset_${ident}(&mut self, other: &Self) { - self.copy_${ident}_from(other) - } - - pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { - use crate::values::generics::svg::SVGLength; - use crate::gecko_bindings::structs::nsStyleSVG_${ident.upper()}_CONTEXT as CONTEXT_VALUE; - if (self.gecko.mContextFlags & CONTEXT_VALUE) != 0 { - return SVGLength::ContextValue; - } - SVGLength::LengthPercentage(self.gecko.${gecko_ffi_name}.clone()) - } -</%def> - -<%def name="impl_svg_opacity(ident, gecko_ffi_name)"> - <% source_prefix = ident.split("_")[0].upper() + "_OPACITY_SOURCE" %> - - pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { - use crate::gecko_bindings::structs::nsStyleSVG_${source_prefix}_MASK as MASK; - use crate::gecko_bindings::structs::nsStyleSVG_${source_prefix}_SHIFT as SHIFT; - use crate::gecko_bindings::structs::nsStyleSVGOpacitySource::*; - use crate::values::generics::svg::SVGOpacity; - self.gecko.mContextFlags &= !MASK; - match v { - SVGOpacity::Opacity(opacity) => { - self.gecko.mContextFlags |= - (eStyleSVGOpacitySource_Normal as u8) << SHIFT; - self.gecko.${gecko_ffi_name} = opacity; - } - SVGOpacity::ContextFillOpacity => { - self.gecko.mContextFlags |= - (eStyleSVGOpacitySource_ContextFillOpacity as u8) << SHIFT; - self.gecko.${gecko_ffi_name} = 1.; - } - SVGOpacity::ContextStrokeOpacity => { - self.gecko.mContextFlags |= - (eStyleSVGOpacitySource_ContextStrokeOpacity as u8) << SHIFT; - self.gecko.${gecko_ffi_name} = 1.; - } - } - } - - pub fn copy_${ident}_from(&mut self, other: &Self) { - use crate::gecko_bindings::structs::nsStyleSVG_${source_prefix}_MASK as MASK; - self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name}; - self.gecko.mContextFlags = - (self.gecko.mContextFlags & !MASK) | - (other.gecko.mContextFlags & MASK); - } - - pub fn reset_${ident}(&mut self, other: &Self) { - self.copy_${ident}_from(other) - } - - pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { - use crate::gecko_bindings::structs::nsStyleSVG_${source_prefix}_MASK as MASK; - use crate::gecko_bindings::structs::nsStyleSVG_${source_prefix}_SHIFT as SHIFT; - use crate::gecko_bindings::structs::nsStyleSVGOpacitySource::*; - use crate::values::generics::svg::SVGOpacity; - - let source = (self.gecko.mContextFlags & MASK) >> SHIFT; - if source == eStyleSVGOpacitySource_Normal as u8 { - return SVGOpacity::Opacity(self.gecko.${gecko_ffi_name}); - } else { - debug_assert_eq!(self.gecko.${gecko_ffi_name}, 1.0); - if source == eStyleSVGOpacitySource_ContextFillOpacity as u8 { - SVGOpacity::ContextFillOpacity - } else { - debug_assert_eq!(source, eStyleSVGOpacitySource_ContextStrokeOpacity as u8); - SVGOpacity::ContextStrokeOpacity - } - } - } -</%def> - <%def name="impl_non_negative_length(ident, gecko_ffi_name, inherit_from=None, round_to_pixels=False)"> #[allow(non_snake_case)] @@ -647,12 +537,7 @@ impl Clone for ${style_struct.gecko_struct_name} { </%def> -<%def name="impl_simple_type_with_conversion(ident, gecko_ffi_name=None)"> - <% - if gecko_ffi_name is None: - gecko_ffi_name = "m" + to_camel_case(ident) - %> - +<%def name="impl_simple_type_with_conversion(ident, gecko_ffi_name)"> #[allow(non_snake_case)] pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { self.gecko.${gecko_ffi_name} = From::from(v) @@ -711,9 +596,6 @@ impl Clone for ${style_struct.gecko_struct_name} { # Types used with predefined_type()-defined properties that we can auto-generate. predefined_types = { "MozScriptMinSize": impl_absolute_length, - "SVGLength": impl_svg_length, - "SVGOpacity": impl_svg_opacity, - "SVGWidth": impl_svg_length, } def longhand_method(longhand): @@ -778,8 +660,7 @@ fn static_assert() { for x in CORNERS]) %> <%self:impl_trait style_struct_name="Border" - skip_longhands="${skip_border_longhands} border-image-source - border-image-repeat"> + skip_longhands="${skip_border_longhands} border-image-repeat"> % for side in SIDES: pub fn set_border_${side.ident}_style(&mut self, v: BorderStyle) { self.gecko.mBorderStyle[${side.index}] = v; @@ -848,35 +729,6 @@ fn static_assert() { corner) %> % endfor - pub fn set_border_image_source(&mut self, image: longhands::border_image_source::computed_value::T) { - unsafe { - // Prevent leaking of the last elements we did set - Gecko_SetNullImageValue(&mut self.gecko.mBorderImageSource); - } - - if let ImageLayer::Image(image) = image { - self.gecko.mBorderImageSource.set(image); - } - } - - pub fn copy_border_image_source_from(&mut self, other: &Self) { - unsafe { - Gecko_CopyImageValueFrom(&mut self.gecko.mBorderImageSource, - &other.gecko.mBorderImageSource); - } - } - - pub fn reset_border_image_source(&mut self, other: &Self) { - self.copy_border_image_source_from(other) - } - - pub fn clone_border_image_source(&self) -> longhands::border_image_source::computed_value::T { - match unsafe { self.gecko.mBorderImageSource.into_image() } { - Some(image) => ImageLayer::Image(image), - None => ImageLayer::None, - } - } - <% border_image_repeat_keywords = ["Stretch", "Repeat", "Round", "Space"] %> @@ -950,11 +802,10 @@ fn static_assert() { <% skip_position_longhands = " ".join(x.ident for x in SIDES) %> <%self:impl_trait style_struct_name="Position" - skip_longhands="${skip_position_longhands} grid-auto-flow"> + skip_longhands="${skip_position_longhands}"> % for side in SIDES: <% impl_split_style_coord(side.ident, "mOffset", side.index) %> % endfor - ${impl_simple_type_with_conversion("grid_auto_flow")} pub fn set_computed_justify_items(&mut self, v: values::specified::JustifyItems) { debug_assert_ne!(v.0, crate::values::specified::align::AlignFlags::LEGACY); self.gecko.mJustifyItems.computed = v; @@ -1005,15 +856,13 @@ fn static_assert() { } </%self:impl_trait> -<% - skip_font_longhands = """font-family font-size font-size-adjust font-weight - font-style font-stretch -moz-script-level - font-synthesis -x-lang font-variant-alternates - font-variant-east-asian font-variant-ligatures - font-variant-numeric font-language-override - font-feature-settings font-variation-settings - -moz-min-font-size-ratio -x-text-zoom""" -%> +<% skip_font_longhands = """font-family font-size font-size-adjust font-weight + font-style font-stretch font-synthesis -x-lang + font-variant-alternates font-variant-east-asian + font-variant-ligatures font-variant-numeric + font-language-override font-feature-settings + font-variation-settings -moz-min-font-size-ratio + -x-text-zoom""" %> <%self:impl_trait style_struct_name="Font" skip_longhands="${skip_font_longhands}"> @@ -1275,9 +1124,7 @@ fn static_assert() { longhands::_x_text_zoom::computed_value::T(self.gecko.mAllowZoom) } - ${impl_simple("_moz_script_level", "mScriptLevel")} <% impl_simple_type_with_conversion("font_language_override", "mFont.languageOverride") %> - ${impl_simple_type_with_conversion("font_variant_ligatures", "mFont.variantLigatures")} ${impl_simple_type_with_conversion("font_variant_east_asian", "mFont.variantEastAsian")} ${impl_simple_type_with_conversion("font_variant_numeric", "mFont.variantNumeric")} @@ -1401,9 +1248,6 @@ fn static_assert() { ${impl_copy_animation_or_transition_value('animation', ident, gecko_ffi_name)} </%def> -<%def name="impl_transition_timing_function()"> - ${impl_animation_or_transition_timing_function('transition')} -</%def> <%def name="impl_animation_count(ident, gecko_ffi_name)"> ${impl_animation_or_transition_count('animation', ident, gecko_ffi_name)} @@ -1413,10 +1257,6 @@ fn static_assert() { ${impl_animation_or_transition_time_value('animation', ident, gecko_ffi_name)} </%def> -<%def name="impl_animation_timing_function()"> - ${impl_animation_or_transition_timing_function('animation')} -</%def> - <%def name="impl_animation_keyword(ident, gecko_ffi_name, keyword, cast_type='u8')"> #[allow(non_snake_case)] pub fn set_animation_${ident}<I>(&mut self, v: I) @@ -1466,7 +1306,7 @@ fn static_assert() { animation-iteration-count animation-timing-function clear transition-duration transition-delay transition-timing-function transition-property - shape-outside -webkit-line-clamp""" %> + -webkit-line-clamp""" %> <%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}"> #[inline] pub fn set_display(&mut self, v: longhands::display::computed_value::T) { @@ -1509,7 +1349,7 @@ fn static_assert() { ${impl_transition_time_value('delay', 'Delay')} ${impl_transition_time_value('duration', 'Duration')} - ${impl_transition_timing_function()} + ${impl_animation_or_transition_timing_function('transition')} pub fn transition_combined_duration_at(&self, index: usize) -> f32 { // https://drafts.csswg.org/css-transitions/#transition-combined-duration @@ -1723,10 +1563,7 @@ fn static_assert() { ${impl_animation_count('iteration_count', 'IterationCount')} ${impl_copy_animation_value('iteration_count', 'IterationCount')} - - ${impl_animation_timing_function()} - - <% impl_shape_source("shape_outside", "mShapeOutside") %> + ${impl_animation_or_transition_timing_function('animation')} #[allow(non_snake_case)] pub fn set__webkit_line_clamp(&mut self, v: longhands::_webkit_line_clamp::computed_value::T) { @@ -2009,7 +1846,7 @@ fn static_assert() { for (layer, other) in self.gecko.${image_layers_field}.mLayers.iter_mut() .zip(other.gecko.${image_layers_field}.mLayers.iter()) .take(count as usize) { - Gecko_CopyImageValueFrom(&mut layer.mImage, &other.mImage); + layer.mImage = other.mImage.clone(); } self.gecko.${image_layers_field}.mImageCount = count; } @@ -2029,22 +1866,17 @@ fn static_assert() { let images = images.into_iter(); unsafe { - // Prevent leaking of the last elements we did set - for image in &mut self.gecko.${image_layers_field}.mLayers { - Gecko_SetNullImageValue(&mut image.mImage) - } - // XXXManishearth clear mSourceURI for masks - Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field}, images.len(), - LayerType::${shorthand.title()}); + Gecko_EnsureImageLayersLength( + &mut self.gecko.${image_layers_field}, + images.len(), + LayerType::${shorthand.title()}, + ); } self.gecko.${image_layers_field}.mImageCount = images.len() as u32; - for (image, geckoimage) in images.zip(self.gecko.${image_layers_field} .mLayers.iter_mut()) { - if let ImageLayer::Image(image) = image { - geckoimage.mImage.set(image) - } + geckoimage.mImage = image; } } @@ -2052,12 +1884,8 @@ fn static_assert() { longhands::${shorthand}_image::computed_value::List( self.gecko.${image_layers_field}.mLayers.iter() .take(self.gecko.${image_layers_field}.mImageCount as usize) - .map(|ref layer| { - match unsafe { layer.mImage.into_image() } { - Some(image) => ImageLayer::Image(image), - None => ImageLayer::None, - } - }).collect() + .map(|layer| layer.mImage.clone()) + .collect() ) } @@ -2189,18 +2017,9 @@ fn static_assert() { <%self:impl_trait style_struct_name="InheritedText" - skip_longhands="text-align -webkit-text-stroke-width text-emphasis-position"> - - <% text_align_keyword = Keyword("text-align", - "start end left right center justify -moz-center -moz-left -moz-right char", - gecko_strip_moz_prefix=False) %> - ${impl_keyword('text_align', 'mTextAlign', text_align_keyword)} - - ${impl_simple_type_with_conversion("text_emphasis_position")} - + skip_longhands="-webkit-text-stroke-width"> ${impl_non_negative_length('_webkit_text_stroke_width', 'mWebkitTextStrokeWidth')} - </%self:impl_trait> <%self:impl_trait style_struct_name="Text" skip_longhands="initial-letter"> @@ -2244,204 +2063,21 @@ fn static_assert() { } </%self:impl_trait> -// Set SVGPathData to StyleShapeSource. -fn set_style_svg_path( - shape_source: &mut structs::mozilla::StyleShapeSource, - servo_path: values::specified::svg_path::SVGPathData, - fill: values::generics::basic_shape::FillRule, -) { - // Setup path. - unsafe { - bindings::Gecko_SetToSVGPath( - shape_source, - servo_path.0.forget(), - fill, - ); - } -} - -<%def name="impl_shape_source(ident, gecko_ffi_name)"> - pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { - use crate::values::generics::basic_shape::ShapeSource; - use crate::gecko_bindings::structs::StyleShapeSourceType; - use crate::gecko_bindings::structs::StyleGeometryBox; - - let ref mut ${ident} = self.gecko.${gecko_ffi_name}; - - // clean up existing struct. - unsafe { bindings::Gecko_DestroyShapeSource(${ident}) }; - - ${ident}.mType = StyleShapeSourceType::None; - - match v { - ShapeSource::None => {} // don't change the type - ShapeSource::ImageOrUrl(image) => { - % if ident == "clip_path": - use crate::values::generics::image::Image; - - let image = Image::Url(ComputedImageUrl(image)); - % endif - unsafe { - bindings::Gecko_NewShapeImage(${ident}); - let style_image = &mut *${ident}.__bindgen_anon_1.mShapeImage.as_mut().mPtr; - style_image.set(image); - } - } - ShapeSource::Box(reference) => { - ${ident}.mReferenceBox = reference.into(); - ${ident}.mType = StyleShapeSourceType::Box; - } - ShapeSource::Path(p) => set_style_svg_path(${ident}, p.path, p.fill), - ShapeSource::Shape(servo_shape, maybe_box) => { - unsafe { - ${ident}.__bindgen_anon_1.mBasicShape.as_mut().mPtr = - Box::into_raw(servo_shape); - } - ${ident}.mReferenceBox = - maybe_box.map(Into::into).unwrap_or(StyleGeometryBox::NoBox); - ${ident}.mType = StyleShapeSourceType::Shape; - } - } - - } - - pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { - (&self.gecko.${gecko_ffi_name}).into() - } - - pub fn copy_${ident}_from(&mut self, other: &Self) { - use crate::gecko_bindings::bindings::Gecko_CopyShapeSourceFrom; - unsafe { - Gecko_CopyShapeSourceFrom(&mut self.gecko.${gecko_ffi_name}, &other.gecko.${gecko_ffi_name}); - } - } - - pub fn reset_${ident}(&mut self, other: &Self) { - self.copy_${ident}_from(other) - } -</%def> - <% skip_svg_longhands = """ mask-mode mask-repeat mask-clip mask-origin mask-composite mask-position-x mask-position-y mask-size mask-image -clip-path """ %> <%self:impl_trait style_struct_name="SVG" skip_longhands="${skip_svg_longhands}"> - <% impl_common_image_layer_properties("mask") %> <% impl_simple_image_array_property("mode", "mask", "mMask", "mMaskMode", "SVG") %> <% impl_simple_image_array_property("composite", "mask", "mMask", "mComposite", "SVG") %> - <% impl_shape_source("clip_path", "mClipPath") %> </%self:impl_trait> -<%self:impl_trait style_struct_name="InheritedSVG" - skip_longhands="stroke-dasharray"> - pub fn set_stroke_dasharray(&mut self, v: longhands::stroke_dasharray::computed_value::T) { - use crate::gecko_bindings::structs::nsStyleSVG_STROKE_DASHARRAY_CONTEXT as CONTEXT_VALUE; - use crate::values::generics::svg::SVGStrokeDashArray; - - match v { - SVGStrokeDashArray::Values(v) => { - let v = v.into_iter(); - self.gecko.mContextFlags &= !CONTEXT_VALUE; - unsafe { - bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut *self.gecko, v.len() as u32); - } - for (gecko, servo) in self.gecko.mStrokeDasharray.iter_mut().zip(v) { - *gecko = servo; - } - } - SVGStrokeDashArray::ContextValue => { - self.gecko.mContextFlags |= CONTEXT_VALUE; - unsafe { - bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut *self.gecko, 0); - } - } - } - } - - pub fn copy_stroke_dasharray_from(&mut self, other: &Self) { - use crate::gecko_bindings::structs::nsStyleSVG_STROKE_DASHARRAY_CONTEXT as CONTEXT_VALUE; - unsafe { - bindings::Gecko_nsStyleSVG_CopyDashArray(&mut *self.gecko, &*other.gecko); - } - self.gecko.mContextFlags = - (self.gecko.mContextFlags & !CONTEXT_VALUE) | - (other.gecko.mContextFlags & CONTEXT_VALUE); - } - - pub fn reset_stroke_dasharray(&mut self, other: &Self) { - self.copy_stroke_dasharray_from(other) - } - - pub fn clone_stroke_dasharray(&self) -> longhands::stroke_dasharray::computed_value::T { - use crate::gecko_bindings::structs::nsStyleSVG_STROKE_DASHARRAY_CONTEXT as CONTEXT_VALUE; - use crate::values::generics::svg::SVGStrokeDashArray; - - if self.gecko.mContextFlags & CONTEXT_VALUE != 0 { - debug_assert_eq!(self.gecko.mStrokeDasharray.len(), 0); - return SVGStrokeDashArray::ContextValue; - } - SVGStrokeDashArray::Values(self.gecko.mStrokeDasharray.iter().cloned().collect()) - } +<%self:impl_trait style_struct_name="InheritedSVG"> </%self:impl_trait> -<%self:impl_trait style_struct_name="InheritedUI" skip_longhands="cursor"> - pub fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) { - self.gecko.mCursor = v.keyword; - unsafe { - bindings::Gecko_SetCursorArrayCapacity(&mut *self.gecko, v.images.len()); - } - for i in 0..v.images.len() { - unsafe { - bindings::Gecko_AppendCursorImage(&mut *self.gecko, &v.images[i].url); - } - - match v.images[i].hotspot { - Some((x, y)) => { - self.gecko.mCursorImages[i].mHaveHotspot = true; - self.gecko.mCursorImages[i].mHotspotX = x; - self.gecko.mCursorImages[i].mHotspotY = y; - }, - _ => { - self.gecko.mCursorImages[i].mHaveHotspot = false; - } - } - } - } - - pub fn copy_cursor_from(&mut self, other: &Self) { - self.gecko.mCursor = other.gecko.mCursor; - unsafe { - Gecko_CopyCursorArrayFrom(&mut *self.gecko, &*other.gecko); - } - } - - pub fn reset_cursor(&mut self, other: &Self) { - self.copy_cursor_from(other) - } - - pub fn clone_cursor(&self) -> longhands::cursor::computed_value::T { - use crate::values::computed::ui::CursorImage; - - let keyword = self.gecko.mCursor; - - let images = self.gecko.mCursorImages.iter().map(|gecko_cursor_image| { - let url = gecko_cursor_image.mImage.clone(); - - let hotspot = - if gecko_cursor_image.mHaveHotspot { - Some((gecko_cursor_image.mHotspotX, gecko_cursor_image.mHotspotY)) - } else { - None - }; - - CursorImage { url, hotspot } - }).collect::<Vec<_>>().into_boxed_slice(); - - longhands::cursor::computed_value::T { images, keyword } - } +<%self:impl_trait style_struct_name="InheritedUI"> </%self:impl_trait> <%self:impl_trait style_struct_name="Column" @@ -2483,8 +2119,7 @@ clip-path } </%self:impl_trait> -<%self:impl_trait style_struct_name="UI" skip_longhands="-moz-force-broken-image-icon"> - ${impl_simple_type_with_conversion("_moz_force_broken_image_icon", "mForceBrokenImageIcon")} +<%self:impl_trait style_struct_name="UI"> </%self:impl_trait> <%self:impl_trait style_struct_name="XUL"> @@ -2494,3 +2129,40 @@ clip-path ${declare_style_struct(style_struct)} ${impl_style_struct(style_struct)} % endfor + +/// Assert that the initial values set in Gecko style struct constructors +/// match the values returned by `get_initial_value()` for each longhand. +#[cfg(feature = "gecko")] +#[inline] +pub fn assert_initial_values_match(data: &PerDocumentStyleData) { + if cfg!(debug_assertions) { + let data = data.borrow(); + let cv = data.stylist.device().default_computed_values(); + <% + # Skip properties with initial values that change at computed value time. + SKIPPED = [ + "border-top-width", + "border-bottom-width", + "border-left-width", + "border-right-width", + "font-family", + "font-size", + "outline-width", + ] + TO_TEST = [p for p in data.longhands if p.enabled_in != "" and not p.logical and not p.name in SKIPPED] + %> + % for property in TO_TEST: + assert_eq!( + cv.clone_${property.ident}(), + longhands::${property.ident}::get_initial_value(), + concat!( + "initial value in Gecko style struct for ", + stringify!(${property.ident}), + " must match longhands::", + stringify!(${property.ident}), + "::get_initial_value()" + ) + ); + % endfor + } +} diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index 7a25b2569ea..9baab22cb45 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -680,7 +680,7 @@ % endfor let mut bits = ${type}::empty(); - % for servo_bit, gecko_bit in bit_map.iteritems(): + % for servo_bit, gecko_bit in bit_map.items(): if kw & (${gecko_bit_prefix}${gecko_bit} as ${kw_type}) != 0 { bits |= ${servo_bit}; } @@ -696,7 +696,7 @@ let mut bits: ${kw_type} = 0; // FIXME: if we ensure that the Servo bitflags storage is the same // as Gecko's one, we can just copy it. - % for servo_bit, gecko_bit in bit_map.iteritems(): + % for servo_bit, gecko_bit in bit_map.items(): if self.contains(${servo_bit}) { bits |= ${gecko_bit_prefix}${gecko_bit} as ${kw_type}; } @@ -707,7 +707,8 @@ </%def> <%def name="single_keyword(name, values, vector=False, - extra_specified=None, needs_conversion=False, **kwargs)"> + extra_specified=None, needs_conversion=False, + gecko_pref_controlled_initial_value=None, **kwargs)"> <% keyword_kwargs = {a: kwargs.pop(a, None) for a in [ 'gecko_constant_prefix', @@ -724,18 +725,19 @@ ]} %> - <%def name="inner_body(keyword, extra_specified=None, needs_conversion=False)"> + <%def name="inner_body(keyword, extra_specified=None, needs_conversion=False, + gecko_pref_controlled_initial_value=None)"> <%def name="variants(variants, include_aliases)"> % for variant in variants: % if include_aliases: <% aliases = [] - for alias, v in keyword.aliases_for(engine).iteritems(): + for alias, v in keyword.aliases_for(engine).items(): if variant == v: aliases.append(alias) %> % if aliases: - #[parse(aliases = "${','.join(aliases)}")] + #[parse(aliases = "${','.join(sorted(aliases))}")] % endif % endif ${to_camel_case(variant)}, @@ -773,10 +775,20 @@ } #[inline] pub fn get_initial_value() -> computed_value::T { + % if engine == "gecko" and gecko_pref_controlled_initial_value: + if static_prefs::pref!("${gecko_pref_controlled_initial_value.split('=')[0]}") { + return computed_value::T::${to_camel_case(gecko_pref_controlled_initial_value.split('=')[1])}; + } + % endif computed_value::T::${to_camel_case(values.split()[0])} } #[inline] pub fn get_initial_specified_value() -> SpecifiedValue { + % if engine == "gecko" and gecko_pref_controlled_initial_value: + if static_prefs::pref!("${gecko_pref_controlled_initial_value.split('=')[0]}") { + return SpecifiedValue::${to_camel_case(gecko_pref_controlled_initial_value.split('=')[1])}; + } + % endif SpecifiedValue::${to_camel_case(values.split()[0])} } #[inline] @@ -805,7 +817,8 @@ % else: <%call expr="longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)"> ${inner_body(Keyword(name, values, **keyword_kwargs), - extra_specified=extra_specified, needs_conversion=needs_conversion)} + extra_specified=extra_specified, needs_conversion=needs_conversion, + gecko_pref_controlled_initial_value=gecko_pref_controlled_initial_value)} % if caller: ${caller.body()} % endif diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 84f843ec728..2e9a53fc677 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -11,7 +11,7 @@ #[cfg(feature = "gecko")] use crate::gecko_bindings::structs::nsCSSPropertyID; use itertools::{EitherOrBoth, Itertools}; -use crate::properties::{CSSWideKeyword, PropertyDeclaration}; +use crate::properties::{CSSWideKeyword, PropertyDeclaration, NonCustomPropertyIterator}; use crate::properties::longhands; use crate::properties::longhands::visibility::computed_value::T as Visibility; use crate::properties::LonghandId; @@ -883,3 +883,66 @@ impl ToAnimatedZero for AnimatedFilter { } } } + +/// An iterator over all the properties that transition on a given style. +pub struct TransitionPropertyIterator<'a> { + style: &'a ComputedValues, + index_range: core::ops::Range<usize>, + longhand_iterator: Option<NonCustomPropertyIterator<LonghandId>>, +} + +impl<'a> TransitionPropertyIterator<'a> { + /// Create a `TransitionPropertyIterator` for the given style. + pub fn from_style(style: &'a ComputedValues) -> Self { + Self { + style, + index_range: 0..style.get_box().transition_property_count(), + longhand_iterator: None, + } + } +} + +/// A single iteration of the TransitionPropertyIterator. +pub struct TransitionPropertyIteration { + /// The id of the longhand for this property. + pub longhand_id: LonghandId, + + /// The index of this property in the list of transition properties for this + /// iterator's style. + pub index: usize, +} + +impl<'a> Iterator for TransitionPropertyIterator<'a> { + type Item = TransitionPropertyIteration; + + fn next(&mut self) -> Option<Self::Item> { + use crate::values::computed::TransitionProperty; + loop { + if let Some(ref mut longhand_iterator) = self.longhand_iterator { + if let Some(longhand_id) = longhand_iterator.next() { + return Some(TransitionPropertyIteration { + longhand_id, + index: self.index_range.start, + }); + } + self.longhand_iterator = None; + } + + let index = self.index_range.next()?; + match self.style.get_box().transition_property_at(index) { + TransitionProperty::Longhand(longhand_id) => { + return Some(TransitionPropertyIteration { + longhand_id, + index, + }) + } + // In the other cases, we set up our state so that we are ready to + // compute the next value of the iterator and then loop (equivalent + // to calling self.next()). + TransitionProperty::Shorthand(ref shorthand_id) => + self.longhand_iterator = Some(shorthand_id.longhands()), + TransitionProperty::Custom(..) | TransitionProperty::Unsupported(..) => {} + } + } + } +} diff --git a/components/style/properties/longhands/background.mako.rs b/components/style/properties/longhands/background.mako.rs index e0ef021f32d..1cbf601ad5d 100644 --- a/components/style/properties/longhands/background.mako.rs +++ b/components/style/properties/longhands/background.mako.rs @@ -21,10 +21,10 @@ ${helpers.predefined_type( ${helpers.predefined_type( "background-image", - "ImageLayer", + "Image", engines="gecko servo-2013 servo-2020", - initial_value="computed::ImageLayer::none()", - initial_specified_value="specified::ImageLayer::none()", + initial_value="computed::Image::None", + initial_specified_value="specified::Image::None", spec="https://drafts.csswg.org/css-backgrounds/#the-background-image", vector="True", animation_value_type="discrete", @@ -35,8 +35,8 @@ ${helpers.predefined_type( ${helpers.predefined_type( "background-position-" + axis, "position::" + direction + "Position", + "computed::LengthPercentage::zero_percent()", engines="gecko servo-2013 servo-2020", - initial_value="computed::LengthPercentage::zero()", initial_specified_value="SpecifiedValue::initial_specified_value()", spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-" + axis, animation_value_type="ComputedValue", @@ -107,7 +107,7 @@ ${helpers.single_keyword( """normal multiply screen overlay darken lighten color-dodge color-burn hard-light soft-light difference exclusion hue saturation color luminosity""", - gecko_constant_prefix="NS_STYLE_BLEND", + gecko_enum_prefix="StyleBlend", vector=True, engines="gecko", animation_value_type="discrete", diff --git a/components/style/properties/longhands/border.mako.rs b/components/style/properties/longhands/border.mako.rs index f281fa1a30d..1c4eae16939 100644 --- a/components/style/properties/longhands/border.mako.rs +++ b/components/style/properties/longhands/border.mako.rs @@ -106,10 +106,10 @@ ${helpers.single_keyword( ${helpers.predefined_type( "border-image-source", - "ImageLayer", + "Image", engines="gecko servo-2013 servo-2020", - initial_value="computed::ImageLayer::none()", - initial_specified_value="specified::ImageLayer::none()", + initial_value="computed::Image::None", + initial_specified_value="specified::Image::None", spec="https://drafts.csswg.org/css-backgrounds/#the-background-image", vector=False, animation_value_type="discrete", diff --git a/components/style/properties/longhands/box.mako.rs b/components/style/properties/longhands/box.mako.rs index 8946290918e..a4f2cc670f5 100644 --- a/components/style/properties/longhands/box.mako.rs +++ b/components/style/properties/longhands/box.mako.rs @@ -573,6 +573,7 @@ ${helpers.single_keyword( "backface-visibility", "visible hidden", engines="gecko servo-2013 servo-2020", + gecko_enum_prefix="StyleBackfaceVisibility", spec="https://drafts.csswg.org/css-transforms/#backface-visibility-property", extra_prefixes=transform_extra_prefixes, animation_value_type="discrete", @@ -633,7 +634,7 @@ ${helpers.predefined_type( "Appearance", "computed::Appearance::None", engines="gecko", - alias="-webkit-appearance:layout.css.webkit-appearance.enabled", + alias="-webkit-appearance", spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-appearance)", animation_value_type="discrete", gecko_ffi_name="mAppearance", @@ -679,10 +680,10 @@ ${helpers.predefined_type( ${helpers.predefined_type( "shape-outside", - "basic_shape::FloatAreaShape", - "generics::basic_shape::ShapeSource::None", + "basic_shape::ShapeOutside", + "generics::basic_shape::ShapeOutside::None", engines="gecko", - animation_value_type="basic_shape::FloatAreaShape", + animation_value_type="basic_shape::ShapeOutside", spec="https://drafts.csswg.org/css-shapes/#shape-outside-property", )} diff --git a/components/style/properties/longhands/effects.mako.rs b/components/style/properties/longhands/effects.mako.rs index d34f13a4a76..f9cef1a34e2 100644 --- a/components/style/properties/longhands/effects.mako.rs +++ b/components/style/properties/longhands/effects.mako.rs @@ -83,7 +83,7 @@ ${helpers.single_keyword( color-burn hard-light soft-light difference exclusion hue saturation color luminosity""", engines="gecko servo-2013 servo-2020", - gecko_constant_prefix="NS_STYLE_BLEND", + gecko_enum_prefix="StyleBlend", animation_value_type="discrete", flags="CREATES_STACKING_CONTEXT", spec="https://drafts.fxtf.org/compositing/#propdef-mix-blend-mode", diff --git a/components/style/properties/longhands/font.mako.rs b/components/style/properties/longhands/font.mako.rs index 7e0bff6fbbe..98ed7fb7f9e 100644 --- a/components/style/properties/longhands/font.mako.rs +++ b/components/style/properties/longhands/font.mako.rs @@ -230,7 +230,7 @@ ${helpers.predefined_type( ${helpers.predefined_type( "-moz-script-level", "MozScriptLevel", - 0, + "0", engines="gecko", animation_value_type="none", enabled_in="ua", diff --git a/components/style/properties/longhands/inherited_box.mako.rs b/components/style/properties/longhands/inherited_box.mako.rs index e8f3a0a45d9..fe2cc5ed024 100644 --- a/components/style/properties/longhands/inherited_box.mako.rs +++ b/components/style/properties/longhands/inherited_box.mako.rs @@ -86,6 +86,7 @@ ${helpers.single_keyword( ${helpers.single_keyword( "image-orientation", "none from-image", + gecko_pref_controlled_initial_value="layout.css.image-orientation.initial-from-image=from-image", engines="gecko", gecko_enum_prefix="StyleImageOrientation", animation_value_type="discrete", diff --git a/components/style/properties/longhands/inherited_svg.mako.rs b/components/style/properties/longhands/inherited_svg.mako.rs index 1839f90d6e6..73db38e0042 100644 --- a/components/style/properties/longhands/inherited_svg.mako.rs +++ b/components/style/properties/longhands/inherited_svg.mako.rs @@ -36,15 +36,16 @@ ${helpers.single_keyword( engines="gecko", animation_value_type="discrete", spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty", + gecko_enum_prefix="StyleColorInterpolation", )} ${helpers.single_keyword( "color-interpolation-filters", "linearrgb auto srgb", engines="gecko", - gecko_constant_prefix="NS_STYLE_COLOR_INTERPOLATION", animation_value_type="discrete", spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationFiltersProperty", + gecko_enum_prefix="StyleColorInterpolation", )} ${helpers.predefined_type( diff --git a/components/style/properties/longhands/inherited_text.mako.rs b/components/style/properties/longhands/inherited_text.mako.rs index f01bedb177e..41614a04d92 100644 --- a/components/style/properties/longhands/inherited_text.mako.rs +++ b/components/style/properties/longhands/inherited_text.mako.rs @@ -141,11 +141,12 @@ ${helpers.predefined_type( % endif </%helpers:single_keyword> -${helpers.single_keyword( +${helpers.predefined_type( "text-align-last", - "auto start end left right center justify", + "TextAlignLast", + "computed::text::TextAlignLast::Auto", + needs_context=False, engines="gecko", - gecko_constant_prefix="NS_STYLE_TEXT_ALIGN", animation_value_type="discrete", spec="https://drafts.csswg.org/css-text/#propdef-text-align-last", )} @@ -244,7 +245,7 @@ ${helpers.predefined_type( ${helpers.predefined_type( "text-emphasis-style", "TextEmphasisStyle", - None, + "computed::TextEmphasisStyle::None", engines="gecko", initial_specified_value="SpecifiedValue::None", animation_value_type="discrete", @@ -367,13 +368,12 @@ ${helpers.single_keyword( servo_restyle_damage="rebuild_and_reflow", )} -// FIXME Firefox expects the initial value of this property to change depending -// on the value of the layout.css.control-characters.visible pref. ${helpers.single_keyword( "-moz-control-character-visibility", "hidden visible", engines="gecko", - gecko_constant_prefix="NS_STYLE_CONTROL_CHARACTER_VISIBILITY", + gecko_enum_prefix="StyleControlCharacterVisibility", + gecko_pref_controlled_initial_value="layout.css.control-characters.visible=visible", animation_value_type="none", gecko_ffi_name="mControlCharacterVisibility", spec="Nonstandard", diff --git a/components/style/properties/longhands/position.mako.rs b/components/style/properties/longhands/position.mako.rs index 660da1a5a37..d9403be5864 100644 --- a/components/style/properties/longhands/position.mako.rs +++ b/components/style/properties/longhands/position.mako.rs @@ -333,7 +333,7 @@ ${helpers.single_keyword( ${helpers.predefined_type( "object-position", "Position", - "computed::Position::zero()", + "computed::Position::center()", engines="gecko", boxed=True, spec="https://drafts.csswg.org/css-images-3/#the-object-position", @@ -375,7 +375,7 @@ ${helpers.predefined_type( ${helpers.predefined_type( "grid-auto-flow", "GridAutoFlow", - "computed::GridAutoFlow::row()", + "computed::GridAutoFlow::ROW", engines="gecko", animation_value_type="discrete", spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-flow", diff --git a/components/style/properties/longhands/svg.mako.rs b/components/style/properties/longhands/svg.mako.rs index 724c38b2d1b..a09f3e7b656 100644 --- a/components/style/properties/longhands/svg.mako.rs +++ b/components/style/properties/longhands/svg.mako.rs @@ -10,6 +10,7 @@ ${helpers.single_keyword( "vector-effect", "none non-scaling-stroke", engines="gecko", + gecko_enum_prefix="StyleVectorEffect", animation_value_type="discrete", spec="https://www.w3.org/TR/SVGTiny12/painting.html#VectorEffectProperty", )} @@ -76,10 +77,10 @@ ${helpers.single_keyword( ${helpers.predefined_type( "clip-path", - "basic_shape::ClippingShape", - "generics::basic_shape::ShapeSource::None", + "basic_shape::ClipPath", + "generics::basic_shape::ClipPath::None", engines="gecko", - animation_value_type="basic_shape::ClippingShape", + animation_value_type="basic_shape::ClipPath", flags="CREATES_STACKING_CONTEXT", spec="https://drafts.fxtf.org/css-masking/#propdef-clip-path", )} @@ -110,7 +111,7 @@ ${helpers.predefined_type( ${helpers.predefined_type( "mask-position-" + axis, "position::" + direction + "Position", - "computed::LengthPercentage::zero()", + "computed::LengthPercentage::zero_percent()", engines="gecko", extra_prefixes="webkit", initial_specified_value="specified::PositionComponent::Center", @@ -164,6 +165,7 @@ ${helpers.single_keyword( "mask-composite", "add subtract intersect exclude", engines="gecko", + gecko_enum_prefix="StyleMaskComposite", vector=True, extra_prefixes="webkit", animation_value_type="discrete", @@ -172,10 +174,10 @@ ${helpers.single_keyword( ${helpers.predefined_type( "mask-image", - "ImageLayer", + "Image", engines="gecko", - initial_value="computed::ImageLayer::none()", - initial_specified_value="specified::ImageLayer::none()", + initial_value="computed::Image::None", + initial_specified_value="specified::Image::None", parse_method="parse_with_cors_anonymous", spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image", vector=True, diff --git a/components/style/properties/longhands/ui.mako.rs b/components/style/properties/longhands/ui.mako.rs index 05d22abd9e9..8aaee392662 100644 --- a/components/style/properties/longhands/ui.mako.rs +++ b/components/style/properties/longhands/ui.mako.rs @@ -56,7 +56,7 @@ ${helpers.single_keyword( ${helpers.single_keyword( "-moz-window-shadow", - "none default menu tooltip sheet", + "default none menu tooltip sheet", engines="gecko", gecko_ffi_name="mWindowShadow", gecko_enum_prefix="StyleWindowShadow", diff --git a/components/style/properties/longhands/xul.mako.rs b/components/style/properties/longhands/xul.mako.rs index d5c4011eaf6..a981f5ba795 100644 --- a/components/style/properties/longhands/xul.mako.rs +++ b/components/style/properties/longhands/xul.mako.rs @@ -64,10 +64,12 @@ ${helpers.single_keyword( spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-pack)", )} +// NOTE(heycam): Odd that the initial value is 1 yet 0 is a valid value. There +// are uses of `-moz-box-ordinal-group: 0` in the tree, too. ${helpers.predefined_type( "-moz-box-ordinal-group", "Integer", - "0", + "1", engines="gecko", parse_method="parse_non_negative", alias="-webkit-box-ordinal-group", diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index d3e61867518..4bebe0040e7 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -312,7 +312,7 @@ impl Clone for PropertyDeclaration { trait AssertCopy { fn assert() {} } trait AssertNotCopy { fn assert() {} } impl<T: Copy> AssertCopy for Helper<T> {} - % for ty in set(x["type"] for x in others): + % for ty in sorted(set(x["type"] for x in others)): impl AssertNotCopy for Helper<${ty}> {} Helper::<${ty}>::assert(); % endfor @@ -729,10 +729,10 @@ impl NonCustomPropertyIdSet { <%def name="static_non_custom_property_id_set(name, is_member)"> static ${name}: NonCustomPropertyIdSet = NonCustomPropertyIdSet { <% - storage = [0] * ((len(data.longhands) + len(data.shorthands) + len(data.all_aliases()) - 1 + 32) / 32) + storage = [0] * int((len(data.longhands) + len(data.shorthands) + len(data.all_aliases()) - 1 + 32) / 32) for i, property in enumerate(data.longhands + data.shorthands + data.all_aliases()): if is_member(property): - storage[i / 32] |= 1 << (i % 32) + storage[int(i / 32)] |= 1 << (i % 32) %> storage: [${", ".join("0x%x" % word for word in storage)}] }; @@ -741,15 +741,61 @@ static ${name}: NonCustomPropertyIdSet = NonCustomPropertyIdSet { <%def name="static_longhand_id_set(name, is_member)"> static ${name}: LonghandIdSet = LonghandIdSet { <% - storage = [0] * ((len(data.longhands) - 1 + 32) / 32) + storage = [0] * int((len(data.longhands) - 1 + 32) / 32) for i, property in enumerate(data.longhands): if is_member(property): - storage[i / 32] |= 1 << (i % 32) + storage[int(i / 32)] |= 1 << (i % 32) %> storage: [${", ".join("0x%x" % word for word in storage)}] }; </%def> +<% + logical_groups = defaultdict(list) + for prop in data.longhands: + if prop.logical_group: + logical_groups[prop.logical_group].append(prop) + + for group, props in logical_groups.items(): + logical_count = sum(1 for p in props if p.logical) + if logical_count * 2 != len(props): + raise RuntimeError("Logical group {} has ".format(group) + + "unbalanced logical / physical properties") + + FIRST_LINE_RESTRICTIONS = PropertyRestrictions.first_line(data) + FIRST_LETTER_RESTRICTIONS = PropertyRestrictions.first_letter(data) + MARKER_RESTRICTIONS = PropertyRestrictions.marker(data) + PLACEHOLDER_RESTRICTIONS = PropertyRestrictions.placeholder(data) + CUE_RESTRICTIONS = PropertyRestrictions.cue(data) + + def restriction_flags(property): + name = property.name + flags = [] + if name in FIRST_LINE_RESTRICTIONS: + flags.append("APPLIES_TO_FIRST_LINE") + if name in FIRST_LETTER_RESTRICTIONS: + flags.append("APPLIES_TO_FIRST_LETTER") + if name in PLACEHOLDER_RESTRICTIONS: + flags.append("APPLIES_TO_PLACEHOLDER") + if name in MARKER_RESTRICTIONS: + flags.append("APPLIES_TO_MARKER") + if name in CUE_RESTRICTIONS: + flags.append("APPLIES_TO_CUE") + return flags + +%> + +/// A group for properties which may override each other +/// via logical resolution. +#[derive(Clone, Copy, Eq, Hash, PartialEq)] +pub enum LogicalGroup { + % for group in sorted(logical_groups.keys()): + /// ${group} + ${to_camel_case(group)}, + % endfor +} + + /// A set of longhand properties #[derive(Clone, Copy, Debug, Default, MallocSizeOf, PartialEq)] pub struct LonghandIdSet { @@ -837,6 +883,30 @@ impl LonghandIdSet { &HAS_NO_EFFECT_ON_SCROLLBARS } + /// Returns the set of padding properties for the purpose of disabling + /// native appearance. + #[inline] + pub fn padding_properties() -> &'static Self { + <% assert "padding" in logical_groups %> + ${static_longhand_id_set( + "PADDING_PROPERTIES", + lambda p: p.logical_group == "padding" + )} + &PADDING_PROPERTIES + } + + /// Returns the set of border properties for the purpose of disabling native + /// appearance. + #[inline] + pub fn border_background_properties() -> &'static Self { + ${static_longhand_id_set( + "BORDER_BACKGROUND_PROPERTIES", + lambda p: (p.logical_group and p.logical_group.startswith("border")) or \ + p.name in ["background-color", "background-image"] + )} + &BORDER_BACKGROUND_PROPERTIES + } + /// Iterate over the current longhand id set. pub fn iter(&self) -> LonghandIdSetIterator { LonghandIdSetIterator { longhands: self, cur: 0, } @@ -998,53 +1068,8 @@ bitflags! { } } -<% - logical_groups = defaultdict(list) - for prop in data.longhands: - if prop.logical_group: - logical_groups[prop.logical_group].append(prop) - - for group, props in logical_groups.iteritems(): - logical_count = sum(1 for p in props if p.logical) - if logical_count * 2 != len(props): - raise RuntimeError("Logical group {} has ".format(group) + - "unbalanced logical / physical properties") - - FIRST_LINE_RESTRICTIONS = PropertyRestrictions.first_line(data) - FIRST_LETTER_RESTRICTIONS = PropertyRestrictions.first_letter(data) - MARKER_RESTRICTIONS = PropertyRestrictions.marker(data) - PLACEHOLDER_RESTRICTIONS = PropertyRestrictions.placeholder(data) - CUE_RESTRICTIONS = PropertyRestrictions.cue(data) - - def restriction_flags(property): - name = property.name - flags = [] - if name in FIRST_LINE_RESTRICTIONS: - flags.append("APPLIES_TO_FIRST_LINE") - if name in FIRST_LETTER_RESTRICTIONS: - flags.append("APPLIES_TO_FIRST_LETTER") - if name in PLACEHOLDER_RESTRICTIONS: - flags.append("APPLIES_TO_PLACEHOLDER") - if name in MARKER_RESTRICTIONS: - flags.append("APPLIES_TO_MARKER") - if name in CUE_RESTRICTIONS: - flags.append("APPLIES_TO_CUE") - return flags - -%> - -/// A group for properties which may override each other -/// via logical resolution. -#[derive(Clone, Copy, Eq, Hash, PartialEq)] -pub enum LogicalGroup { - % for group in logical_groups.iterkeys(): - /// ${group} - ${to_camel_case(group)}, - % endfor -} - /// An identifier for a given longhand property. -#[derive(Clone, Copy, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)] +#[derive(Clone, Copy, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] #[repr(u16)] pub enum LonghandId { % for i, property in enumerate(data.longhands): @@ -1089,6 +1114,7 @@ impl LonghandId { // could potentially do so, which would speed up serialization // algorithms and what not, I guess. <% + from functools import cmp_to_key longhand_to_shorthand_map = {} num_sub_properties = {} for shorthand in data.shorthands: @@ -1099,6 +1125,9 @@ impl LonghandId { longhand_to_shorthand_map[sub_property.ident].append(shorthand.camel_case) + def cmp(a, b): + return (a > b) - (a < b) + def preferred_order(x, y): # Since we want properties in order from most subproperties to least, # reverse the arguments to cmp from the expected order. @@ -1110,8 +1139,8 @@ impl LonghandId { # Sort the lists of shorthand properties according to preferred order: # https://drafts.csswg.org/cssom/#concept-shorthands-preferred-order - for shorthand_list in longhand_to_shorthand_map.itervalues(): - shorthand_list.sort(cmp=preferred_order) + for shorthand_list in longhand_to_shorthand_map.values(): + shorthand_list.sort(key=cmp_to_key(preferred_order)) %> // based on lookup results for each longhand, create result arrays @@ -1353,7 +1382,7 @@ where } /// An identifier for a given shorthand property. -#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)] +#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] #[repr(u16)] pub enum ShorthandId { % for i, property in enumerate(data.shorthands): @@ -1590,10 +1619,7 @@ impl UnparsedValue { } else { CSSWideKeyword::Initial }; - PropertyDeclaration::CSSWideKeyword(WideKeywordDeclaration { - id: longhand_id, - keyword, - }) + PropertyDeclaration::css_wide_keyword(longhand_id, keyword) }; let css = match crate::custom_properties::substitute( @@ -1630,10 +1656,7 @@ impl UnparsedValue { let mut input = Parser::new(&mut input); input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less. if let Ok(keyword) = input.try(CSSWideKeyword::parse) { - return PropertyDeclaration::CSSWideKeyword(WideKeywordDeclaration { - id: longhand_id, - keyword, - }); + return PropertyDeclaration::css_wide_keyword(longhand_id, keyword); } let declaration = input.parse_entirely(|input| { @@ -2239,6 +2262,12 @@ impl PropertyDeclaration { } } + /// Returns a CSS-wide keyword declaration for a given property. + #[inline] + pub fn css_wide_keyword(id: LonghandId, keyword: CSSWideKeyword) -> Self { + Self::CSSWideKeyword(WideKeywordDeclaration { id, keyword }) + } + /// Returns a CSS-wide keyword if the declaration's value is one. #[inline] pub fn get_css_wide_keyword(&self) -> Option<CSSWideKeyword> { @@ -2367,9 +2396,7 @@ impl PropertyDeclaration { PropertyId::Longhand(id) => { input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less. input.try(CSSWideKeyword::parse).map(|keyword| { - PropertyDeclaration::CSSWideKeyword( - WideKeywordDeclaration { id, keyword }, - ) + PropertyDeclaration::css_wide_keyword(id, keyword) }).or_else(|()| { input.look_for_var_or_env_functions(); input.parse_entirely(|input| id.parse_value(context, input)) @@ -2403,12 +2430,7 @@ impl PropertyDeclaration { declarations.all_shorthand = AllShorthand::CSSWideKeyword(keyword) } else { for longhand in id.longhands() { - declarations.push(PropertyDeclaration::CSSWideKeyword( - WideKeywordDeclaration { - id: longhand, - keyword, - }, - )) + declarations.push(PropertyDeclaration::css_wide_keyword(longhand, keyword)); } } } else { @@ -2550,12 +2572,7 @@ impl<'a> Iterator for AllShorthandDeclarationIterator<'a> { match *self.all_shorthand { AllShorthand::NotSet => None, AllShorthand::CSSWideKeyword(ref keyword) => { - Some(PropertyDeclaration::CSSWideKeyword( - WideKeywordDeclaration { - id: self.longhands.next()?, - keyword: *keyword - } - )) + Some(PropertyDeclaration::css_wide_keyword(self.longhands.next()?, *keyword)) } AllShorthand::WithVariables(ref unparsed) => { Some(PropertyDeclaration::WithVariables( @@ -3003,6 +3020,13 @@ impl ComputedValues { % endfor set } + + /// Create a `TransitionPropertyIterator` for this styles transition properties. + pub fn transition_properties<'a>( + &'a self + ) -> animated_properties::TransitionPropertyIterator<'a> { + animated_properties::TransitionPropertyIterator::from_style(self) + } } #[cfg(feature = "servo")] diff --git a/components/style/properties/shorthands/border.mako.rs b/components/style/properties/shorthands/border.mako.rs index 1f77b905021..e5122153db7 100644 --- a/components/style/properties/shorthands/border.mako.rs +++ b/components/style/properties/shorthands/border.mako.rs @@ -70,11 +70,10 @@ pub fn parse_border<'i, 't>( let mut width = None; let mut any = false; loop { - if color.is_none() { - if let Ok(value) = input.try(|i| Color::parse(context, i)) { - color = Some(value); + if width.is_none() { + if let Ok(value) = input.try(|i| BorderSideWidth::parse(context, i)) { + width = Some(value); any = true; - continue } } if style.is_none() { @@ -84,9 +83,9 @@ pub fn parse_border<'i, 't>( continue } } - if width.is_none() { - if let Ok(value) = input.try(|i| BorderSideWidth::parse(context, i)) { - width = Some(value); + if color.is_none() { + if let Ok(value) = input.try(|i| Color::parse(context, i)) { + color = Some(value); any = true; continue } diff --git a/components/style/properties/shorthands/position.mako.rs b/components/style/properties/shorthands/position.mako.rs index d9cb9da3342..48e56e6ef3c 100644 --- a/components/style/properties/shorthands/position.mako.rs +++ b/components/style/properties/shorthands/position.mako.rs @@ -549,7 +549,7 @@ use crate::properties::longhands::{grid_auto_columns, grid_auto_rows, grid_auto_flow}; use crate::values::generics::grid::GridTemplateComponent; use crate::values::specified::{GenericGridTemplateComponent, ImplicitGridTracks}; - use crate::values::specified::position::{AutoFlow, GridAutoFlow, GridTemplateAreas}; + use crate::values::specified::position::{GridAutoFlow, GridTemplateAreas}; pub fn parse_value<'i, 't>( context: &ParserContext, @@ -566,28 +566,28 @@ input: &mut Parser<'i, 't>, is_row: bool, ) -> Result<GridAutoFlow, ParseError<'i>> { - let mut auto_flow = None; - let mut dense = false; + let mut track = None; + let mut dense = GridAutoFlow::empty(); + for _ in 0..2 { if input.try(|i| i.expect_ident_matching("auto-flow")).is_ok() { - auto_flow = if is_row { - Some(AutoFlow::Row) + track = if is_row { + Some(GridAutoFlow::ROW) } else { - Some(AutoFlow::Column) + Some(GridAutoFlow::COLUMN) }; } else if input.try(|i| i.expect_ident_matching("dense")).is_ok() { - dense = true; + dense = GridAutoFlow::DENSE } else { break } } - auto_flow.map(|flow| { - GridAutoFlow { - autoflow: flow, - dense: dense, - } - }).ok_or(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + if track.is_some() { + Ok(track.unwrap() | dense) + } else { + Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + } } if let Ok((rows, cols, areas)) = input.try(|i| super::grid_template::parse_grid_template(context, i)) { @@ -637,7 +637,7 @@ self.grid_template_areas, dest); } - if self.grid_auto_flow.autoflow == AutoFlow::Column { + if self.grid_auto_flow.contains(GridAutoFlow::COLUMN) { // It should fail to serialize if other branch of the if condition's values are set. if !self.grid_auto_rows.is_initial() || !self.grid_template_columns.is_initial() { @@ -653,7 +653,7 @@ self.grid_template_rows.to_css(dest)?; dest.write_str(" / auto-flow")?; - if self.grid_auto_flow.dense { + if self.grid_auto_flow.contains(GridAutoFlow::DENSE) { dest.write_str(" dense")?; } @@ -676,7 +676,7 @@ } dest.write_str("auto-flow")?; - if self.grid_auto_flow.dense { + if self.grid_auto_flow.contains(GridAutoFlow::DENSE) { dest.write_str(" dense")?; } diff --git a/components/style/rule_collector.rs b/components/style/rule_collector.rs index 9841eb9e70f..1550a0368a4 100644 --- a/components/style/rule_collector.rs +++ b/components/style/rule_collector.rs @@ -55,11 +55,6 @@ pub fn containing_shadow_ignoring_svg_use<E: TElement>( } } -#[inline] -fn sort_rules_from(rules: &mut ApplicableDeclarationList, start: usize) { - rules[start..].sort_unstable_by_key(|block| (block.specificity, block.source_order())); -} - /// An object that we use with all the intermediate state needed for the /// cascade. /// @@ -82,6 +77,7 @@ where flags_setter: &'a mut F, matches_user_and_author_rules: bool, matches_document_author_rules: bool, + in_sort_scope: bool, } impl<'a, 'b: 'a, E, F: 'a> RuleCollector<'a, 'b, E, F> @@ -134,9 +130,36 @@ where rules, matches_user_and_author_rules, matches_document_author_rules: matches_user_and_author_rules, + in_sort_scope: false, } } + /// Sets up the state necessary to collect rules from a given DOM tree + /// (either the document tree, or a shadow tree). + /// + /// All rules in the same tree need to be matched together, and this + /// function takes care of sorting them by specificity and source order. + #[inline] + fn in_tree(&mut self, host: Option<E>, f: impl FnOnce(&mut Self)) { + debug_assert!(!self.in_sort_scope, "Nested sorting makes no sense"); + let start = self.rules.len(); + self.in_sort_scope = true; + let old_host = self.context.current_host.take(); + self.context.current_host = host.map(|e| e.opaque()); + f(self); + if start != self.rules.len() { + self.rules[start..] + .sort_unstable_by_key(|block| (block.specificity, block.source_order())); + } + self.context.current_host = old_host; + self.in_sort_scope = false; + } + + #[inline] + fn in_shadow_tree(&mut self, host: E, f: impl FnOnce(&mut Self)) { + self.in_tree(Some(host), f); + } + fn collect_stylist_rules(&mut self, origin: Origin) { let cascade_level = match origin { Origin::UserAgent => CascadeLevel::UANormal, @@ -150,7 +173,9 @@ where None => return, }; - self.collect_rules_internal(None, map, cascade_level); + self.in_tree(None, |collector| { + collector.collect_rules_in_map(map, cascade_level); + }); } fn collect_user_agent_rules(&mut self) { @@ -189,39 +214,30 @@ where } } - fn collect_rules_in_shadow_tree( - &mut self, - shadow_host: E, - map: &SelectorMap<Rule>, - cascade_level: CascadeLevel, - ) { - debug_assert!(shadow_host.shadow_root().is_some()); - self.collect_rules_internal(Some(shadow_host), map, cascade_level); + #[inline] + fn collect_rules_in_list(&mut self, part_rules: &[Rule], cascade_level: CascadeLevel) { + debug_assert!(self.in_sort_scope, "Rules gotta be sorted"); + SelectorMap::get_matching_rules( + self.element, + part_rules, + &mut self.rules, + &mut self.context, + &mut self.flags_setter, + cascade_level, + ); } #[inline] - fn collect_rules_internal( - &mut self, - shadow_host: Option<E>, - map: &SelectorMap<Rule>, - cascade_level: CascadeLevel, - ) { - let element = self.element; - let rule_hash_target = self.rule_hash_target; - let rules = &mut self.rules; - let flags_setter = &mut self.flags_setter; - let start = rules.len(); - self.context.with_shadow_host(shadow_host, |context| { - map.get_all_matching_rules( - element, - rule_hash_target, - rules, - context, - flags_setter, - cascade_level, - ); - }); - sort_rules_from(rules, start); + fn collect_rules_in_map(&mut self, map: &SelectorMap<Rule>, cascade_level: CascadeLevel) { + debug_assert!(self.in_sort_scope, "Rules gotta be sorted"); + map.get_all_matching_rules( + self.element, + self.rule_hash_target, + &mut self.rules, + &mut self.context, + &mut self.flags_setter, + cascade_level, + ); } /// Collects the rules for the ::slotted pseudo-element and the :host @@ -258,17 +274,16 @@ where None => continue, }; - self.collect_rules_in_shadow_tree( - shadow.host(), - slotted_rules, - CascadeLevel::AuthorNormal { + self.in_shadow_tree(shadow.host(), |collector| { + let cascade_level = CascadeLevel::AuthorNormal { shadow_cascade_order, - }, - ); + }; + collector.collect_rules_in_map(slotted_rules, cascade_level); + }); } } - fn collect_normal_rules_from_containing_shadow_tree(&mut self) { + fn collect_rules_from_containing_shadow_tree(&mut self) { if !self.matches_user_and_author_rules { return; } @@ -281,11 +296,34 @@ where self.matches_document_author_rules = false; - let cascade_data = containing_shadow.style_data(); - let host = containing_shadow.host(); - if let Some(map) = cascade_data.and_then(|data| data.normal_rules(self.pseudo_element)) { - self.collect_rules_in_shadow_tree(host, map, CascadeLevel::same_tree_author_normal()); - } + let cascade_data = match containing_shadow.style_data() { + Some(c) => c, + None => return, + }; + + let cascade_level = CascadeLevel::same_tree_author_normal(); + self.in_shadow_tree(containing_shadow.host(), |collector| { + if let Some(map) = cascade_data.normal_rules(collector.pseudo_element) { + collector.collect_rules_in_map(map, cascade_level); + } + + // Collect rules from :host::part() and such + let hash_target = collector.rule_hash_target; + if !hash_target.has_part_attr() { + return; + } + + let part_rules = match cascade_data.part_rules(collector.pseudo_element) { + Some(p) => p, + None => return, + }; + + hash_target.each_part(|part| { + if let Some(part_rules) = part_rules.get(part) { + collector.collect_rules_in_list(part_rules, cascade_level); + } + }); + }); } /// Collects the rules for the :host pseudo-class. @@ -311,13 +349,12 @@ where }; let rule_hash_target = self.rule_hash_target; - self.collect_rules_in_shadow_tree( - rule_hash_target, - host_rules, - CascadeLevel::AuthorNormal { + self.in_shadow_tree(rule_hash_target, |collector| { + let cascade_level = CascadeLevel::AuthorNormal { shadow_cascade_order, - }, - ); + }; + collector.collect_rules_in_map(host_rules, cascade_level); + }); } fn collect_document_author_rules(&mut self) { @@ -328,7 +365,7 @@ where self.collect_stylist_rules(Origin::Author); } - fn collect_part_rules(&mut self) { + fn collect_part_rules_from_outer_trees(&mut self) { if !self.rule_hash_target.has_part_attr() { return; } @@ -363,28 +400,16 @@ where if let Some(part_rules) = part_rules { let containing_host = outer_shadow.map(|s| s.host()); - let element = self.element; - let rules = &mut self.rules; - let flags_setter = &mut self.flags_setter; let cascade_level = CascadeLevel::AuthorNormal { shadow_cascade_order, }; - let start = rules.len(); - self.context.with_shadow_host(containing_host, |context| { + self.in_tree(containing_host, |collector| { for p in &parts { if let Some(part_rules) = part_rules.get(p) { - SelectorMap::get_matching_rules( - element, - &part_rules, - rules, - context, - flags_setter, - cascade_level, - ); + collector.collect_rules_in_list(part_rules, cascade_level); } } }); - sort_rules_from(rules, start); shadow_cascade_order.inc(); } @@ -393,14 +418,13 @@ where None => break, // Nowhere to export to. }; - parts.retain(|part| { - let exported_part = match inner_shadow_host.exported_part(part) { - Some(part) => part, - None => return false, - }; - std::mem::replace(part, exported_part); - true - }); + let mut new_parts = SmallVec::new(); + for part in &parts { + inner_shadow_host.each_exported_part(part, |exported_part| { + new_parts.push(exported_part.clone()); + }); + } + parts = new_parts; } } @@ -461,10 +485,10 @@ where return; } self.collect_host_and_slotted_rules(); - self.collect_normal_rules_from_containing_shadow_tree(); + self.collect_rules_from_containing_shadow_tree(); self.collect_document_author_rules(); self.collect_style_attribute(); - self.collect_part_rules(); + self.collect_part_rules_from_outer_trees(); self.collect_animation_rules(); } } diff --git a/components/style/rule_tree/mod.rs b/components/style/rule_tree/mod.rs index 113fa9cb9bb..484cdee5183 100644 --- a/components/style/rule_tree/mod.rs +++ b/components/style/rule_tree/mod.rs @@ -7,8 +7,6 @@ //! The rule tree. use crate::applicable_declarations::ApplicableDeclarationList; -#[cfg(feature = "gecko")] -use crate::gecko::selector_parser::PseudoElement; use crate::hash::{self, FxHashMap}; use crate::properties::{Importance, LonghandIdSet, PropertyDeclarationBlock}; use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards}; @@ -136,29 +134,6 @@ impl StyleSource { let _ = write!(writer, " -> {:?}", self.read(guard).declarations()); } - // This is totally unsafe, should be removed when we figure out the cause of - // bug 1607553. - #[cfg(feature = "gecko")] - unsafe fn dump_unchecked<W: Write>(&self, writer: &mut W) { - if let Some(ref rule) = self.0.as_first() { - let rule = rule.read_unchecked(); - let _ = write!(writer, "{:?}", rule.selectors); - } - let _ = write!(writer, " -> {:?}", self.read_unchecked().declarations()); - } - - // This is totally unsafe, should be removed when we figure out the cause of - // bug 1607553. - #[inline] - #[cfg(feature = "gecko")] - unsafe fn read_unchecked(&self) -> &PropertyDeclarationBlock { - let block: &Locked<PropertyDeclarationBlock> = match self.0.borrow() { - ArcUnionBorrow::First(ref rule) => &rule.get().read_unchecked().block, - ArcUnionBorrow::Second(ref block) => block.get(), - }; - block.read_unchecked() - } - /// Read the style source guard, and obtain thus read access to the /// underlying property declaration block. #[inline] @@ -1441,198 +1416,6 @@ impl StrongRuleNode { } } - /// Returns true if any properties specified by `rule_type_mask` was set by - /// an author rule. - #[cfg(feature = "gecko")] - pub fn has_author_specified_rules<E>( - &self, - mut element: E, - mut pseudo: Option<PseudoElement>, - guards: &StylesheetGuards, - rule_type_mask: u32, - author_colors_allowed: bool, - ) -> bool - where - E: crate::dom::TElement, - { - use crate::gecko_bindings::structs::NS_AUTHOR_SPECIFIED_BACKGROUND; - use crate::gecko_bindings::structs::NS_AUTHOR_SPECIFIED_BORDER; - use crate::gecko_bindings::structs::NS_AUTHOR_SPECIFIED_PADDING; - use crate::properties::{CSSWideKeyword, LonghandId}; - use crate::properties::{PropertyDeclaration, PropertyDeclarationId}; - use std::borrow::Cow; - - // Reset properties: - const BACKGROUND_PROPS: &'static [LonghandId] = - &[LonghandId::BackgroundColor, LonghandId::BackgroundImage]; - - const BORDER_PROPS: &'static [LonghandId] = &[ - LonghandId::BorderTopColor, - LonghandId::BorderTopStyle, - LonghandId::BorderTopWidth, - LonghandId::BorderRightColor, - LonghandId::BorderRightStyle, - LonghandId::BorderRightWidth, - LonghandId::BorderBottomColor, - LonghandId::BorderBottomStyle, - LonghandId::BorderBottomWidth, - LonghandId::BorderLeftColor, - LonghandId::BorderLeftStyle, - LonghandId::BorderLeftWidth, - LonghandId::BorderTopLeftRadius, - LonghandId::BorderTopRightRadius, - LonghandId::BorderBottomRightRadius, - LonghandId::BorderBottomLeftRadius, - LonghandId::BorderInlineStartColor, - LonghandId::BorderInlineStartStyle, - LonghandId::BorderInlineStartWidth, - LonghandId::BorderInlineEndColor, - LonghandId::BorderInlineEndStyle, - LonghandId::BorderInlineEndWidth, - LonghandId::BorderBlockStartColor, - LonghandId::BorderBlockStartStyle, - LonghandId::BorderBlockStartWidth, - LonghandId::BorderBlockEndColor, - LonghandId::BorderBlockEndStyle, - LonghandId::BorderBlockEndWidth, - ]; - - const PADDING_PROPS: &'static [LonghandId] = &[ - LonghandId::PaddingTop, - LonghandId::PaddingRight, - LonghandId::PaddingBottom, - LonghandId::PaddingLeft, - LonghandId::PaddingInlineStart, - LonghandId::PaddingInlineEnd, - LonghandId::PaddingBlockStart, - LonghandId::PaddingBlockEnd, - ]; - - // Set of properties that we are currently interested in. - let mut properties = LonghandIdSet::new(); - - if rule_type_mask & NS_AUTHOR_SPECIFIED_BACKGROUND != 0 { - for id in BACKGROUND_PROPS { - properties.insert(*id); - } - } - if rule_type_mask & NS_AUTHOR_SPECIFIED_BORDER != 0 { - for id in BORDER_PROPS { - properties.insert(*id); - } - } - if rule_type_mask & NS_AUTHOR_SPECIFIED_PADDING != 0 { - for id in PADDING_PROPS { - properties.insert(*id); - } - } - - // If author colors are not allowed, don't look at those properties - // (except for background-color which is special and we handle below). - if !author_colors_allowed { - properties.remove_all(LonghandIdSet::ignored_when_colors_disabled()); - if rule_type_mask & NS_AUTHOR_SPECIFIED_BACKGROUND != 0 { - properties.insert(LonghandId::BackgroundColor); - } - } - - let mut element_rule_node = Cow::Borrowed(self); - - loop { - // We need to be careful not to count styles covered up by - // user-important or UA-important declarations. But we do want to - // catch explicit inherit styling in those and check our parent - // element to see whether we have user styling for those properties. - // Note that we don't care here about inheritance due to lack of a - // specified value, since all the properties we care about are reset - // properties. - - let mut inherited_properties = LonghandIdSet::new(); - let mut have_explicit_ua_inherit = false; - - for node in element_rule_node.self_and_ancestors() { - let source = node.style_source(); - let declarations = if source.is_some() { - source - .as_ref() - .unwrap() - .read(node.cascade_level().guard(guards)) - .declaration_importance_iter() - } else { - continue; - }; - - // Iterate over declarations of the longhands we care about. - let node_importance = node.importance(); - let longhands = declarations.rev().filter_map(|(declaration, importance)| { - if importance != node_importance { - return None; - } - match declaration.id() { - PropertyDeclarationId::Longhand(id) => Some((id, declaration)), - _ => None, - } - }); - - let is_author = node.cascade_level().origin() == Origin::Author; - for (id, declaration) in longhands { - if !properties.contains(id) { - continue; - } - - if is_author { - if !author_colors_allowed { - if let PropertyDeclaration::BackgroundColor(ref color) = *declaration { - if color.is_transparent() { - return true; - } - continue; - } - } - return true; - } - - // This property was set by a non-author rule. - // Stop looking for it in this element's rule - // nodes. - properties.remove(id); - - // However, if it is inherited, then it might be - // inherited from an author rule from an - // ancestor element's rule nodes. - if declaration.get_css_wide_keyword() == Some(CSSWideKeyword::Inherit) { - have_explicit_ua_inherit = true; - inherited_properties.insert(id); - } - } - } - - if !have_explicit_ua_inherit { - break; - } - - // Continue to the parent element and search for the inherited properties. - if let Some(pseudo) = pseudo.take() { - if pseudo.inherits_from_default_values() { - break; - } - } else { - element = match element.inheritance_parent() { - Some(parent) => parent, - None => break, - }; - - let parent_data = element.mutate_data().unwrap(); - let parent_rule_node = parent_data.styles.primary().rules().clone(); - element_rule_node = Cow::Owned(parent_rule_node); - } - - properties = inherited_properties; - } - - false - } - /// Returns true if there is either animation or transition level rule. pub fn has_animation_or_transition_rules(&self) -> bool { self.self_and_ancestors() @@ -1742,47 +1525,6 @@ impl Drop for StrongRuleNode { return; } - #[cfg(feature = "gecko")] - #[inline(always)] - fn assert_on_release() -> bool { - crate::gecko_bindings::structs::GECKO_IS_NIGHTLY - } - - #[cfg(feature = "servo")] - fn assert_on_release() -> bool { - false - } - - if cfg!(debug_assertions) || assert_on_release() { - let children = node.children.read(); - if !children.is_empty() { - let mut crash_str = vec![]; - - #[cfg(feature = "gecko")] - unsafe { - // Try to unsafely collect some information of this before - // crashing the process. - if let Some(ref s) = node.source { - s.dump_unchecked(&mut crash_str); - crash_str.push(b'\n'); - } - children.each(|child| { - (*child.ptr()) - .source - .as_ref() - .unwrap() - .dump_unchecked(&mut crash_str); - crash_str.push(b'\n'); - }); - } - - panic!( - "Children left in the rule tree on drop: {}", - String::from_utf8_lossy(&crash_str).trim() - ); - } - } - if node.parent.is_none() { debug!("Dropping root node!"); // The free list should be null by this point diff --git a/components/style/servo/selector_parser.rs b/components/style/servo/selector_parser.rs index 599b603f4ff..2537cae9f83 100644 --- a/components/style/servo/selector_parser.rs +++ b/components/style/servo/selector_parser.rs @@ -709,10 +709,6 @@ impl ElementSnapshot for ServoElementSnapshot { false } - fn exported_part(&self, _: &Atom) -> Option<Atom> { - None - } - fn imported_part(&self, _: &Atom) -> Option<Atom> { None } diff --git a/components/style/style_adjuster.rs b/components/style/style_adjuster.rs index a2c6e5a2928..c2a15f7fa0e 100644 --- a/components/style/style_adjuster.rs +++ b/components/style/style_adjuster.rs @@ -227,15 +227,21 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { fn set_bits(&mut self) { let display = self.style.get_box().clone_display(); - if !display.is_contents() && - !self + if !display.is_contents() { + if !self .style .get_text() .clone_text_decoration_line() .is_empty() - { - self.style - .add_flags(ComputedValueFlags::HAS_TEXT_DECORATION_LINES); + { + self.style + .add_flags(ComputedValueFlags::HAS_TEXT_DECORATION_LINES); + } + + if self.style.get_effects().clone_opacity() == 0. { + self.style + .add_flags(ComputedValueFlags::IS_IN_OPACITY_ZERO_SUBTREE); + } } if self.style.is_pseudo_element() { @@ -488,6 +494,35 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { } } + /// <textarea>'s editor root needs to inherit the overflow value from its + /// parent, but we need to make sure it's still scrollable. + #[cfg(feature = "gecko")] + fn adjust_for_text_control_editing_root(&mut self) { + use crate::selector_parser::PseudoElement; + + if self.style.pseudo != Some(&PseudoElement::MozTextControlEditingRoot) { + return; + } + + let box_style = self.style.get_box(); + let overflow_x = box_style.clone_overflow_x(); + let overflow_y = box_style.clone_overflow_y(); + + fn scrollable(v: Overflow) -> bool { + v != Overflow::MozHiddenUnscrollable && v != Overflow::Visible + } + + // If at least one is scrollable we'll adjust the other one in + // adjust_for_overflow if needed. + if scrollable(overflow_x) || scrollable(overflow_y) { + return; + } + + let box_style = self.style.mutate_box(); + box_style.set_overflow_x(Overflow::Auto); + box_style.set_overflow_y(Overflow::Auto); + } + /// If a <fieldset> has grid/flex display type, we need to inherit /// this type into its ::-moz-fieldset-content anonymous box. /// @@ -496,9 +531,10 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { /// normal cascading process. #[cfg(feature = "gecko")] fn adjust_for_fieldset_content(&mut self, layout_parent_style: &ComputedValues) { - match self.style.pseudo { - Some(ref p) if p.is_fieldset_content() => {}, - _ => return, + use crate::selector_parser::PseudoElement; + + if self.style.pseudo != Some(&PseudoElement::FieldsetContent) { + return; } debug_assert_eq!(self.style.get_box().clone_display(), Display::Block); @@ -780,6 +816,9 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { { self.adjust_for_prohibited_display_contents(element); self.adjust_for_fieldset_content(layout_parent_style); + // NOTE: It's important that this happens before + // adjust_for_overflow. + self.adjust_for_text_control_editing_root(); } self.adjust_for_top_layer(); self.blockify_if_necessary(layout_parent_style, element); diff --git a/components/style/stylesheet_set.rs b/components/style/stylesheet_set.rs index cca08c9d233..a9cd39eef20 100644 --- a/components/style/stylesheet_set.rs +++ b/components/style/stylesheet_set.rs @@ -294,7 +294,9 @@ where // Removing sheets makes us tear down the whole cascade and invalidation // data, but only if the sheet has been involved in at least one flush. // Checking whether the sheet has been committed allows us to avoid - // rebuilding the world when sites quickly append and remove a stylesheet. + // rebuilding the world when sites quickly append and remove a + // stylesheet. + // // See bug 1434756. if sheet.committed { self.set_data_validity_at_least(DataValidity::FullyInvalid); diff --git a/components/style/stylesheets/mod.rs b/components/style/stylesheets/mod.rs index c9697ead615..daf97f20e3c 100644 --- a/components/style/stylesheets/mod.rs +++ b/components/style/stylesheets/mod.rs @@ -58,8 +58,8 @@ pub use self::rule_parser::{InsertRuleContext, State, TopLevelRuleParser}; pub use self::rules_iterator::{AllRules, EffectiveRules}; pub use self::rules_iterator::{NestedRuleIterationCondition, RulesIterator}; pub use self::style_rule::StyleRule; +pub use self::stylesheet::{AllowImportRules, SanitizationData, SanitizationKind}; pub use self::stylesheet::{DocumentStyleSheet, Namespaces, Stylesheet}; -pub use self::stylesheet::{SanitizationData, SanitizationKind}; pub use self::stylesheet::{StylesheetContents, StylesheetInDocument, UserAgentStylesheets}; pub use self::supports_rule::SupportsRule; pub use self::viewport_rule::ViewportRule; @@ -369,6 +369,7 @@ impl CssRule { shared_lock: &SharedRwLock, state: State, loader: Option<&dyn StylesheetLoader>, + allow_import_rules: AllowImportRules, ) -> Result<Self, RulesMutateError> { let url_data = parent_stylesheet_contents.url_data.read(); let context = ParserContext::new( @@ -395,6 +396,7 @@ impl CssRule { dom_error: None, namespaces: &mut *guard, insert_rule_context: Some(insert_rule_context), + allow_import_rules, }; parse_one_rule(&mut input, &mut rule_parser) diff --git a/components/style/stylesheets/rule_list.rs b/components/style/stylesheets/rule_list.rs index 05f93eca489..d84a738bca0 100644 --- a/components/style/stylesheets/rule_list.rs +++ b/components/style/stylesheets/rule_list.rs @@ -10,7 +10,7 @@ use crate::str::CssStringWriter; use crate::stylesheets::loader::StylesheetLoader; use crate::stylesheets::rule_parser::{InsertRuleContext, State}; use crate::stylesheets::stylesheet::StylesheetContents; -use crate::stylesheets::{CssRule, RulesMutateError}; +use crate::stylesheets::{AllowImportRules, CssRule, RulesMutateError}; #[cfg(feature = "gecko")] use malloc_size_of::{MallocShallowSizeOf, MallocSizeOfOps}; use servo_arc::{Arc, RawOffsetArc}; @@ -128,6 +128,7 @@ pub trait CssRulesHelpers { index: usize, nested: bool, loader: Option<&dyn StylesheetLoader>, + allow_import_rules: AllowImportRules, ) -> Result<CssRule, RulesMutateError>; } @@ -140,6 +141,7 @@ impl CssRulesHelpers for RawOffsetArc<Locked<CssRules>> { index: usize, nested: bool, loader: Option<&dyn StylesheetLoader>, + allow_import_rules: AllowImportRules, ) -> Result<CssRule, RulesMutateError> { let new_rule = { let read_guard = lock.read(); @@ -176,6 +178,7 @@ impl CssRulesHelpers for RawOffsetArc<Locked<CssRules>> { lock, state, loader, + allow_import_rules, )? }; diff --git a/components/style/stylesheets/rule_parser.rs b/components/style/stylesheets/rule_parser.rs index aefea6c504d..74425afafcd 100644 --- a/components/style/stylesheets/rule_parser.rs +++ b/components/style/stylesheets/rule_parser.rs @@ -19,6 +19,7 @@ use crate::stylesheets::keyframes_rule::parse_keyframe_list; use crate::stylesheets::stylesheet::Namespaces; use crate::stylesheets::supports_rule::SupportsCondition; use crate::stylesheets::viewport_rule; +use crate::stylesheets::AllowImportRules; use crate::stylesheets::{CorsMode, DocumentRule, FontFeatureValuesRule, KeyframesRule, MediaRule}; use crate::stylesheets::{CssRule, CssRuleType, CssRules, RulesMutateError, StylesheetLoader}; use crate::stylesheets::{NamespaceRule, PageRule, StyleRule, SupportsRule, ViewportRule}; @@ -50,7 +51,7 @@ pub struct TopLevelRuleParser<'a> { /// This won't contain any namespaces, and only nested parsers created with /// `ParserContext::new_with_rule_type` will. pub context: ParserContext<'a>, - /// The current state of the parser. + /// The current stajkj/te of the parser. pub state: State, /// Whether we have tried to parse was invalid due to being in the wrong /// place (e.g. an @import rule was found while in the `Body` state). Reset @@ -62,6 +63,8 @@ pub struct TopLevelRuleParser<'a> { pub namespaces: &'a mut Namespaces, /// The info we need insert a rule in a list. pub insert_rule_context: Option<InsertRuleContext<'a>>, + /// Whether @import rules will be allowed. + pub allow_import_rules: AllowImportRules, } impl<'b> TopLevelRuleParser<'b> { @@ -189,6 +192,10 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> { return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedImportRule)) } + if let AllowImportRules::No = self.allow_import_rules { + return Err(input.new_custom_error(StyleParseErrorKind::DisallowedImportRule)) + } + // FIXME(emilio): We should always be able to have a loader // around! See bug 1533783. if self.loader.is_none() { @@ -203,6 +210,7 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> { let media = Arc::new(self.shared_lock.wrap(media)); let prelude = AtRuleNonBlockPrelude::Import(url, media); + return Ok(AtRuleType::WithoutBlock(prelude)); }, "namespace" => { diff --git a/components/style/stylesheets/stylesheet.rs b/components/style/stylesheets/stylesheet.rs index 068bfb6502a..6679f587a41 100644 --- a/components/style/stylesheets/stylesheet.rs +++ b/components/style/stylesheets/stylesheet.rs @@ -81,6 +81,7 @@ impl StylesheetContents { quirks_mode: QuirksMode, line_number_offset: u32, use_counters: Option<&UseCounters>, + allow_import_rules: AllowImportRules, sanitization_data: Option<&mut SanitizationData>, ) -> Self { let namespaces = RwLock::new(Namespaces::default()); @@ -95,6 +96,7 @@ impl StylesheetContents { quirks_mode, line_number_offset, use_counters, + allow_import_rules, sanitization_data, ); @@ -355,6 +357,16 @@ pub enum SanitizationKind { NoConditionalRules, } +/// Whether @import rules are allowed. +#[repr(u8)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum AllowImportRules { + /// @import rules will be parsed. + Yes, + /// @import rules will not be parsed. + No, +} + impl SanitizationKind { fn allows(self, rule: &CssRule) -> bool { debug_assert_ne!(self, SanitizationKind::None); @@ -415,6 +427,7 @@ impl Stylesheet { stylesheet_loader: Option<&dyn StylesheetLoader>, error_reporter: Option<&dyn ParseErrorReporter>, line_number_offset: u32, + allow_import_rules: AllowImportRules, ) { let namespaces = RwLock::new(Namespaces::default()); @@ -430,6 +443,7 @@ impl Stylesheet { existing.contents.quirks_mode, line_number_offset, /* use_counters = */ None, + allow_import_rules, /* sanitization_data = */ None, ); @@ -457,6 +471,7 @@ impl Stylesheet { quirks_mode: QuirksMode, line_number_offset: u32, use_counters: Option<&UseCounters>, + allow_import_rules: AllowImportRules, mut sanitization_data: Option<&mut SanitizationData>, ) -> (Vec<CssRule>, Option<String>, Option<String>) { let mut rules = Vec::new(); @@ -481,6 +496,7 @@ impl Stylesheet { dom_error: None, insert_rule_context: None, namespaces, + allow_import_rules, }; { @@ -537,6 +553,7 @@ impl Stylesheet { error_reporter: Option<&dyn ParseErrorReporter>, quirks_mode: QuirksMode, line_number_offset: u32, + allow_import_rules: AllowImportRules, ) -> Self { // FIXME: Consider adding use counters to Servo? let contents = StylesheetContents::from_str( @@ -549,6 +566,7 @@ impl Stylesheet { quirks_mode, line_number_offset, /* use_counters = */ None, + allow_import_rules, /* sanitized_output = */ None, ); diff --git a/components/style/traversal.rs b/components/style/traversal.rs index a6aa220ccfa..48e42656e86 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -684,7 +684,7 @@ fn notify_paint_worklet<E>(context: &StyleContext<E>, data: &ElementData) where E: TElement, { - use crate::values::generics::image::{GenericImageLayer, Image}; + use crate::values::generics::image::Image; use style_traits::ToCss; // We speculatively evaluate any paint worklets during styling. @@ -694,9 +694,7 @@ where if let Some(ref values) = data.styles.primary { for image in &values.get_background().background_image.0 { let (name, arguments) = match *image { - GenericImageLayer::Image(Image::PaintWorklet(ref worklet)) => { - (&worklet.name, &worklet.arguments) - }, + Image::PaintWorklet(ref worklet) => (&worklet.name, &worklet.arguments), _ => continue, }; let painter = match context.shared.registered_speculative_painters.get(name) { diff --git a/components/style/values/animated/length.rs b/components/style/values/animated/length.rs deleted file mode 100644 index 04690446e64..00000000000 --- a/components/style/values/animated/length.rs +++ /dev/null @@ -1,39 +0,0 @@ -/* 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/. */ - -//! Animation implementation for various length-related types. - -use super::{Animate, Procedure}; -use crate::values::computed::length::LengthPercentage; -use crate::values::computed::Percentage; -use style_traits::values::specified::AllowedNumericType; - -/// <https://drafts.csswg.org/css-transitions/#animtype-lpcalc> -impl Animate for LengthPercentage { - #[inline] - fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> { - let animate_percentage_half = |this: Option<Percentage>, other: Option<Percentage>| { - if this.is_none() && other.is_none() { - return Ok(None); - } - let this = this.unwrap_or_default(); - let other = other.unwrap_or_default(); - Ok(Some(this.animate(&other, procedure)?)) - }; - - let length = self - .unclamped_length() - .animate(&other.unclamped_length(), procedure)?; - let percentage = - animate_percentage_half(self.specified_percentage(), other.specified_percentage())?; - - // Gets clamped as needed after the animation if needed, so no need to - // specify any particular AllowedNumericType. - Ok(LengthPercentage::new_calc( - length, - percentage, - AllowedNumericType::All, - )) - } -} diff --git a/components/style/values/animated/mod.rs b/components/style/values/animated/mod.rs index 7e699542fd4..226c01a9a49 100644 --- a/components/style/values/animated/mod.rs +++ b/components/style/values/animated/mod.rs @@ -23,7 +23,6 @@ pub mod color; pub mod effects; mod font; mod grid; -mod length; mod svg; pub mod transform; @@ -109,9 +108,6 @@ pub fn animate_multiplicative_factor( /// If a variant is annotated with `#[animation(error)]`, the corresponding /// `match` arm returns an error. /// -/// If the two values are not similar, an error is returned unless a fallback -/// function has been specified through `#[animate(fallback)]`. -/// /// Trait bounds for type parameter `Foo` can be opted out of with /// `#[animation(no_bound(Foo))]` on the type definition, trait bounds for /// fields can be opted into with `#[animation(field_bound)]` on the field. @@ -457,6 +453,16 @@ where } } +impl<T> ToAnimatedZero for Box<[T]> +where + T: ToAnimatedZero, +{ + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { + self.iter().map(|v| v.to_animated_zero()).collect() + } +} + impl<T> ToAnimatedZero for crate::OwnedSlice<T> where T: ToAnimatedZero, diff --git a/components/style/values/computed/basic_shape.rs b/components/style/values/computed/basic_shape.rs index 27a091a1115..fa30220157b 100644 --- a/components/style/values/computed/basic_shape.rs +++ b/components/style/values/computed/basic_shape.rs @@ -14,11 +14,11 @@ use crate::values::generics::basic_shape as generic; /// A computed alias for FillRule. pub use crate::values::generics::basic_shape::FillRule; -/// A computed clipping shape. -pub type ClippingShape = generic::ClippingShape<BasicShape, ComputedUrl>; +/// A computed `clip-path` value. +pub type ClipPath = generic::GenericClipPath<BasicShape, ComputedUrl>; -/// A computed float area shape. -pub type FloatAreaShape = generic::FloatAreaShape<BasicShape, Image>; +/// A computed `shape-outside` value. +pub type ShapeOutside = generic::GenericShapeOutside<BasicShape, Image>; /// A computed basic shape. pub type BasicShape = generic::GenericBasicShape< diff --git a/components/style/values/computed/font.rs b/components/style/values/computed/font.rs index 6867f582d7d..0f821123c20 100644 --- a/components/style/values/computed/font.rs +++ b/components/style/values/computed/font.rs @@ -178,7 +178,7 @@ impl ToAnimatedValue for FontSize { } } -#[derive(Clone, Debug, Eq, PartialEq, ToResolvedValue)] +#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToResolvedValue)] #[cfg_attr(feature = "servo", derive(Hash, MallocSizeOf))] /// Specifies a prioritized list of font family names or generic family names. pub struct FontFamily { @@ -227,7 +227,9 @@ impl ToCss for FontFamily { } } -#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToResolvedValue, ToShmem)] +#[derive( + Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem, +)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] /// The name of a font family of choice pub struct FamilyName { @@ -270,7 +272,9 @@ impl ToCss for FamilyName { } } -#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToResolvedValue, ToShmem)] +#[derive( + Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem, +)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] /// Font family names must either be given quoted as strings, /// or unquoted as a sequence of one or more identifiers. @@ -285,7 +289,9 @@ pub enum FontFamilyNameSyntax { Identifiers, } -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToResolvedValue, ToShmem)] +#[derive( + Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToComputedValue, ToResolvedValue, ToShmem, +)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize, Hash))] /// A set of faces that vary in weight, width or slope. pub enum SingleFontFamily { @@ -301,15 +307,28 @@ pub enum SingleFontFamily { /// `gfxPlatformFontList.h`s ranged array and `gfxFontFamilyList`'s /// sSingleGenerics are updated as well. #[derive( - Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, Parse, ToCss, ToResolvedValue, ToShmem, + Clone, + Copy, + Debug, + Eq, + Hash, + MallocSizeOf, + PartialEq, + Parse, + ToCss, + ToComputedValue, + ToResolvedValue, + ToShmem, )] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[repr(u8)] #[allow(missing_docs)] pub enum GenericFontFamily { /// No generic family specified, only for internal usage. + /// + /// NOTE(emilio): Gecko code relies on this variant being zero. #[css(skip)] - None, + None = 0, Serif, SansSerif, #[parse(aliases = "-moz-fixed")] @@ -350,19 +369,22 @@ impl SingleFontFamily { }; let mut value = first_ident.as_ref().to_owned(); + let mut serialize_quoted = value.contains(' '); // These keywords are not allowed by themselves. // The only way this value can be valid with with another keyword. if reserved { let ident = input.expect_ident()?; + serialize_quoted = serialize_quoted || ident.contains(' '); value.push(' '); value.push_str(&ident); } while let Ok(ident) = input.try(|i| i.expect_ident_cloned()) { + serialize_quoted = serialize_quoted || ident.contains(' '); value.push(' '); value.push_str(&ident); } - let syntax = if value.starts_with(' ') || value.ends_with(' ') || value.contains(" ") { + let syntax = if serialize_quoted { // For font family names which contains special white spaces, e.g. // `font-family: \ a\ \ b\ \ c\ ;`, it is tricky to serialize them // as identifiers correctly. Just mark them quoted so we don't need @@ -422,16 +444,22 @@ impl SingleFontFamily { } #[cfg(feature = "servo")] -#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToResolvedValue, ToShmem)] +#[derive( + Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem, +)] /// A list of SingleFontFamily pub struct FontFamilyList(Box<[SingleFontFamily]>); #[cfg(feature = "gecko")] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, ToComputedValue, ToResolvedValue)] /// A list of SingleFontFamily pub enum FontFamilyList { /// A strong reference to a Gecko SharedFontList object. - SharedFontList(RefPtr<structs::SharedFontList>), + SharedFontList( + #[compute(no_field_bound)] + #[resolve(no_field_bound)] + RefPtr<structs::SharedFontList>, + ), /// A font-family generic ID. Generic(GenericFontFamily), } @@ -675,7 +703,7 @@ pub type FontVariationSettings = FontSettings<VariationValue<Number>>; /// (see http://www.microsoft.com/typography/otspec/languagetags.htm). #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToResolvedValue)] #[repr(C)] -pub struct FontLanguageOverride(u32); +pub struct FontLanguageOverride(pub u32); impl FontLanguageOverride { #[inline] @@ -686,10 +714,7 @@ impl FontLanguageOverride { /// Returns this value as a `&str`, backed by `storage`. #[inline] - pub fn to_str(self, storage: &mut [u8; 4]) -> &str { - if self.0 == 0 { - return "normal"; - } + pub(crate) fn to_str(self, storage: &mut [u8; 4]) -> &str { *storage = u32::to_be_bytes(self.0); // Safe because we ensure it's ASCII during computing let slice = if cfg!(debug_assertions) { @@ -730,10 +755,22 @@ impl ToCss for FontLanguageOverride { where W: fmt::Write, { + if self.0 == 0 { + return dest.write_str("normal"); + } self.to_str(&mut [0; 4]).to_css(dest) } } +// FIXME(emilio): Make Gecko use the cbindgen'd fontLanguageOverride, then +// remove this. +#[cfg(feature = "gecko")] +impl From<u32> for FontLanguageOverride { + fn from(v: u32) -> Self { + unsafe { Self::from_u32(v) } + } +} + #[cfg(feature = "gecko")] impl From<FontLanguageOverride> for u32 { fn from(v: FontLanguageOverride) -> u32 { diff --git a/components/style/values/computed/image.rs b/components/style/values/computed/image.rs index bd59acac547..a2b59809021 100644 --- a/components/style/values/computed/image.rs +++ b/components/style/values/computed/image.rs @@ -13,7 +13,8 @@ use crate::values::computed::url::ComputedImageUrl; use crate::values::computed::NumberOrPercentage; use crate::values::computed::{Angle, Color, Context}; use crate::values::computed::{ - LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage, ToComputedValue, + AngleOrPercentage, LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage, + ToComputedValue, }; use crate::values::generics::image::{self as generic, GradientCompatMode}; use crate::values::specified::image::LineDirection as SpecifiedLineDirection; @@ -22,9 +23,6 @@ use std::f32::consts::PI; use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss}; -/// A computed image layer. -pub type ImageLayer = generic::GenericImageLayer<Image>; - /// Computed values for an image according to CSS-IMAGES. /// <https://drafts.csswg.org/css-images/#image-values> pub type Image = generic::GenericImage<Gradient, MozImageRect, ComputedImageUrl>; @@ -37,6 +35,8 @@ pub type Gradient = generic::GenericGradient< NonNegativeLength, NonNegativeLengthPercentage, Position, + Angle, + AngleOrPercentage, Color, >; @@ -57,15 +57,9 @@ pub enum LineDirection { Corner(HorizontalPositionKeyword, VerticalPositionKeyword), } -/// A computed gradient item. -pub type GradientItem = generic::GenericGradientItem<Color, LengthPercentage>; - -/// A computed color stop. -pub type ColorStop = generic::ColorStop<Color, LengthPercentage>; - /// Computed values for `-moz-image-rect(...)`. #[cfg(feature = "gecko")] -pub type MozImageRect = generic::MozImageRect<NumberOrPercentage, ComputedImageUrl>; +pub type MozImageRect = generic::GenericMozImageRect<NumberOrPercentage, ComputedImageUrl>; /// Empty enum on non-gecko #[cfg(not(feature = "gecko"))] diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index 32b0946493c..8c6dde8c738 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -17,7 +17,7 @@ use crate::values::{specified, CSSFloat}; use crate::Zero; use app_units::Au; use std::fmt::{self, Write}; -use std::ops::{Add, AddAssign, Div, Mul, Neg, Sub}; +use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub}; use style_traits::{CSSPixel, CssWriter, ToCss}; pub use super::image::Image; @@ -203,6 +203,7 @@ impl Size { Serialize, ToAnimatedValue, ToAnimatedZero, + ToComputedValue, ToResolvedValue, ToShmem, )] @@ -331,6 +332,13 @@ impl Div<CSSFloat> for CSSPixelLength { } } +impl MulAssign<CSSFloat> for CSSPixelLength { + #[inline] + fn mul_assign(&mut self, other: CSSFloat) { + self.0 *= other; + } +} + impl Mul<CSSFloat> for CSSPixelLength { type Output = Self; diff --git a/components/style/values/computed/length_percentage.rs b/components/style/values/computed/length_percentage.rs index 96bf76c98d4..1889481ad84 100644 --- a/components/style/values/computed/length_percentage.rs +++ b/components/style/values/computed/length_percentage.rs @@ -25,15 +25,16 @@ //! our expectations. use super::{Context, Length, Percentage, ToComputedValue}; -use crate::values::animated::{ToAnimatedValue, ToAnimatedZero}; +use crate::values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero}; use crate::values::distance::{ComputeSquaredDistance, SquaredDistance}; -use crate::values::generics::NonNegative; +use crate::values::generics::{calc, NonNegative}; use crate::values::specified::length::FontBaseSize; use crate::values::{specified, CSSFloat}; use crate::Zero; use app_units::Au; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use serde::{Deserialize, Serialize}; +use std::borrow::Cow; use std::fmt::{self, Write}; use style_traits::values::specified::AllowedNumericType; use style_traits::{CssWriter, ToCss}; @@ -162,13 +163,20 @@ impl MallocSizeOf for LengthPercentage { } /// An unpacked `<length-percentage>` that borrows the `calc()` variant. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, ToCss)] enum Unpacked<'a> { Calc(&'a CalcLengthPercentage), Length(Length), Percentage(Percentage), } +/// An unpacked `<length-percentage>` that mutably borrows the `calc()` variant. +enum UnpackedMut<'a> { + Calc(&'a mut CalcLengthPercentage), + Length(Length), + Percentage(Percentage), +} + /// An unpacked `<length-percentage>` that owns the `calc()` variant, for /// serialization purposes. #[derive(Deserialize, PartialEq, Serialize)] @@ -185,6 +193,22 @@ impl LengthPercentage { Self::new_length(Length::new(1.)) } + /// 0% + #[inline] + pub fn zero_percent() -> Self { + Self::new_percent(Percentage::zero()) + } + + fn to_calc_node(&self) -> Cow<CalcNode> { + match self.unpack() { + Unpacked::Length(l) => Cow::Owned(CalcNode::Leaf(CalcLengthPercentageLeaf::Length(l))), + Unpacked::Percentage(p) => { + Cow::Owned(CalcNode::Leaf(CalcLengthPercentageLeaf::Percentage(p))) + }, + Unpacked::Calc(p) => Cow::Borrowed(&p.node), + } + } + /// Constructs a length value. #[inline] pub fn new_length(length: Length) -> Self { @@ -211,25 +235,46 @@ impl LengthPercentage { percent } + /// Given a `LengthPercentage` value `v`, construct the value representing + /// `calc(100% - v)`. + pub fn hundred_percent_minus(v: Self, clamping_mode: AllowedNumericType) -> Self { + // TODO: This could in theory take ownership of the calc node in `v` if + // possible instead of cloning. + let mut node = v.to_calc_node().into_owned(); + node.negate(); + + let new_node = CalcNode::Sum( + vec![ + CalcNode::Leaf(CalcLengthPercentageLeaf::Percentage(Percentage::hundred())), + node, + ] + .into(), + ); + + Self::new_calc(new_node, clamping_mode) + } + /// Constructs a `calc()` value. #[inline] - pub fn new_calc( - length: Length, - percentage: Option<Percentage>, - clamping_mode: AllowedNumericType, - ) -> Self { - let percentage = match percentage { - Some(p) => p, - None => return Self::new_length(Length::new(clamping_mode.clamp(length.px()))), - }; - if length.is_zero() { - return Self::new_percent(Percentage(clamping_mode.clamp(percentage.0))); + pub fn new_calc(mut node: CalcNode, clamping_mode: AllowedNumericType) -> Self { + node.simplify_and_sort(); + + match node { + CalcNode::Leaf(l) => { + return match l { + CalcLengthPercentageLeaf::Length(l) => { + Self::new_length(Length::new(clamping_mode.clamp(l.px()))) + }, + CalcLengthPercentageLeaf::Percentage(p) => { + Self::new_percent(Percentage(clamping_mode.clamp(p.0))) + }, + } + }, + _ => Self::new_calc_unchecked(Box::new(CalcLengthPercentage { + clamping_mode, + node, + })), } - Self::new_calc_unchecked(Box::new(CalcLengthPercentage { - length, - percentage, - clamping_mode, - })) } /// Private version of new_calc() that constructs a calc() variant without @@ -262,7 +307,18 @@ impl LengthPercentage { LengthPercentageUnion::TAG_CALC => Tag::Calc, LengthPercentageUnion::TAG_LENGTH => Tag::Length, LengthPercentageUnion::TAG_PERCENTAGE => Tag::Percentage, - _ => unreachable!("Bogus tag?"), + _ => unsafe { debug_unreachable!("Bogus tag?") }, + } + } + + #[inline] + fn unpack_mut<'a>(&'a mut self) -> UnpackedMut<'a> { + unsafe { + match self.tag() { + Tag::Calc => UnpackedMut::Calc(&mut *self.calc_ptr()), + Tag::Length => UnpackedMut::Length(self.0.length.length), + Tag::Percentage => UnpackedMut::Percentage(self.0.percentage.percentage), + } } } @@ -313,57 +369,7 @@ impl LengthPercentage { match self.unpack() { Unpacked::Length(l) => l.px() == 0.0, Unpacked::Percentage(p) => p.0 == 0.0, - Unpacked::Calc(ref c) => { - debug_assert_ne!( - c.length.px(), - 0.0, - "Should've been simplified to a percentage" - ); - false - }, - } - } - - /// Returns the `<length>` component of this `calc()`, unclamped. - #[inline] - pub fn unclamped_length(&self) -> Length { - match self.unpack() { - Unpacked::Length(l) => l, - Unpacked::Percentage(..) => Zero::zero(), - Unpacked::Calc(c) => c.unclamped_length(), - } - } - - /// Returns this `calc()` as a `<length>`. - /// - /// Panics in debug mode if a percentage is present in the expression. - #[inline] - fn length(&self) -> Length { - debug_assert!(!self.has_percentage()); - self.length_component() - } - - /// Returns the `<length>` component of this `calc()`, clamped. - #[inline] - pub fn length_component(&self) -> Length { - match self.unpack() { - Unpacked::Length(l) => l, - Unpacked::Percentage(..) => Zero::zero(), - Unpacked::Calc(c) => c.length_component(), - } - } - - /// Returns the `<percentage>` component of this `calc()`, unclamped, as a - /// float. - /// - /// FIXME: This are very different semantics from length(), we should - /// probably rename this. - #[inline] - pub fn percentage(&self) -> CSSFloat { - match self.unpack() { - Unpacked::Length(..) => 0., - Unpacked::Percentage(p) => p.0, - Unpacked::Calc(c) => c.percentage.0, + Unpacked::Calc(..) => false, } } @@ -407,25 +413,8 @@ impl LengthPercentage { #[inline] pub fn to_percentage(&self) -> Option<Percentage> { match self.unpack() { - Unpacked::Length(..) => None, Unpacked::Percentage(p) => Some(p), - Unpacked::Calc(ref c) => { - debug_assert!(!c.length.is_zero()); - None - }, - } - } - - /// Return the specified percentage if any. - #[inline] - pub fn specified_percentage(&self) -> Option<Percentage> { - match self.unpack() { - Unpacked::Length(..) => None, - Unpacked::Percentage(p) => Some(p), - Unpacked::Calc(ref c) => { - debug_assert!(self.has_percentage()); - Some(c.percentage) - }, + Unpacked::Length(..) | Unpacked::Calc(..) => None, } } @@ -452,19 +441,22 @@ impl LengthPercentage { /// the height property), they apply whenever a calc() expression contains /// percentages. pub fn maybe_percentage_relative_to(&self, container_len: Option<Length>) -> Option<Length> { - if self.has_percentage() { - return Some(self.resolve(container_len?)); + if let Unpacked::Length(l) = self.unpack() { + return Some(l); } - Some(self.length()) + Some(self.resolve(container_len?)) } /// Returns the clamped non-negative values. #[inline] - pub fn clamp_to_non_negative(&self) -> Self { - match self.unpack() { - Unpacked::Length(l) => Self::new_length(l.clamp_to_non_negative()), - Unpacked::Percentage(p) => Self::new_percent(p.clamp_to_non_negative()), - Unpacked::Calc(c) => c.clamp_to_non_negative(), + pub fn clamp_to_non_negative(mut self) -> Self { + match self.unpack_mut() { + UnpackedMut::Length(l) => Self::new_length(l.clamp_to_non_negative()), + UnpackedMut::Percentage(p) => Self::new_percent(p.clamp_to_non_negative()), + UnpackedMut::Calc(ref mut c) => { + c.clamping_mode = AllowedNumericType::NonNegative; + self + }, } } } @@ -549,7 +541,7 @@ impl ToCss for LengthPercentage { where W: Write, { - specified::LengthPercentage::from_computed_value(self).to_css(dest) + self.unpack().to_css(dest) } } @@ -584,46 +576,138 @@ impl<'de> Deserialize<'de> for LengthPercentage { } } -/// The representation of a calc() function with mixed lengths and percentages. -#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize, ToAnimatedZero, ToResolvedValue)] -#[repr(C)] -pub struct CalcLengthPercentage { - length: Length, +/// The leaves of a `<length-percentage>` calc expression. +#[derive( + Clone, + Debug, + Deserialize, + MallocSizeOf, + PartialEq, + Serialize, + ToAnimatedZero, + ToCss, + ToResolvedValue, +)] +#[allow(missing_docs)] +#[repr(u8)] +pub enum CalcLengthPercentageLeaf { + Length(Length), + Percentage(Percentage), +} - percentage: Percentage, +impl CalcLengthPercentageLeaf { + fn is_zero_length(&self) -> bool { + match *self { + Self::Length(ref l) => l.is_zero(), + Self::Percentage(..) => false, + } + } +} - #[animation(constant)] - clamping_mode: AllowedNumericType, +impl PartialOrd for CalcLengthPercentageLeaf { + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { + use self::CalcLengthPercentageLeaf::*; + + if std::mem::discriminant(self) != std::mem::discriminant(other) { + return None; + } + + match (self, other) { + (&Length(ref one), &Length(ref other)) => one.partial_cmp(other), + (&Percentage(ref one), &Percentage(ref other)) => one.partial_cmp(other), + _ => { + match *self { + Length(..) | Percentage(..) => {}, + } + unsafe { + debug_unreachable!("Forgot a branch?"); + } + }, + } + } } -impl CalcLengthPercentage { - /// Returns the length component of this `calc()`, clamped. - #[inline] - fn length_component(&self) -> Length { - Length::new(self.clamping_mode.clamp(self.length.px())) +impl calc::CalcNodeLeaf for CalcLengthPercentageLeaf { + fn is_negative(&self) -> bool { + match *self { + Self::Length(ref l) => l.px() < 0., + Self::Percentage(ref p) => p.0 < 0., + } } - /// Resolves the percentage. - #[inline] - pub fn resolve(&self, basis: Length) -> Length { - let length = self.length.px() + basis.px() * self.percentage.0; - Length::new(self.clamping_mode.clamp(length)) + fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()> { + use self::CalcLengthPercentageLeaf::*; + + // 0px plus anything else is equal to the right hand side. + if self.is_zero_length() { + *self = other.clone(); + return Ok(()); + } + + if other.is_zero_length() { + return Ok(()); + } + + match (self, other) { + (&mut Length(ref mut one), &Length(ref other)) => { + *one += *other; + }, + (&mut Percentage(ref mut one), &Percentage(ref other)) => { + one.0 += other.0; + }, + _ => return Err(()), + } + + Ok(()) } - /// Returns the length, without clamping. - #[inline] - fn unclamped_length(&self) -> Length { - self.length + fn mul_by(&mut self, scalar: f32) { + match *self { + Self::Length(ref mut l) => *l = *l * scalar, + Self::Percentage(ref mut p) => p.0 *= scalar, + } } - /// Returns the clamped non-negative values. + fn simplify(&mut self) {} + + fn sort_key(&self) -> calc::SortKey { + match *self { + Self::Length(..) => calc::SortKey::Px, + Self::Percentage(..) => calc::SortKey::Percentage, + } + } +} + +/// The computed version of a calc() node for `<length-percentage>` values. +pub type CalcNode = calc::GenericCalcNode<CalcLengthPercentageLeaf>; + +/// The representation of a calc() function with mixed lengths and percentages. +#[derive( + Clone, Debug, Deserialize, MallocSizeOf, Serialize, ToAnimatedZero, ToResolvedValue, ToCss, +)] +#[repr(C)] +pub struct CalcLengthPercentage { + #[animation(constant)] + #[css(skip)] + clamping_mode: AllowedNumericType, + node: CalcNode, +} + +impl CalcLengthPercentage { + /// Resolves the percentage. #[inline] - fn clamp_to_non_negative(&self) -> LengthPercentage { - LengthPercentage::new_calc( - self.length, - Some(self.percentage), - AllowedNumericType::NonNegative, - ) + fn resolve(&self, basis: Length) -> Length { + // unwrap() is fine because the conversion below is infallible. + let px = self + .node + .resolve(|l| { + Ok(match *l { + CalcLengthPercentageLeaf::Length(l) => l.px(), + CalcLengthPercentageLeaf::Percentage(ref p) => basis.px() * p.0, + }) + }) + .unwrap(); + Length::new(self.clamping_mode.clamp(px)) } } @@ -641,7 +725,7 @@ impl CalcLengthPercentage { // maybe. impl PartialEq for CalcLengthPercentage { fn eq(&self, other: &Self) -> bool { - self.length == other.length && self.percentage == other.percentage + self.node == other.node } } @@ -656,43 +740,22 @@ impl specified::CalcLengthPercentage { where F: Fn(Length) -> Length, { - use crate::values::specified::length::{FontRelativeLength, ViewportPercentageLength}; - use std::f32; - - let mut length = 0.; - - if let Some(absolute) = self.absolute { - length += zoom_fn(absolute.to_computed_value(context)).px(); - } - - for val in &[ - self.vw.map(ViewportPercentageLength::Vw), - self.vh.map(ViewportPercentageLength::Vh), - self.vmin.map(ViewportPercentageLength::Vmin), - self.vmax.map(ViewportPercentageLength::Vmax), - ] { - if let Some(val) = *val { - let viewport_size = context.viewport_size_for_viewport_unit_resolution(); - length += val.to_computed_value(viewport_size).px(); - } - } - - for val in &[ - self.ch.map(FontRelativeLength::Ch), - self.em.map(FontRelativeLength::Em), - self.ex.map(FontRelativeLength::Ex), - self.rem.map(FontRelativeLength::Rem), - ] { - if let Some(val) = *val { - length += val.to_computed_value(context, base_size).px(); - } - } + use crate::values::specified::calc::Leaf; + use crate::values::specified::length::NoCalcLength; + + let node = self.node.map_leaves(|leaf| match *leaf { + Leaf::Percentage(p) => CalcLengthPercentageLeaf::Percentage(Percentage(p)), + Leaf::Length(l) => CalcLengthPercentageLeaf::Length(match l { + NoCalcLength::Absolute(ref abs) => zoom_fn(abs.to_computed_value(context)), + NoCalcLength::FontRelative(ref fr) => fr.to_computed_value(context, base_size), + other => other.to_computed_value(context), + }), + Leaf::Number(..) | Leaf::Angle(..) | Leaf::Time(..) => { + unreachable!("Shouldn't have parsed") + }, + }); - LengthPercentage::new_calc( - Length::new(length.min(f32::MAX).max(f32::MIN)), - self.percentage, - self.clamping_mode, - ) + LengthPercentage::new_calc(node, self.clamping_mode) } /// Compute font-size or line-height taking into account text-zoom if necessary. @@ -711,25 +774,14 @@ impl specified::CalcLengthPercentage { /// Compute the value into pixel length as CSSFloat without context, /// so it returns Err(()) if there is any non-absolute unit. pub fn to_computed_pixel_length_without_context(&self) -> Result<CSSFloat, ()> { - if self.vw.is_some() || - self.vh.is_some() || - self.vmin.is_some() || - self.vmax.is_some() || - self.em.is_some() || - self.ex.is_some() || - self.ch.is_some() || - self.rem.is_some() || - self.percentage.is_some() - { - return Err(()); - } - - match self.absolute { - Some(abs) => Ok(abs.to_px()), - None => { - debug_assert!(false, "Someone forgot to handle an unit here: {:?}", self); - Err(()) - }, + use crate::values::specified::calc::Leaf; + use crate::values::specified::length::NoCalcLength; + + // Simplification should've turned this into an absolute length, + // otherwise it wouldn't have been able to. + match self.node { + calc::CalcNode::Leaf(Leaf::Length(NoCalcLength::Absolute(ref l))) => Ok(l.to_px()), + _ => Err(()), } } @@ -740,17 +792,51 @@ impl specified::CalcLengthPercentage { #[inline] fn from_computed_value(computed: &CalcLengthPercentage) -> Self { - use crate::values::specified::length::AbsoluteLength; + use crate::values::specified::calc::Leaf; + use crate::values::specified::length::NoCalcLength; specified::CalcLengthPercentage { clamping_mode: computed.clamping_mode, - absolute: Some(AbsoluteLength::from_computed_value(&computed.length)), - percentage: Some(computed.percentage), - ..Default::default() + node: computed.node.map_leaves(|l| match l { + CalcLengthPercentageLeaf::Length(ref l) => { + Leaf::Length(NoCalcLength::from_px(l.px())) + }, + CalcLengthPercentageLeaf::Percentage(ref p) => Leaf::Percentage(p.0), + }), } } } +/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc +/// https://drafts.csswg.org/css-values-4/#combine-math +/// https://drafts.csswg.org/css-values-4/#combine-mixed +impl Animate for LengthPercentage { + #[inline] + fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> { + Ok(match (self.unpack(), other.unpack()) { + (Unpacked::Length(one), Unpacked::Length(other)) => { + Self::new_length(one.animate(&other, procedure)?) + }, + (Unpacked::Percentage(one), Unpacked::Percentage(other)) => { + Self::new_percent(one.animate(&other, procedure)?) + }, + _ => { + let mut one = self.to_calc_node().into_owned(); + let mut other = other.to_calc_node().into_owned(); + let (l, r) = procedure.weights(); + + one.mul_by(l as f32); + other.mul_by(r as f32); + + Self::new_calc( + CalcNode::Sum(vec![one, other].into()), + AllowedNumericType::All, + ) + }, + }) + } +} + /// A wrapper of LengthPercentage, whose value must be >= 0. pub type NonNegativeLengthPercentage = NonNegative<LengthPercentage>; diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 7cfd1e20abe..841cc3df22a 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -21,10 +21,9 @@ use crate::media_queries::Device; use crate::properties; use crate::properties::{ComputedValues, LonghandId, StyleBuilder}; use crate::rule_cache::RuleCacheConditions; -use crate::Atom; -#[cfg(feature = "servo")] -use crate::Prefix; +use crate::{ArcSlice, Atom}; use euclid::default::Size2D; +use servo_arc::Arc; use std::cell::RefCell; use std::cmp; use std::f32; @@ -57,7 +56,7 @@ pub use self::font::{FontSize, FontSizeAdjust, FontStretch, FontSynthesis}; pub use self::font::{FontVariantAlternates, FontWeight}; pub use self::font::{FontVariantEastAsian, FontVariationSettings}; pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom}; -pub use self::image::{Gradient, GradientItem, Image, ImageLayer, LineDirection, MozImageRect}; +pub use self::image::{Gradient, Image, LineDirection, MozImageRect}; pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength}; pub use self::length::{Length, LengthOrNumber, LengthPercentage, NonNegativeLengthOrNumber}; pub use self::length::{LengthOrAuto, LengthPercentageOrAuto, MaxSize, Size}; @@ -78,7 +77,7 @@ pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; pub use self::text::TextUnderlinePosition; pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight}; pub use self::text::{OverflowWrap, TextOverflow, WordBreak, WordSpacing}; -pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle}; +pub use self::text::{TextAlign, TextAlignLast, TextEmphasisPosition, TextEmphasisStyle}; pub use self::text::{TextDecorationLength, TextDecorationSkipInk}; pub use self::time::Time; pub use self::transform::{Rotate, Scale, Transform, TransformOperation}; @@ -450,6 +449,46 @@ where } } +// NOTE(emilio): This is implementable more generically, but it's unlikely +// what you want there, as it forces you to have an extra allocation. +// +// We could do that if needed, ideally with specialization for the case where +// ComputedValue = T. But we don't need it for now. +impl<T> ToComputedValue for Arc<T> +where + T: ToComputedValue<ComputedValue = T>, +{ + type ComputedValue = Self; + + #[inline] + fn to_computed_value(&self, _: &Context) -> Self { + self.clone() + } + + #[inline] + fn from_computed_value(computed: &Self) -> Self { + computed.clone() + } +} + +// Same caveat as above applies. +impl<T> ToComputedValue for ArcSlice<T> +where + T: ToComputedValue<ComputedValue = T>, +{ + type ComputedValue = Self; + + #[inline] + fn to_computed_value(&self, _: &Context) -> Self { + self.clone() + } + + #[inline] + fn from_computed_value(computed: &Self) -> Self { + computed.clone() + } +} + trivial_to_computed_value!(()); trivial_to_computed_value!(bool); trivial_to_computed_value!(f32); @@ -460,10 +499,13 @@ trivial_to_computed_value!(u32); trivial_to_computed_value!(usize); trivial_to_computed_value!(Atom); #[cfg(feature = "servo")] -trivial_to_computed_value!(Prefix); +trivial_to_computed_value!(html5ever::Namespace); +#[cfg(feature = "servo")] +trivial_to_computed_value!(html5ever::Prefix); trivial_to_computed_value!(String); trivial_to_computed_value!(Box<str>); trivial_to_computed_value!(crate::OwnedStr); +trivial_to_computed_value!(style_traits::values::specified::AllowedNumericType); #[allow(missing_docs)] #[derive( diff --git a/components/style/values/computed/position.rs b/components/style/values/computed/position.rs index 7b22c37f73f..3eff231de88 100644 --- a/components/style/values/computed/position.rs +++ b/components/style/values/computed/position.rs @@ -9,6 +9,7 @@ use crate::values::computed::{Integer, LengthPercentage, Percentage}; use crate::values::generics::position::Position as GenericPosition; +use crate::values::generics::position::PositionComponent as GenericPositionComponent; use crate::values::generics::position::PositionOrAuto as GenericPositionOrAuto; use crate::values::generics::position::ZIndex as GenericZIndex; pub use crate::values::specified::position::{GridAutoFlow, GridTemplateAreas}; @@ -56,5 +57,14 @@ impl ToCss for Position { } } +impl GenericPositionComponent for LengthPercentage { + fn is_center(&self) -> bool { + match self.to_percentage() { + Some(Percentage(per)) => per == 0.5, + _ => false, + } + } +} + /// A computed value for the `z-index` property. pub type ZIndex = GenericZIndex<Integer>; diff --git a/components/style/values/computed/svg.rs b/components/style/values/computed/svg.rs index 54648572f86..a348d071ab9 100644 --- a/components/style/values/computed/svg.rs +++ b/components/style/values/computed/svg.rs @@ -31,7 +31,7 @@ impl SVGPaint { } /// <length> | <percentage> | <number> | context-value -pub type SVGLength = generic::SVGLength<LengthPercentage>; +pub type SVGLength = generic::GenericSVGLength<LengthPercentage>; impl SVGLength { /// `0px` @@ -41,7 +41,7 @@ impl SVGLength { } /// An non-negative wrapper of SVGLength. -pub type SVGWidth = generic::SVGLength<NonNegativeLengthPercentage>; +pub type SVGWidth = generic::GenericSVGLength<NonNegativeLengthPercentage>; impl SVGWidth { /// `1px`. diff --git a/components/style/values/computed/text.rs b/components/style/values/computed/text.rs index 0ca2e6044ed..b77695e06c0 100644 --- a/components/style/values/computed/text.rs +++ b/components/style/values/computed/text.rs @@ -18,8 +18,7 @@ use crate::Zero; use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss}; -pub use crate::values::specified::TextAlignKeyword as TextAlign; -pub use crate::values::specified::TextUnderlinePosition; +pub use crate::values::specified::text::{TextAlignLast, TextUnderlinePosition}; pub use crate::values::specified::{LineBreak, OverflowWrap, WordBreak}; pub use crate::values::specified::{TextDecorationLine, TextEmphasisPosition}; pub use crate::values::specified::{TextDecorationSkipInk, TextTransform}; @@ -30,6 +29,9 @@ pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>; /// Implements type for `text-decoration-thickness` property. pub type TextDecorationLength = GenericTextDecorationLength<LengthPercentage>; +/// The computed value of `text-align`. +pub type TextAlign = specified::TextAlignKeyword; + /// A computed value for the `letter-spacing` property. #[repr(transparent)] #[derive( diff --git a/components/style/values/computed/ui.rs b/components/style/values/computed/ui.rs index 21914995951..ae12dfcdae0 100644 --- a/components/style/values/computed/ui.rs +++ b/components/style/values/computed/ui.rs @@ -13,10 +13,10 @@ pub use crate::values::specified::ui::CursorKind; pub use crate::values::specified::ui::{MozForceBrokenImageIcon, UserSelect}; /// A computed value for the `cursor` property. -pub type Cursor = generics::Cursor<CursorImage>; +pub type Cursor = generics::GenericCursor<CursorImage>; /// A computed value for item of `image cursors`. -pub type CursorImage = generics::CursorImage<ComputedImageUrl, Number>; +pub type CursorImage = generics::GenericCursorImage<ComputedImageUrl, Number>; /// A computed value for `scrollbar-color` property. pub type ScrollbarColor = generics::GenericScrollbarColor<Color>; diff --git a/components/style/values/distance.rs b/components/style/values/distance.rs index 67c735676b5..a4259ce8c6b 100644 --- a/components/style/values/distance.rs +++ b/components/style/values/distance.rs @@ -19,9 +19,6 @@ use std::ops::Add; /// If a variant is annotated with `#[animation(error)]`, the corresponding /// `match` arm returns an error. /// -/// If the two values are not similar, an error is returned unless a fallback -/// function has been specified through `#[distance(fallback)]`. -/// /// Trait bounds for type parameter `Foo` can be opted out of with /// `#[animation(no_bound(Foo))]` on the type definition, trait bounds for /// fields can be opted into with `#[distance(field_bound)]` on the field. @@ -81,6 +78,16 @@ impl ComputeSquaredDistance for Au { } } +impl<T> ComputeSquaredDistance for Box<T> +where + T: ComputeSquaredDistance, +{ + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { + (**self).compute_squared_distance(&**other) + } +} + impl<T> ComputeSquaredDistance for Option<T> where T: ComputeSquaredDistance, diff --git a/components/style/values/generics/basic_shape.rs b/components/style/values/generics/basic_shape.rs index d91fa58eb0d..745d6e07bbf 100644 --- a/components/style/values/generics/basic_shape.rs +++ b/components/style/values/generics/basic_shape.rs @@ -15,18 +15,17 @@ use crate::Zero; use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss}; -/// A clipping shape, for `clip-path`. -pub type ClippingShape<BasicShape, Url> = ShapeSource<BasicShape, GeometryBox, Url>; - /// <https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box> #[allow(missing_docs)] #[derive( Animate, Clone, + ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, + Parse, SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, @@ -34,15 +33,27 @@ pub type ClippingShape<BasicShape, Url> = ShapeSource<BasicShape, GeometryBox, U ToResolvedValue, ToShmem, )] -pub enum GeometryBox { +#[repr(u8)] +pub enum ShapeGeometryBox { + /// Depending on which kind of element this style value applied on, the + /// default value of the reference-box can be different. For an HTML + /// element, the default value of reference-box is border-box; for an SVG + /// element, the default value is fill-box. Since we can not determine the + /// default value at parsing time, we keep this value to make a decision on + /// it. + #[css(skip)] + ElementDependent, FillBox, StrokeBox, ViewBox, ShapeBox(ShapeBox), } -/// A float area shape, for `shape-outside`. -pub type FloatAreaShape<BasicShape, Image> = ShapeSource<BasicShape, ShapeBox, Image>; +impl Default for ShapeGeometryBox { + fn default() -> Self { + Self::ElementDependent + } +} /// https://drafts.csswg.org/css-shapes-1/#typedef-shape-box #[allow(missing_docs)] @@ -51,6 +62,7 @@ pub type FloatAreaShape<BasicShape, Image> = ShapeSource<BasicShape, ShapeBox, I Animate, Clone, Copy, + ComputeSquaredDistance, Debug, Eq, MallocSizeOf, @@ -63,6 +75,7 @@ pub type FloatAreaShape<BasicShape, Image> = ShapeSource<BasicShape, ShapeBox, I ToResolvedValue, ToShmem, )] +#[repr(u8)] pub enum ShapeBox { MarginBox, BorderBox, @@ -70,12 +83,19 @@ pub enum ShapeBox { ContentBox, } -/// A shape source, for some reference box. +impl Default for ShapeBox { + fn default() -> Self { + ShapeBox::MarginBox + } +} + +/// A value for the `clip-path` property. #[allow(missing_docs)] -#[animation(no_bound(ImageOrUrl))] +#[animation(no_bound(U))] #[derive( Animate, Clone, + ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, @@ -86,18 +106,54 @@ pub enum ShapeBox { ToResolvedValue, ToShmem, )] -pub enum ShapeSource<BasicShape, ReferenceBox, ImageOrUrl> { +#[repr(u8)] +pub enum GenericClipPath<BasicShape, U> { #[animation(error)] - ImageOrUrl(ImageOrUrl), - Shape(Box<BasicShape>, Option<ReferenceBox>), + None, #[animation(error)] - Box(ReferenceBox), + Url(U), #[css(function)] Path(Path), + Shape( + Box<BasicShape>, + #[css(skip_if = "is_default")] ShapeGeometryBox, + ), + #[animation(error)] + Box(ShapeGeometryBox), +} + +pub use self::GenericClipPath as ClipPath; + +/// A value for the `shape-outside` property. +#[allow(missing_docs)] +#[animation(no_bound(I))] +#[derive( + Animate, + Clone, + ComputeSquaredDistance, + Debug, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToAnimatedValue, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] +#[repr(u8)] +pub enum GenericShapeOutside<BasicShape, I> { #[animation(error)] None, + #[animation(error)] + Image(I), + Shape(Box<BasicShape>, #[css(skip_if = "is_default")] ShapeBox), + #[animation(error)] + Box(ShapeBox), } +pub use self::GenericShapeOutside as ShapeOutside; + #[allow(missing_docs)] #[derive( Animate, @@ -252,7 +308,7 @@ pub use self::GenericShapeRadius as ShapeRadius; #[repr(C)] pub struct GenericPolygon<LengthPercentage> { /// The filling rule for a polygon. - #[css(skip_if = "fill_is_default")] + #[css(skip_if = "is_default")] pub fill: FillRule, /// A collection of (x, y) coordinates to draw the polygon. #[css(iterable)] @@ -311,6 +367,7 @@ pub enum FillRule { #[derive( Animate, Clone, + ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, @@ -321,39 +378,23 @@ pub enum FillRule { ToResolvedValue, ToShmem, )] +#[repr(C)] pub struct Path { /// The filling rule for the svg path. - #[css(skip_if = "fill_is_default")] + #[css(skip_if = "is_default")] #[animation(constant)] pub fill: FillRule, /// The svg path data. pub path: SVGPathData, } -// FIXME(nox): Implement ComputeSquaredDistance for T types and stop -// using PartialEq here, this will let us derive this impl. -impl<B, T, U> ComputeSquaredDistance for ShapeSource<B, T, U> -where - B: ComputeSquaredDistance, - T: PartialEq, -{ - fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { - match (self, other) { - ( - &ShapeSource::Shape(ref this, ref this_box), - &ShapeSource::Shape(ref other, ref other_box), - ) if this_box == other_box => this.compute_squared_distance(other), - (&ShapeSource::Path(ref this), &ShapeSource::Path(ref other)) - if this.fill == other.fill => - { - this.path.compute_squared_distance(&other.path) - }, - _ => Err(()), - } +impl<B, U> ToAnimatedZero for ClipPath<B, U> { + fn to_animated_zero(&self) -> Result<Self, ()> { + Err(()) } } -impl<B, T, U> ToAnimatedZero for ShapeSource<B, T, U> { +impl<B, U> ToAnimatedZero for ShapeOutside<B, U> { fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } @@ -488,6 +529,6 @@ impl Default for FillRule { } #[inline] -fn fill_is_default(fill: &FillRule) -> bool { - *fill == FillRule::default() +fn is_default<T: Default + PartialEq>(fill: &T) -> bool { + *fill == Default::default() } diff --git a/components/style/values/generics/calc.rs b/components/style/values/generics/calc.rs new file mode 100644 index 00000000000..074dd97f4d0 --- /dev/null +++ b/components/style/values/generics/calc.rs @@ -0,0 +1,573 @@ +/* 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/. */ + +//! [Calc expressions][calc]. +//! +//! [calc]: https://drafts.csswg.org/css-values/#calc-notation + +use crate::Zero; +use smallvec::SmallVec; +use std::fmt::{self, Write}; +use std::ops::Add; +use std::{cmp, mem}; +use style_traits::{CssWriter, ToCss}; + +/// Whether we're a `min` or `max` function. +#[derive( + Clone, + Copy, + Debug, + Deserialize, + MallocSizeOf, + PartialEq, + Serialize, + ToAnimatedZero, + ToResolvedValue, + ToShmem, +)] +#[repr(u8)] +pub enum MinMaxOp { + /// `min()` + Min, + /// `max()` + Max, +} + +/// This determines the order in which we serialize members of a calc() sum. +/// +/// See https://drafts.csswg.org/css-values-4/#sort-a-calculations-children +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[allow(missing_docs)] +pub enum SortKey { + Number, + Percentage, + Ch, + Deg, + Em, + Ex, + Px, + Rem, + Sec, + Vh, + Vmax, + Vmin, + Vw, + Other, +} + +/// A generic node in a calc expression. +/// +/// FIXME: This would be much more elegant if we used `Self` in the types below, +/// but we can't because of https://github.com/serde-rs/serde/issues/1565. +#[repr(u8)] +#[derive( + Clone, + Debug, + Deserialize, + MallocSizeOf, + PartialEq, + Serialize, + ToAnimatedZero, + ToResolvedValue, + ToShmem, +)] +pub enum GenericCalcNode<L> { + /// A leaf node. + Leaf(L), + /// A sum node, representing `a + b + c` where a, b, and c are the + /// arguments. + Sum(crate::OwnedSlice<GenericCalcNode<L>>), + /// A `min` or `max` function. + MinMax(crate::OwnedSlice<GenericCalcNode<L>>, MinMaxOp), + /// A `clamp()` function. + Clamp { + /// The minimum value. + min: Box<GenericCalcNode<L>>, + /// The central value. + center: Box<GenericCalcNode<L>>, + /// The maximum value. + max: Box<GenericCalcNode<L>>, + }, +} + +pub use self::GenericCalcNode as CalcNode; + +/// A trait that represents all the stuff a valid leaf of a calc expression. +pub trait CalcNodeLeaf: Clone + Sized + PartialOrd + PartialEq + ToCss { + /// Whether this value is known-negative. + fn is_negative(&self) -> bool; + + /// Tries to merge one sum to another, that is, perform `x` + `y`. + fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()>; + + /// Multiplies the leaf by a given scalar number. + fn mul_by(&mut self, scalar: f32); + + /// Negates the leaf. + fn negate(&mut self) { + self.mul_by(-1.); + } + + /// Canonicalizes the expression if necessary. + fn simplify(&mut self); + + /// Returns the sort key for simplification. + fn sort_key(&self) -> SortKey; +} + +impl<L: CalcNodeLeaf> CalcNode<L> { + /// Negates the node. + pub fn negate(&mut self) { + self.mul_by(-1.); + } + + fn sort_key(&self) -> SortKey { + match *self { + Self::Leaf(ref l) => l.sort_key(), + _ => SortKey::Other, + } + } + + /// Tries to merge one sum to another, that is, perform `x` + `y`. + fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()> { + match (self, other) { + (&mut CalcNode::Leaf(ref mut one), &CalcNode::Leaf(ref other)) => { + one.try_sum_in_place(other) + }, + _ => Err(()), + } + } + + /// Convert this `CalcNode` into a `CalcNode` with a different leaf kind. + pub fn map_leaves<O, F>(&self, mut map: F) -> CalcNode<O> + where + O: CalcNodeLeaf, + F: FnMut(&L) -> O, + { + self.map_leaves_internal(&mut map) + } + + fn map_leaves_internal<O, F>(&self, map: &mut F) -> CalcNode<O> + where + O: CalcNodeLeaf, + F: FnMut(&L) -> O, + { + fn map_children<L, O, F>( + children: &[CalcNode<L>], + map: &mut F, + ) -> crate::OwnedSlice<CalcNode<O>> + where + L: CalcNodeLeaf, + O: CalcNodeLeaf, + F: FnMut(&L) -> O, + { + children + .iter() + .map(|c| c.map_leaves_internal(map)) + .collect() + } + + match *self { + Self::Leaf(ref l) => CalcNode::Leaf(map(l)), + Self::Sum(ref c) => CalcNode::Sum(map_children(c, map)), + Self::MinMax(ref c, op) => CalcNode::MinMax(map_children(c, map), op), + Self::Clamp { + ref min, + ref center, + ref max, + } => { + let min = Box::new(min.map_leaves_internal(map)); + let center = Box::new(center.map_leaves_internal(map)); + let max = Box::new(max.map_leaves_internal(map)); + CalcNode::Clamp { min, center, max } + }, + } + } + + /// Resolves the expression returning a value of `O`, given a function to + /// turn a leaf into the relevant value. + pub fn resolve<O>( + &self, + mut leaf_to_output_fn: impl FnMut(&L) -> Result<O, ()>, + ) -> Result<O, ()> + where + O: PartialOrd + PartialEq + Add<Output = O> + Zero, + { + self.resolve_internal(&mut leaf_to_output_fn) + } + + fn resolve_internal<O, F>(&self, leaf_to_output_fn: &mut F) -> Result<O, ()> + where + O: PartialOrd + PartialEq + Add<Output = O> + Zero, + F: FnMut(&L) -> Result<O, ()>, + { + Ok(match *self { + Self::Leaf(ref l) => return leaf_to_output_fn(l), + Self::Sum(ref c) => { + let mut result = Zero::zero(); + for child in &**c { + result = result + child.resolve_internal(leaf_to_output_fn)?; + } + result + }, + Self::MinMax(ref nodes, op) => { + let mut result = nodes[0].resolve_internal(leaf_to_output_fn)?; + for node in nodes.iter().skip(1) { + let candidate = node.resolve_internal(leaf_to_output_fn)?; + let candidate_wins = match op { + MinMaxOp::Min => candidate < result, + MinMaxOp::Max => candidate > result, + }; + if candidate_wins { + result = candidate; + } + } + result + }, + Self::Clamp { + ref min, + ref center, + ref max, + } => { + let min = min.resolve_internal(leaf_to_output_fn)?; + let center = center.resolve_internal(leaf_to_output_fn)?; + let max = max.resolve_internal(leaf_to_output_fn)?; + + let mut result = center; + if result > max { + result = max; + } + if result < min { + result = min + } + result + }, + }) + } + + fn is_negative_leaf(&self) -> bool { + match *self { + Self::Leaf(ref l) => l.is_negative(), + _ => false, + } + } + + /// Multiplies the node by a scalar. + pub fn mul_by(&mut self, scalar: f32) { + match *self { + Self::Leaf(ref mut l) => l.mul_by(scalar), + // Multiplication is distributive across this. + Self::Sum(ref mut children) => { + for node in &mut **children { + node.mul_by(scalar); + } + }, + // This one is a bit trickier. + Self::MinMax(ref mut children, ref mut op) => { + for node in &mut **children { + node.mul_by(scalar); + } + + // For negatives we need to invert the operation. + if scalar < 0. { + *op = match *op { + MinMaxOp::Min => MinMaxOp::Max, + MinMaxOp::Max => MinMaxOp::Min, + } + } + }, + // This one is slightly tricky too. + Self::Clamp { + ref mut min, + ref mut center, + ref mut max, + } => { + min.mul_by(scalar); + center.mul_by(scalar); + max.mul_by(scalar); + // For negatives we need to swap min / max. + if scalar < 0. { + mem::swap(min, max); + } + }, + } + } + + /// Visits all the nodes in this calculation tree recursively, starting by + /// the leaves and bubbling all the way up. + /// + /// This is useful for simplification, but can also be used for validation + /// and such. + pub fn visit_depth_first(&mut self, mut f: impl FnMut(&mut Self)) { + self.visit_depth_first_internal(&mut f); + } + + fn visit_depth_first_internal(&mut self, f: &mut impl FnMut(&mut Self)) { + match *self { + Self::Clamp { + ref mut min, + ref mut center, + ref mut max, + } => { + min.visit_depth_first_internal(f); + center.visit_depth_first_internal(f); + max.visit_depth_first_internal(f); + }, + Self::Sum(ref mut children) | Self::MinMax(ref mut children, _) => { + for child in &mut **children { + child.visit_depth_first_internal(f); + } + }, + Self::Leaf(..) => {}, + } + f(self); + } + + /// Simplifies and sorts the calculation of a given node. All the nodes + /// below it should be simplified already, this only takes care of + /// simplifying directly nested nodes. So, probably should always be used in + /// combination with `visit_depth_first()`. + /// + /// This is only needed if it's going to be preserved after parsing (so, for + /// `<length-percentage>`). Otherwise we can just evaluate it using + /// `resolve()`, and we'll come up with a simplified value anyways. + pub fn simplify_and_sort_direct_children(&mut self) { + macro_rules! replace_self_with { + ($slot:expr) => {{ + let dummy = Self::MinMax(Default::default(), MinMaxOp::Max); + let result = mem::replace($slot, dummy); + mem::replace(self, result); + }}; + } + match *self { + Self::Clamp { + ref mut min, + ref mut center, + ref mut max, + } => { + // NOTE: clamp() is max(min, min(center, max)) + let min_cmp_center = match min.partial_cmp(¢er) { + Some(o) => o, + None => return, + }; + + // So if we can prove that min is more than center, then we won, + // as that's what we should always return. + if matches!(min_cmp_center, cmp::Ordering::Greater) { + return replace_self_with!(&mut **min); + } + + // Otherwise try with max. + let max_cmp_center = match max.partial_cmp(¢er) { + Some(o) => o, + None => return, + }; + + if matches!(max_cmp_center, cmp::Ordering::Less) { + // max is less than center, so we need to return effectively + // `max(min, max)`. + let max_cmp_min = match max.partial_cmp(&min) { + Some(o) => o, + None => { + debug_assert!( + false, + "We compared center with min and max, how are \ + min / max not comparable with each other?" + ); + return; + }, + }; + + if matches!(max_cmp_min, cmp::Ordering::Less) { + return replace_self_with!(&mut **min); + } + + return replace_self_with!(&mut **max); + } + + // Otherwise we're the center node. + return replace_self_with!(&mut **center); + }, + Self::MinMax(ref mut children, op) => { + let winning_order = match op { + MinMaxOp::Min => cmp::Ordering::Less, + MinMaxOp::Max => cmp::Ordering::Greater, + }; + + let mut result = 0; + for i in 1..children.len() { + let o = match children[i].partial_cmp(&children[result]) { + // We can't compare all the children, so we can't + // know which one will actually win. Bail out and + // keep ourselves as a min / max function. + // + // TODO: Maybe we could simplify compatible children, + // see https://github.com/w3c/csswg-drafts/issues/4756 + None => return, + Some(o) => o, + }; + + if o == winning_order { + result = i; + } + } + + replace_self_with!(&mut children[result]); + }, + Self::Sum(ref mut children_slot) => { + let mut sums_to_merge = SmallVec::<[_; 3]>::new(); + let mut extra_kids = 0; + for (i, child) in children_slot.iter().enumerate() { + if let Self::Sum(ref children) = *child { + extra_kids += children.len(); + sums_to_merge.push(i); + } + } + + // If we only have one kid, we've already simplified it, and it + // doesn't really matter whether it's a sum already or not, so + // lift it up and continue. + if children_slot.len() == 1 { + return replace_self_with!(&mut children_slot[0]); + } + + let mut children = mem::replace(children_slot, Default::default()).into_vec(); + + if !sums_to_merge.is_empty() { + children.reserve(extra_kids - sums_to_merge.len()); + // Merge all our nested sums, in reverse order so that the + // list indices are not invalidated. + for i in sums_to_merge.drain(..).rev() { + let kid_children = match children.swap_remove(i) { + Self::Sum(c) => c, + _ => unreachable!(), + }; + + // This would be nicer with + // https://github.com/rust-lang/rust/issues/59878 fixed. + children.extend(kid_children.into_vec()); + } + } + + debug_assert!(children.len() >= 2, "Should still have multiple kids!"); + + // Sort by spec order. + children.sort_unstable_by_key(|c| c.sort_key()); + + // NOTE: if the function returns true, by the docs of dedup_by, + // a is removed. + children.dedup_by(|a, b| b.try_sum_in_place(a).is_ok()); + + if children.len() == 1 { + // If only one children remains, lift it up, and carry on. + replace_self_with!(&mut children[0]); + } else { + // Else put our simplified children back. + mem::replace(children_slot, children.into_boxed_slice().into()); + } + }, + Self::Leaf(ref mut l) => { + l.simplify(); + }, + } + } + + /// Simplifies and sorts the kids in the whole calculation subtree. + pub fn simplify_and_sort(&mut self) { + self.visit_depth_first(|node| node.simplify_and_sort_direct_children()) + } + + fn to_css_impl<W>(&self, dest: &mut CssWriter<W>, is_outermost: bool) -> fmt::Result + where + W: Write, + { + let write_closing_paren = match *self { + Self::MinMax(_, op) => { + dest.write_str(match op { + MinMaxOp::Max => "max(", + MinMaxOp::Min => "min(", + })?; + true + }, + Self::Clamp { .. } => { + dest.write_str("clamp(")?; + true + }, + _ => { + if is_outermost { + dest.write_str("calc(")?; + } + is_outermost + }, + }; + + match *self { + Self::MinMax(ref children, _) => { + let mut first = true; + for child in &**children { + if !first { + dest.write_str(", ")?; + } + first = false; + child.to_css_impl(dest, false)?; + } + }, + Self::Sum(ref children) => { + let mut first = true; + for child in &**children { + if !first { + if child.is_negative_leaf() { + dest.write_str(" - ")?; + let mut c = child.clone(); + c.negate(); + c.to_css_impl(dest, false)?; + } else { + dest.write_str(" + ")?; + child.to_css_impl(dest, false)?; + } + } else { + first = false; + child.to_css_impl(dest, false)?; + } + } + }, + Self::Clamp { + ref min, + ref center, + ref max, + } => { + min.to_css_impl(dest, false)?; + dest.write_str(", ")?; + center.to_css_impl(dest, false)?; + dest.write_str(", ")?; + max.to_css_impl(dest, false)?; + }, + Self::Leaf(ref l) => l.to_css(dest)?, + } + + if write_closing_paren { + dest.write_str(")")?; + } + Ok(()) + } +} + +impl<L: CalcNodeLeaf> PartialOrd for CalcNode<L> { + fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { + match (self, other) { + (&CalcNode::Leaf(ref one), &CalcNode::Leaf(ref other)) => one.partial_cmp(other), + _ => None, + } + } +} + +impl<L: CalcNodeLeaf> ToCss for CalcNode<L> { + /// <https://drafts.csswg.org/css-values/#calc-serialize> + fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result + where + W: Write, + { + self.to_css_impl(dest, /* is_outermost = */ true) + } +} diff --git a/components/style/values/generics/grid.rs b/components/style/values/generics/grid.rs index 5666e2c5818..6f0f155912d 100644 --- a/components/style/values/generics/grid.rs +++ b/components/style/values/generics/grid.rs @@ -655,8 +655,10 @@ impl<L: ToCss, I: ToCss> ToCss for TrackList<L, I> { pub struct LineNameList { /// The optional `<line-name-list>` pub names: crate::OwnedSlice<crate::OwnedSlice<CustomIdent>>, - /// Indicates the line name that requires `auto-fill`, if in bounds. - pub fill_idx: usize, + /// Indicates the starting line names that requires `auto-fill`, if in bounds. + pub fill_start: usize, + /// Indicates the number of line names in the auto-fill + pub fill_len: usize, } impl Parse for LineNameList { @@ -666,7 +668,7 @@ impl Parse for LineNameList { ) -> Result<Self, ParseError<'i>> { input.expect_ident_matching("subgrid")?; let mut line_names = vec![]; - let mut fill_idx = None; + let mut fill_data = None; loop { let repeat_parse_result = input.try(|input| { @@ -682,8 +684,7 @@ impl Parse for LineNameList { Ok((names_list, count)) }) }); - - if let Ok((mut names_list, count)) = repeat_parse_result { + if let Ok((names_list, count)) = repeat_parse_result { match count { // FIXME(emilio): we shouldn't expand repeat() at // parse time for subgrid. (bug 1583429) @@ -694,19 +695,11 @@ impl Parse for LineNameList { .cycle() .take(num.value() as usize * names_list.len()), ), - RepeatCount::AutoFill if fill_idx.is_none() => { - // `repeat(autof-fill, ..)` should have just one line name. - // FIXME(bug 1341507) the above comment is wrong per: - // https://drafts.csswg.org/css-grid-2/#typedef-name-repeat - if names_list.len() != 1 { - return Err( - input.new_custom_error(StyleParseErrorKind::UnspecifiedError) - ); - } - let names = names_list.pop().unwrap(); - - line_names.push(names); - fill_idx = Some(line_names.len() - 1); + RepeatCount::AutoFill if fill_data.is_none() => { + let fill_idx = line_names.len(); + let fill_len = names_list.len(); + fill_data = Some((fill_idx, fill_len)); + line_names.extend(names_list.into_iter()); }, _ => return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)), } @@ -721,9 +714,12 @@ impl Parse for LineNameList { line_names.truncate(MAX_GRID_LINE as usize); } + let (fill_start, fill_len) = fill_data.unwrap_or((usize::MAX, 0)); + Ok(LineNameList { names: line_names.into(), - fill_idx: fill_idx.unwrap_or(usize::MAX), + fill_start: fill_start, + fill_len: fill_len, }) } } @@ -734,9 +730,10 @@ impl ToCss for LineNameList { W: Write, { dest.write_str("subgrid")?; - let fill_idx = self.fill_idx; + let fill_start = self.fill_start; + let fill_len = self.fill_len; for (i, names) in self.names.iter().enumerate() { - if i == fill_idx { + if i == fill_start { dest.write_str(" repeat(auto-fill,")?; } @@ -751,7 +748,7 @@ impl ToCss for LineNameList { } dest.write_str("]")?; - if i == fill_idx { + if i == fill_start + fill_len - 1 { dest.write_str(")")?; } } diff --git a/components/style/values/generics/image.rs b/components/style/values/generics/image.rs index a6b45bc82ad..42d541dc6f2 100644 --- a/components/style/values/generics/image.rs +++ b/components/style/values/generics/image.rs @@ -9,55 +9,28 @@ use crate::custom_properties; use crate::values::serialize_atom_identifier; use crate::Atom; +use crate::Zero; use servo_arc::Arc; use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss}; +use values::generics::position::PositionComponent; -/// An <image> | <none> (for background-image, for example). -#[derive( - Clone, - Debug, - MallocSizeOf, - Parse, - PartialEq, - SpecifiedValueInfo, - ToComputedValue, - ToCss, - ToResolvedValue, - ToShmem, -)] -pub enum GenericImageLayer<Image> { - /// The `none` value. - None, - /// The `<image>` value. - Image(Image), -} - -pub use self::GenericImageLayer as ImageLayer; - -impl<I> ImageLayer<I> { - /// Returns `none`. - #[inline] - pub fn none() -> Self { - ImageLayer::None - } -} - -/// An [image]. +/// An `<image> | none` value. /// -/// [image]: https://drafts.csswg.org/css-images/#image-values +/// https://drafts.csswg.org/css-images/#image-values #[derive( Clone, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem, )] #[repr(C, u8)] -pub enum GenericImage<Gradient, MozImageRect, ImageUrl> { +pub enum GenericImage<G, MozImageRect, ImageUrl> { + /// `none` variant. + None, /// A `<url()>` image. Url(ImageUrl), /// A `<gradient>` image. Gradients are rather large, and not nearly as /// common as urls, so we box them here to keep the size of this enum sane. - Gradient(Box<Gradient>), - + Gradient(Box<G>), /// A `-moz-image-rect` image. Also fairly large and rare. // not cfg’ed out on non-Gecko to avoid `error[E0392]: parameter `MozImageRect` is never used` // Instead we make MozImageRect an empty enum @@ -80,27 +53,51 @@ pub use self::GenericImage as Image; /// <https://drafts.csswg.org/css-images/#gradients> #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] #[repr(C)] -pub struct GenericGradient< +pub enum GenericGradient< LineDirection, LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage, Position, + Angle, + AngleOrPercentage, Color, > { - /// Gradients can be linear or radial. - pub kind: GenericGradientKind< - LineDirection, - NonNegativeLength, - NonNegativeLengthPercentage, - Position, - >, - /// The color stops and interpolation hints. - pub items: crate::OwnedSlice<GenericGradientItem<Color, LengthPercentage>>, - /// True if this is a repeating gradient. - pub repeating: bool, - /// Compatibility mode. - pub compat_mode: GradientCompatMode, + /// A linear gradient. + Linear { + /// Line direction + direction: LineDirection, + /// The color stops and interpolation hints. + items: crate::OwnedSlice<GenericGradientItem<Color, LengthPercentage>>, + /// True if this is a repeating gradient. + repeating: bool, + /// Compatibility mode. + compat_mode: GradientCompatMode, + }, + /// A radial gradient. + Radial { + /// Shape of gradient + shape: GenericEndingShape<NonNegativeLength, NonNegativeLengthPercentage>, + /// Center of gradient + position: Position, + /// The color stops and interpolation hints. + items: crate::OwnedSlice<GenericGradientItem<Color, LengthPercentage>>, + /// True if this is a repeating gradient. + repeating: bool, + /// Compatibility mode. + compat_mode: GradientCompatMode, + }, + /// A conic gradient. + Conic { + /// Start angle of gradient + angle: Angle, + /// Center of gradient + position: Position, + /// The color stops and interpolation hints. + items: crate::OwnedSlice<GenericGradientItem<Color, AngleOrPercentage>>, + /// True if this is a repeating gradient. + repeating: bool, + }, } pub use self::GenericGradient as Gradient; @@ -117,26 +114,6 @@ pub enum GradientCompatMode { Moz, } -/// A gradient kind. -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] -#[repr(C, u8)] -pub enum GenericGradientKind< - LineDirection, - NonNegativeLength, - NonNegativeLengthPercentage, - Position, -> { - /// A linear gradient. - Linear(LineDirection), - /// A radial gradient. - Radial( - GenericEndingShape<NonNegativeLength, NonNegativeLengthPercentage>, - Position, - ), -} - -pub use self::GenericGradientKind as GradientKind; - /// A radial gradient's ending shape. #[derive( Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem, @@ -209,7 +186,7 @@ pub enum ShapeExtent { Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem, )] #[repr(C, u8)] -pub enum GenericGradientItem<Color, LengthPercentage> { +pub enum GenericGradientItem<Color, T> { /// A simple color stop, without position. SimpleColorStop(Color), /// A complex color stop, with a position. @@ -217,10 +194,10 @@ pub enum GenericGradientItem<Color, LengthPercentage> { /// The color for the stop. color: Color, /// The position for the stop. - position: LengthPercentage, + position: T, }, /// An interpolation hint. - InterpolationHint(LengthPercentage), + InterpolationHint(T), } pub use self::GenericGradientItem as GradientItem; @@ -230,17 +207,17 @@ pub use self::GenericGradientItem as GradientItem; #[derive( Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem, )] -pub struct ColorStop<Color, LengthPercentage> { +pub struct ColorStop<Color, T> { /// The color of this stop. pub color: Color, /// The position of this stop. - pub position: Option<LengthPercentage>, + pub position: Option<T>, } -impl<Color, LengthPercentage> ColorStop<Color, LengthPercentage> { +impl<Color, T> ColorStop<Color, T> { /// Convert the color stop into an appropriate `GradientItem`. #[inline] - pub fn into_item(self) -> GradientItem<Color, LengthPercentage> { + pub fn into_item(self) -> GradientItem<Color, T> { match self.position { Some(position) => GradientItem::ComplexColorStop { color: self.color, @@ -261,6 +238,8 @@ pub struct PaintWorklet { /// The arguments for the worklet. /// TODO: store a parsed representation of the arguments. #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")] + #[compute(no_field_bound)] + #[resolve(no_field_bound)] pub arguments: Vec<Arc<custom_properties::SpecifiedValue>>, } @@ -285,7 +264,7 @@ impl ToCss for PaintWorklet { /// /// `-moz-image-rect(<uri>, top, right, bottom, left);` #[allow(missing_docs)] -#[css(comma, function)] +#[css(comma, function = "-moz-image-rect")] #[derive( Clone, Debug, @@ -297,7 +276,8 @@ impl ToCss for PaintWorklet { ToResolvedValue, ToShmem, )] -pub struct MozImageRect<NumberOrPercentage, MozImageRectUrl> { +#[repr(C)] +pub struct GenericMozImageRect<NumberOrPercentage, MozImageRectUrl> { pub url: MozImageRectUrl, pub top: NumberOrPercentage, pub right: NumberOrPercentage, @@ -305,6 +285,8 @@ pub struct MozImageRect<NumberOrPercentage, MozImageRectUrl> { pub left: NumberOrPercentage, } +pub use self::GenericMozImageRect as MozImageRect; + impl<G, R, U> fmt::Debug for Image<G, R, U> where G: ToCss, @@ -327,6 +309,7 @@ where W: Write, { match *self { + Image::None => dest.write_str("none"), Image::Url(ref url) => url.to_css(dest), Image::Gradient(ref gradient) => gradient.to_css(dest), Image::Rect(ref rect) => rect.to_css(dest), @@ -342,81 +325,146 @@ where } } -impl<D, LP, NL, NLP, P, C> ToCss for Gradient<D, LP, NL, NLP, P, C> +impl<D, LP, NL, NLP, P, A: Zero, AoP, C> ToCss for Gradient<D, LP, NL, NLP, P, A, AoP, C> where D: LineDirection, LP: ToCss, NL: ToCss, NLP: ToCss, - P: ToCss, + P: PositionComponent + ToCss, + A: ToCss, + AoP: ToCss, C: ToCss, { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write, { - match self.compat_mode { + let (compat_mode, repeating) = match *self { + Gradient::Linear { + compat_mode, + repeating, + .. + } => (compat_mode, repeating), + Gradient::Radial { + compat_mode, + repeating, + .. + } => (compat_mode, repeating), + Gradient::Conic { repeating, .. } => (GradientCompatMode::Modern, repeating), + }; + + match compat_mode { GradientCompatMode::WebKit => dest.write_str("-webkit-")?, GradientCompatMode::Moz => dest.write_str("-moz-")?, _ => {}, } - if self.repeating { + if repeating { dest.write_str("repeating-")?; } - dest.write_str(self.kind.label())?; - dest.write_str("-gradient(")?; - let mut skip_comma = match self.kind { - GradientKind::Linear(ref direction) if direction.points_downwards(self.compat_mode) => { - true - }, - GradientKind::Linear(ref direction) => { - direction.to_css(dest, self.compat_mode)?; - false + + match *self { + Gradient::Linear { + ref direction, + ref items, + compat_mode, + .. + } => { + dest.write_str("linear-gradient(")?; + let mut skip_comma = if !direction.points_downwards(compat_mode) { + direction.to_css(dest, compat_mode)?; + false + } else { + true + }; + for item in &**items { + if !skip_comma { + dest.write_str(", ")?; + } + skip_comma = false; + item.to_css(dest)?; + } }, - GradientKind::Radial(ref shape, ref position) => { + Gradient::Radial { + ref shape, + ref position, + ref items, + compat_mode, + .. + } => { + dest.write_str("radial-gradient(")?; let omit_shape = match *shape { EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::Cover)) | EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::FarthestCorner)) => true, _ => false, }; - if self.compat_mode == GradientCompatMode::Modern { + let omit_position = position.is_center(); + if compat_mode == GradientCompatMode::Modern { + if !omit_shape { + shape.to_css(dest)?; + if !omit_position { + dest.write_str(" ")?; + } + } + if !omit_position { + dest.write_str("at ")?; + position.to_css(dest)?; + } + } else { + if !omit_position { + position.to_css(dest)?; + if !omit_shape { + dest.write_str(", ")?; + } + } if !omit_shape { shape.to_css(dest)?; + } + } + let mut skip_comma = omit_shape && omit_position; + for item in &**items { + if !skip_comma { + dest.write_str(", ")?; + } + skip_comma = false; + item.to_css(dest)?; + } + }, + Gradient::Conic { + ref angle, + ref position, + ref items, + .. + } => { + dest.write_str("conic-gradient(")?; + let omit_angle = angle.is_zero(); + let omit_position = position.is_center(); + if !omit_angle { + dest.write_str("from ")?; + angle.to_css(dest)?; + if !omit_position { dest.write_str(" ")?; } + } + if !omit_position { dest.write_str("at ")?; position.to_css(dest)?; - } else { - position.to_css(dest)?; - if !omit_shape { + } + let mut skip_comma = omit_angle && omit_position; + for item in &**items { + if !skip_comma { dest.write_str(", ")?; - shape.to_css(dest)?; } + skip_comma = false; + item.to_css(dest)?; } - false }, - }; - for item in &*self.items { - if !skip_comma { - dest.write_str(", ")?; - } - skip_comma = false; - item.to_css(dest)?; } dest.write_str(")") } } -impl<D, L, LoP, P> GradientKind<D, L, LoP, P> { - fn label(&self) -> &str { - match *self { - GradientKind::Linear(..) => "linear", - GradientKind::Radial(..) => "radial", - } - } -} - /// The direction of a linear gradient. pub trait LineDirection { /// Whether this direction points towards, and thus can be omitted. diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index a97d9e1018a..6689405b2b1 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -19,6 +19,7 @@ pub mod basic_shape; pub mod border; #[path = "box.rs"] pub mod box_; +pub mod calc; pub mod color; pub mod column; pub mod counters; diff --git a/components/style/values/generics/position.rs b/components/style/values/generics/position.rs index a3552ea3eab..00a9a219df4 100644 --- a/components/style/values/generics/position.rs +++ b/components/style/values/generics/position.rs @@ -31,6 +31,17 @@ pub struct GenericPosition<H, V> { pub vertical: V, } +impl<H, V> PositionComponent for Position<H, V> +where + H: PositionComponent, + V: PositionComponent, +{ + #[inline] + fn is_center(&self) -> bool { + self.horizontal.is_center() && self.vertical.is_center() + } +} + pub use self::GenericPosition as Position; impl<H, V> Position<H, V> { @@ -43,6 +54,13 @@ impl<H, V> Position<H, V> { } } +/// Implements a method that checks if the position is centered. +pub trait PositionComponent { + /// Returns if the position component is 50% or center. + /// For pixel lengths, it always returns false. + fn is_center(&self) -> bool; +} + /// A generic type for representing an `Auto | <position>`. /// This is used by <offset-anchor> for now. /// https://drafts.fxtf.org/motion-1/#offset-anchor-property diff --git a/components/style/values/generics/svg.rs b/components/style/values/generics/svg.rs index 82183c30564..2b04d36db78 100644 --- a/components/style/values/generics/svg.rs +++ b/components/style/values/generics/svg.rs @@ -152,7 +152,8 @@ impl<C: Parse, U: Parse> Parse for SVGPaint<C, U> { ToResolvedValue, ToShmem, )] -pub enum SVGLength<L> { +#[repr(C, u8)] +pub enum GenericSVGLength<L> { /// `<length> | <percentage> | <number>` LengthPercentage(L), /// `context-value` @@ -160,6 +161,8 @@ pub enum SVGLength<L> { ContextValue, } +pub use self::GenericSVGLength as SVGLength; + /// Generic value for stroke-dasharray. #[derive( Clone, diff --git a/components/style/values/generics/transform.rs b/components/style/values/generics/transform.rs index b77bba40b82..ef414c1f9a0 100644 --- a/components/style/values/generics/transform.rs +++ b/components/style/values/generics/transform.rs @@ -354,7 +354,7 @@ impl ToAbsoluteLength for SpecifiedLengthPercentage { match *self { Length(len) => len.to_computed_pixel_length_without_context(), Calc(ref calc) => calc.to_computed_pixel_length_without_context(), - _ => Err(()), + Percentage(..) => Err(()), } } } diff --git a/components/style/values/generics/ui.rs b/components/style/values/generics/ui.rs index 945f60fb5dd..6dfbb4a9c94 100644 --- a/components/style/values/generics/ui.rs +++ b/components/style/values/generics/ui.rs @@ -21,19 +21,22 @@ use values::specified::ui::CursorKind; ToResolvedValue, ToShmem, )] -pub struct Cursor<Image> { +#[repr(C)] +pub struct GenericCursor<Image> { /// The parsed images for the cursor. - pub images: Box<[Image]>, + pub images: crate::OwnedSlice<Image>, /// The kind of the cursor [default | help | ...]. pub keyword: CursorKind, } +pub use self::GenericCursor as Cursor; + impl<Image> Cursor<Image> { /// Set `cursor` to `auto` #[inline] pub fn auto() -> Self { Self { - images: vec![].into_boxed_slice(), + images: Default::default(), keyword: CursorKind::Auto, } } @@ -63,24 +66,31 @@ impl<Image: ToCss> ToCss for Cursor<Image> { ToResolvedValue, ToShmem, )] -pub struct CursorImage<ImageUrl, Number> { +#[repr(C)] +pub struct GenericCursorImage<ImageUrl, Number> { /// The url to parse images from. pub url: ImageUrl, - /// The <x> and <y> coordinates. - pub hotspot: Option<(Number, Number)>, + /// Whether the image has a hotspot or not. + pub has_hotspot: bool, + /// The x coordinate. + pub hotspot_x: Number, + /// The y coordinate. + pub hotspot_y: Number, } +pub use self::GenericCursorImage as CursorImage; + impl<ImageUrl: ToCss, Number: ToCss> ToCss for CursorImage<ImageUrl, Number> { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write, { self.url.to_css(dest)?; - if let Some((ref x, ref y)) = self.hotspot { + if self.has_hotspot { dest.write_str(" ")?; - x.to_css(dest)?; + self.hotspot_x.to_css(dest)?; dest.write_str(" ")?; - y.to_css(dest)?; + self.hotspot_y.to_css(dest)?; } Ok(()) } diff --git a/components/style/values/resolved/mod.rs b/components/style/values/resolved/mod.rs index 022cb7893c6..45cc5cbd8cf 100644 --- a/components/style/values/resolved/mod.rs +++ b/components/style/values/resolved/mod.rs @@ -6,7 +6,9 @@ //! there are used values. use crate::properties::ComputedValues; +use crate::ArcSlice; use cssparser; +use servo_arc::Arc; use smallvec::SmallVec; mod color; @@ -77,8 +79,11 @@ trivial_to_resolved_value!(computed::url::ComputedUrl); #[cfg(feature = "gecko")] trivial_to_resolved_value!(computed::url::ComputedImageUrl); #[cfg(feature = "servo")] +trivial_to_resolved_value!(html5ever::Namespace); +#[cfg(feature = "servo")] trivial_to_resolved_value!(html5ever::Prefix); trivial_to_resolved_value!(computed::LengthPercentage); +trivial_to_resolved_value!(style_traits::values::specified::AllowedNumericType); impl<A, B> ToResolvedValue for (A, B) where @@ -214,3 +219,43 @@ where Self::from(Box::from_resolved_value(resolved.into_box())) } } + +// NOTE(emilio): This is implementable more generically, but it's unlikely what +// you want there, as it forces you to have an extra allocation. +// +// We could do that if needed, ideally with specialization for the case where +// ResolvedValue = T. But we don't need it for now. +impl<T> ToResolvedValue for Arc<T> +where + T: ToResolvedValue<ResolvedValue = T>, +{ + type ResolvedValue = Self; + + #[inline] + fn to_resolved_value(self, _: &Context) -> Self { + self + } + + #[inline] + fn from_resolved_value(resolved: Self) -> Self { + resolved + } +} + +// Same caveat as above applies. +impl<T> ToResolvedValue for ArcSlice<T> +where + T: ToResolvedValue<ResolvedValue = T>, +{ + type ResolvedValue = Self; + + #[inline] + fn to_resolved_value(self, _: &Context) -> Self { + self + } + + #[inline] + fn from_resolved_value(resolved: Self) -> Self { + resolved + } +} diff --git a/components/style/values/specified/align.rs b/components/style/values/specified/align.rs index d0160a32ae6..10f7f3efbfc 100644 --- a/components/style/values/specified/align.rs +++ b/components/style/values/specified/align.rs @@ -556,7 +556,7 @@ impl SpecifiedValueInfo for AlignItems { /// Value of the `justify-items` property /// /// <https://drafts.csswg.org/css-align/#justify-items-property> -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToShmem)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToResolvedValue, ToShmem)] #[repr(C)] pub struct JustifyItems(pub AlignFlags); diff --git a/components/style/values/specified/basic_shape.rs b/components/style/values/specified/basic_shape.rs index 3c32144e71c..b1782c5b294 100644 --- a/components/style/values/specified/basic_shape.rs +++ b/components/style/values/specified/basic_shape.rs @@ -9,8 +9,7 @@ use crate::parser::{Parse, ParserContext}; use crate::values::generics::basic_shape as generic; -use crate::values::generics::basic_shape::{GeometryBox, Path, PolygonCoord}; -use crate::values::generics::basic_shape::{ShapeBox, ShapeSource}; +use crate::values::generics::basic_shape::{Path, PolygonCoord}; use crate::values::generics::rect::Rect; use crate::values::specified::border::BorderRadius; use crate::values::specified::image::Image; @@ -25,14 +24,14 @@ use style_traits::{ParseError, StyleParseErrorKind}; /// A specified alias for FillRule. pub use crate::values::generics::basic_shape::FillRule; -/// A specified clipping shape. -pub type ClippingShape = generic::ClippingShape<BasicShape, SpecifiedUrl>; +/// A specified `clip-path` value. +pub type ClipPath = generic::GenericClipPath<BasicShape, SpecifiedUrl>; -/// A specified float area shape. -pub type FloatAreaShape = generic::FloatAreaShape<BasicShape, Image>; +/// A specified `shape-outside` value. +pub type ShapeOutside = generic::GenericShapeOutside<BasicShape, Image>; /// A specified basic shape. -pub type BasicShape = generic::BasicShape< +pub type BasicShape = generic::GenericBasicShape< HorizontalPosition, VerticalPosition, LengthPercentage, @@ -65,99 +64,90 @@ fn is_clip_path_path_enabled(_: &ParserContext) -> bool { false } -impl Parse for ClippingShape { - #[inline] - fn parse<'i, 't>( +/// A helper for both clip-path and shape-outside parsing of shapes. +fn parse_shape_or_box<'i, 't, R, ReferenceBox>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + to_shape: impl FnOnce(Box<BasicShape>, ReferenceBox) -> R, + to_reference_box: impl FnOnce(ReferenceBox) -> R, +) -> Result<R, ParseError<'i>> +where + ReferenceBox: Default + Parse, +{ + fn parse_component<U: Parse>( context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result<Self, ParseError<'i>> { - if is_clip_path_path_enabled(context) { - if let Ok(p) = input.try(|i| Path::parse(context, i)) { - return Ok(ShapeSource::Path(p)); - } + input: &mut Parser, + component: &mut Option<U>, + ) -> bool { + if component.is_some() { + return false; // already parsed this component } - if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) { - return Ok(ShapeSource::ImageOrUrl(url)); - } + *component = input.try(|i| U::parse(context, i)).ok(); + component.is_some() + } + + let mut shape = None; + let mut ref_box = None; - Self::parse_common(context, input) + while parse_component(context, input, &mut shape) || + parse_component(context, input, &mut ref_box) + { + // } -} -impl Parse for FloatAreaShape { - #[inline] - fn parse<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result<Self, ParseError<'i>> { - if let Ok(image) = input.try(|i| Image::parse_with_cors_anonymous(context, i)) { - return Ok(ShapeSource::ImageOrUrl(image)); - } + if let Some(shp) = shape { + return Ok(to_shape(Box::new(shp), ref_box.unwrap_or_default())); + } - Self::parse_common(context, input) + match ref_box { + Some(r) => Ok(to_reference_box(r)), + None => Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)), } } -impl<ReferenceBox, ImageOrUrl> ShapeSource<BasicShape, ReferenceBox, ImageOrUrl> -where - ReferenceBox: Parse, -{ - /// The internal parser for ShapeSource. - fn parse_common<'i, 't>( +impl Parse for ClipPath { + #[inline] + fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> { if input.try(|i| i.expect_ident_matching("none")).is_ok() { - return Ok(ShapeSource::None); + return Ok(ClipPath::None); } - fn parse_component<U: Parse>( - context: &ParserContext, - input: &mut Parser, - component: &mut Option<U>, - ) -> bool { - if component.is_some() { - return false; // already parsed this component + if is_clip_path_path_enabled(context) { + if let Ok(p) = input.try(|i| Path::parse(context, i)) { + return Ok(ClipPath::Path(p)); } - - *component = input.try(|i| U::parse(context, i)).ok(); - component.is_some() } - let mut shape = None; - let mut ref_box = None; - - while parse_component(context, input, &mut shape) || - parse_component(context, input, &mut ref_box) - { - // - } - - if let Some(shp) = shape { - return Ok(ShapeSource::Shape(Box::new(shp), ref_box)); + if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) { + return Ok(ClipPath::Url(url)); } - ref_box - .map(ShapeSource::Box) - .ok_or(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + parse_shape_or_box(context, input, ClipPath::Shape, ClipPath::Box) } } -impl Parse for GeometryBox { +impl Parse for ShapeOutside { + #[inline] fn parse<'i, 't>( - _context: &ParserContext, + context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> { - if let Ok(shape_box) = input.try(ShapeBox::parse) { - return Ok(GeometryBox::ShapeBox(shape_box)); + // Need to parse this here so that `Image::parse_with_cors_anonymous` + // doesn't parse it. + if input.try(|i| i.expect_ident_matching("none")).is_ok() { + return Ok(ShapeOutside::None); } - try_match_ident_ignore_ascii_case! { input, - "fill-box" => Ok(GeometryBox::FillBox), - "stroke-box" => Ok(GeometryBox::StrokeBox), - "view-box" => Ok(GeometryBox::ViewBox), + if let Ok(image) = input.try(|i| Image::parse_with_cors_anonymous(context, i)) { + debug_assert_ne!(image, Image::None); + return Ok(ShapeOutside::Image(image)); } + + parse_shape_or_box(context, input, ShapeOutside::Shape, ShapeOutside::Box) } } diff --git a/components/style/values/specified/border.rs b/components/style/values/specified/border.rs index 1b1ed74d568..28be8177cf4 100644 --- a/components/style/values/specified/border.rs +++ b/components/style/values/specified/border.rs @@ -234,7 +234,18 @@ impl Parse for BorderSpacing { #[allow(missing_docs)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[derive( - Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem, + Clone, + Copy, + Debug, + Eq, + MallocSizeOf, + Parse, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, )] pub enum BorderImageRepeatKeyword { Stretch, diff --git a/components/style/values/specified/box.rs b/components/style/values/specified/box.rs index fa5d5a2d43a..987a0567432 100644 --- a/components/style/values/specified/box.rs +++ b/components/style/values/specified/box.rs @@ -104,6 +104,8 @@ pub enum DisplayInside { #[cfg(feature = "gecko")] MozGridLine, #[cfg(feature = "gecko")] + MozStack, + #[cfg(feature = "gecko")] MozDeck, #[cfg(feature = "gecko")] MozPopup, @@ -227,6 +229,8 @@ impl Display { #[cfg(feature = "gecko")] pub const MozGridLine: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGridLine); #[cfg(feature = "gecko")] + pub const MozStack: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozStack); + #[cfg(feature = "gecko")] pub const MozDeck: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozDeck); #[cfg(feature = "gecko")] pub const MozPopup: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozPopup); @@ -616,6 +620,8 @@ impl Parse for Display { #[cfg(feature = "gecko")] "-moz-grid-line" if moz_display_values_enabled(context) => Display::MozGridLine, #[cfg(feature = "gecko")] + "-moz-stack" if moz_display_values_enabled(context) => Display::MozStack, + #[cfg(feature = "gecko")] "-moz-deck" if moz_display_values_enabled(context) => Display::MozDeck, #[cfg(feature = "gecko")] "-moz-popup" if moz_display_values_enabled(context) => Display::MozPopup, @@ -1595,7 +1601,7 @@ pub enum Appearance { Meterchunk, /// The "arrowed" part of the dropdown button that open up a dropdown list. #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")] - MozMenulistButton, + MozMenulistArrowButton, /// For HTML's <input type=number> NumberInput, /// A horizontal progress bar. @@ -1624,7 +1630,7 @@ pub enum Appearance { RadioLabel, /// nsRangeFrame and its subparts Range, - RangeThumb, + RangeThumb, // FIXME: This should not be exposed to content. /// The resizer background area in a status bar for the resizer widget in /// the corner of a window. #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")] @@ -1850,6 +1856,14 @@ pub enum Appearance { Count, } +impl Appearance { + /// Returns whether we're the `none` value. + #[inline] + pub fn is_none(self) -> bool { + self == Appearance::None + } +} + /// A kind of break between two boxes. /// /// https://drafts.csswg.org/css-break/#break-between diff --git a/components/style/values/specified/calc.rs b/components/style/values/specified/calc.rs index 9736491adce..9947fc7a8cc 100644 --- a/components/style/values/specified/calc.rs +++ b/components/style/values/specified/calc.rs @@ -7,15 +7,16 @@ //! [calc]: https://drafts.csswg.org/css-values/#calc-notation use crate::parser::ParserContext; -use crate::values::computed; +use crate::values::generics::calc as generic; +use crate::values::generics::calc::{MinMaxOp, SortKey}; use crate::values::specified::length::ViewportPercentageLength; use crate::values::specified::length::{AbsoluteLength, FontRelativeLength, NoCalcLength}; use crate::values::specified::{self, Angle, Time}; use crate::values::{CSSFloat, CSSInteger}; use cssparser::{AngleOrNumber, CowRcStr, NumberOrPercentage, Parser, Token}; use smallvec::SmallVec; +use std::cmp; use std::fmt::{self, Write}; -use std::{cmp, mem}; use style_traits::values::specified::AllowedNumericType; use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss}; @@ -32,40 +33,9 @@ pub enum MathFunction { Clamp, } -/// This determines the order in which we serialize members of a calc() -/// sum. -/// -/// See https://drafts.csswg.org/css-values-4/#sort-a-calculations-children -#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] -enum SortKey { - Number, - Percentage, - Ch, - Deg, - Em, - Ex, - Px, - Rem, - Sec, - Vh, - Vmax, - Vmin, - Vw, - Other, -} - -/// Whether we're a `min` or `max` function. -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum MinMaxOp { - /// `min()` - Min, - /// `max()` - Max, -} - -/// A node inside a `Calc` expression's AST. -#[derive(Clone, Debug, PartialEq)] -pub enum CalcNode { +/// A leaf node inside a `Calc` expression's AST. +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)] +pub enum Leaf { /// `<length>` Length(NoCalcLength), /// `<angle>` @@ -76,27 +46,28 @@ pub enum CalcNode { Percentage(CSSFloat), /// `<number>` Number(CSSFloat), - /// An expression of the form `x + y + ...`. Subtraction is represented by - /// the negated expression of the right hand side. - Sum(Box<[CalcNode]>), - /// A `min()` / `max()` function. - MinMax(Box<[CalcNode]>, MinMaxOp), - /// A `clamp()` function. - Clamp { - /// The minimum value. - min: Box<CalcNode>, - /// The central value. - center: Box<CalcNode>, - /// The maximum value. - max: Box<CalcNode>, - }, +} + +impl ToCss for Leaf { + fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result + where + W: Write, + { + match *self { + Self::Length(ref l) => l.to_css(dest), + Self::Number(ref n) => n.to_css(dest), + Self::Percentage(p) => crate::values::serialize_percentage(p, dest), + Self::Angle(ref a) => a.to_css(dest), + Self::Time(ref t) => t.to_css(dest), + } + } } /// An expected unit we intend to parse within a `calc()` expression. /// /// This is used as a hint for the parser to fast-reject invalid expressions. #[derive(Clone, Copy, PartialEq)] -pub enum CalcUnit { +enum CalcUnit { /// `<number>` Number, /// `<length>` @@ -117,178 +88,50 @@ pub enum CalcUnit { /// relative lengths, and to_computed_pixel_length_without_context() handles /// this case. Therefore, if you want to add a new field, please make sure this /// function work properly. -#[derive(Clone, Copy, Debug, Default, MallocSizeOf, PartialEq, ToShmem)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)] #[allow(missing_docs)] pub struct CalcLengthPercentage { + #[css(skip)] pub clamping_mode: AllowedNumericType, - pub absolute: Option<AbsoluteLength>, - pub vw: Option<CSSFloat>, - pub vh: Option<CSSFloat>, - pub vmin: Option<CSSFloat>, - pub vmax: Option<CSSFloat>, - pub em: Option<CSSFloat>, - pub ex: Option<CSSFloat>, - pub ch: Option<CSSFloat>, - pub rem: Option<CSSFloat>, - pub percentage: Option<computed::Percentage>, -} - -impl ToCss for CalcLengthPercentage { - /// <https://drafts.csswg.org/css-values/#calc-serialize> - /// - /// FIXME(emilio): Should this simplify away zeros? - #[allow(unused_assignments)] - fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result - where - W: Write, - { - use num_traits::Zero; - - let mut first_value = true; - macro_rules! first_value_check { - ($val:expr) => { - if !first_value { - dest.write_str(if $val < Zero::zero() { " - " } else { " + " })?; - } else if $val < Zero::zero() { - dest.write_str("-")?; - } - first_value = false; - }; - } - - macro_rules! serialize { - ( $( $val:ident ),* ) => { - $( - if let Some(val) = self.$val { - first_value_check!(val); - val.abs().to_css(dest)?; - dest.write_str(stringify!($val))?; - } - )* - }; - } - - macro_rules! serialize_abs { - ( $( $val:ident ),+ ) => { - $( - if let Some(AbsoluteLength::$val(v)) = self.absolute { - first_value_check!(v); - AbsoluteLength::$val(v.abs()).to_css(dest)?; - } - )+ - }; - } - - dest.write_str("calc(")?; - - // NOTE(emilio): Percentages first because of web-compat problems, see: - // https://github.com/w3c/csswg-drafts/issues/1731 - if let Some(val) = self.percentage { - first_value_check!(val.0); - val.abs().to_css(dest)?; - } - - // NOTE(emilio): The order here it's very intentional, and alphabetic - // per the spec linked above. - serialize!(ch); - serialize_abs!(Cm); - serialize!(em, ex); - serialize_abs!(In, Mm, Pc, Pt, Px, Q); - serialize!(rem, vh, vmax, vmin, vw); - - dest.write_str(")") - } + pub node: CalcNode, } impl SpecifiedValueInfo for CalcLengthPercentage {} -macro_rules! impl_generic_to_type { - ($self:ident, $self_variant:ident, $to_self:ident, $to_float:ident, $from_float:path) => {{ - if let Self::$self_variant(ref v) = *$self { - return Ok(v.clone()); - } - - Ok(match *$self { - Self::Sum(ref expressions) => { - let mut sum = 0.; - for sub in &**expressions { - sum += sub.$to_self()?.$to_float(); - } - $from_float(sum) - }, - Self::Clamp { - ref min, - ref center, - ref max, - } => { - let min = min.$to_self()?; - let center = center.$to_self()?; - let max = max.$to_self()?; - - // Equivalent to cmp::max(min, cmp::min(center, max)) - // - // But preserving units when appropriate. - let center_float = center.$to_float(); - let min_float = min.$to_float(); - let max_float = max.$to_float(); - - let mut result = center; - let mut result_float = center_float; - - if result_float > max_float { - result = max; - result_float = max_float; - } +impl PartialOrd for Leaf { + fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { + use self::Leaf::*; - if result_float < min_float { - min - } else { - result - } - }, - Self::MinMax(ref nodes, op) => { - let mut result = nodes[0].$to_self()?; - let mut result_float = result.$to_float(); - for node in nodes.iter().skip(1) { - let candidate = node.$to_self()?; - let candidate_float = candidate.$to_float(); - let candidate_wins = match op { - MinMaxOp::Min => candidate_float < result_float, - MinMaxOp::Max => candidate_float > result_float, - }; - if candidate_wins { - result = candidate; - result_float = candidate_float; - } - } - result - }, - Self::Length(..) | - Self::Angle(..) | - Self::Time(..) | - Self::Percentage(..) | - Self::Number(..) => return Err(()), - }) - }}; -} + if std::mem::discriminant(self) != std::mem::discriminant(other) { + return None; + } -impl PartialOrd for CalcNode { - fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { - use self::CalcNode::*; match (self, other) { (&Length(ref one), &Length(ref other)) => one.partial_cmp(other), (&Percentage(ref one), &Percentage(ref other)) => one.partial_cmp(other), (&Angle(ref one), &Angle(ref other)) => one.degrees().partial_cmp(&other.degrees()), (&Time(ref one), &Time(ref other)) => one.seconds().partial_cmp(&other.seconds()), (&Number(ref one), &Number(ref other)) => one.partial_cmp(other), - _ => None, + _ => { + match *self { + Length(..) | Percentage(..) | Angle(..) | Time(..) | Number(..) => {}, + } + unsafe { + debug_unreachable!("Forgot a branch?"); + } + }, } } } -impl CalcNode { - fn negate(&mut self) { - self.mul_by(-1.); +impl generic::CalcNodeLeaf for Leaf { + fn is_negative(&self) -> bool { + match *self { + Self::Length(ref l) => l.is_negative(), + Self::Percentage(n) | Self::Number(n) => n < 0., + Self::Angle(ref a) => a.degrees() < 0., + Self::Time(ref t) => t.seconds() < 0., + } } fn mul_by(&mut self, scalar: f32) { @@ -310,44 +153,10 @@ impl CalcNode { Self::Percentage(ref mut p) => { *p *= scalar; }, - // Multiplication is distributive across this. - Self::Sum(ref mut children) => { - for node in &mut **children { - node.mul_by(scalar); - } - }, - // This one is a bit trickier. - Self::MinMax(ref mut children, ref mut op) => { - for node in &mut **children { - node.mul_by(scalar); - } - - // For negatives we need to invert the operation. - if scalar < 0. { - *op = match *op { - MinMaxOp::Min => MinMaxOp::Max, - MinMaxOp::Max => MinMaxOp::Min, - } - } - }, - // Multiplication is distributive across these. - Self::Clamp { - ref mut min, - ref mut center, - ref mut max, - } => { - min.mul_by(scalar); - center.mul_by(scalar); - max.mul_by(scalar); - // For negatives we need to swap min / max. - if scalar < 0. { - mem::swap(min, max); - } - }, } } - fn calc_node_sort_key(&self) -> SortKey { + fn sort_key(&self) -> SortKey { match *self { Self::Number(..) => SortKey::Number, Self::Percentage(..) => SortKey::Percentage, @@ -369,7 +178,12 @@ impl CalcNode { }, NoCalcLength::ServoCharacterWidth(..) => unreachable!(), }, - Self::Sum(..) | Self::MinMax(..) | Self::Clamp { .. } => SortKey::Other, + } + } + + fn simplify(&mut self) { + if let Self::Length(NoCalcLength::Absolute(ref mut abs)) = *self { + *abs = AbsoluteLength::Px(abs.to_px()); } } @@ -378,7 +192,11 @@ impl CalcNode { /// Only handles leaf nodes, it's the caller's responsibility to simplify /// them before calling this if needed. fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()> { - use self::CalcNode::*; + use self::Leaf::*; + + if std::mem::discriminant(self) != std::mem::discriminant(other) { + return Err(()); + } match (self, other) { (&mut Number(ref mut one), &Number(ref other)) | @@ -394,170 +212,24 @@ impl CalcNode { (&mut Length(ref mut one), &Length(ref other)) => { *one = one.try_sum(other)?; }, - _ => return Err(()), - } - - Ok(()) - } - - /// Simplifies and sorts the calculation. This is only needed if it's going - /// to be preserved after parsing (so, for `<length-percentage>`). Otherwise - /// we can just evaluate it and we'll come up with a simplified value - /// anyways. - fn simplify_and_sort_children(&mut self) { - macro_rules! replace_self_with { - ($slot:expr) => {{ - let result = mem::replace($slot, Self::Number(0.)); - mem::replace(self, result); - }}; - } - match *self { - Self::Clamp { - ref mut min, - ref mut center, - ref mut max, - } => { - min.simplify_and_sort_children(); - center.simplify_and_sort_children(); - max.simplify_and_sort_children(); - - // NOTE: clamp() is max(min, min(center, max)) - let min_cmp_center = match min.partial_cmp(¢er) { - Some(o) => o, - None => return, - }; - - // So if we can prove that min is more than center, then we won, - // as that's what we should always return. - if matches!(min_cmp_center, cmp::Ordering::Greater) { - return replace_self_with!(&mut **min); - } - - // Otherwise try with max. - let max_cmp_center = match max.partial_cmp(¢er) { - Some(o) => o, - None => return, - }; - - if matches!(max_cmp_center, cmp::Ordering::Less) { - // max is less than center, so we need to return effectively - // `max(min, max)`. - let max_cmp_min = match max.partial_cmp(&min) { - Some(o) => o, - None => { - debug_assert!( - false, - "We compared center with min and max, how are \ - min / max not comparable with each other?" - ); - return; - }, - }; - - if matches!(max_cmp_min, cmp::Ordering::Less) { - return replace_self_with!(&mut **min); - } - - return replace_self_with!(&mut **max); - } - - // Otherwise we're the center node. - return replace_self_with!(&mut **center); - }, - Self::MinMax(ref mut children, op) => { - for child in &mut **children { - child.simplify_and_sort_children(); - } - - let winning_order = match op { - MinMaxOp::Min => cmp::Ordering::Less, - MinMaxOp::Max => cmp::Ordering::Greater, - }; - - let mut result = 0; - for i in 1..children.len() { - let o = match children[i].partial_cmp(&children[result]) { - // We can't compare all the children, so we can't - // know which one will actually win. Bail out and - // keep ourselves as a min / max function. - // - // TODO: Maybe we could simplify compatible children, - // see https://github.com/w3c/csswg-drafts/issues/4756 - None => return, - Some(o) => o, - }; - - if o == winning_order { - result = i; - } - } - - replace_self_with!(&mut children[result]); - }, - Self::Sum(ref mut children_slot) => { - let mut sums_to_merge = SmallVec::<[_; 3]>::new(); - let mut extra_kids = 0; - for (i, child) in children_slot.iter_mut().enumerate() { - child.simplify_and_sort_children(); - if let Self::Sum(ref mut children) = *child { - extra_kids += children.len(); - sums_to_merge.push(i); - } - } - - // If we only have one kid, we've already simplified it, and it - // doesn't really matter whether it's a sum already or not, so - // lift it up and continue. - if children_slot.len() == 1 { - return replace_self_with!(&mut children_slot[0]); - } - - let mut children = mem::replace(children_slot, Box::new([])).into_vec(); - - if !sums_to_merge.is_empty() { - children.reserve(extra_kids - sums_to_merge.len()); - // Merge all our nested sums, in reverse order so that the - // list indices are not invalidated. - for i in sums_to_merge.drain(..).rev() { - let kid_children = match children.swap_remove(i) { - Self::Sum(c) => c, - _ => unreachable!(), - }; - - // This would be nicer with - // https://github.com/rust-lang/rust/issues/59878 fixed. - children.extend(kid_children.into_vec()); - } - } - - debug_assert!(children.len() >= 2, "Should still have multiple kids!"); - - // Sort by spec order. - children.sort_unstable_by_key(|c| c.calc_node_sort_key()); - - // NOTE: if the function returns true, by the docs of dedup_by, - // a is removed. - children.dedup_by(|a, b| b.try_sum_in_place(a).is_ok()); - - if children.len() == 1 { - // If only one children remains, lift it up, and carry on. - replace_self_with!(&mut children[0]); - } else { - // Else put our simplified children back. - mem::replace(children_slot, children.into_boxed_slice()); + _ => { + match *other { + Number(..) | Percentage(..) | Angle(..) | Time(..) | Length(..) => {}, } - }, - Self::Length(ref mut len) => { - if let NoCalcLength::Absolute(ref mut absolute_length) = *len { - *absolute_length = AbsoluteLength::Px(absolute_length.to_px()); + unsafe { + debug_unreachable!(); } }, - Self::Percentage(..) | Self::Angle(..) | Self::Time(..) | Self::Number(..) => { - // These are leaves already, nothing to do. - }, } + + Ok(()) } +} + +/// A calc node representation for specified values. +pub type CalcNode = generic::GenericCalcNode<Leaf>; +impl CalcNode { /// Tries to parse a single element in the expression, that is, a /// `<length>`, `<angle>`, `<time>`, `<percentage>`, according to /// `expected_unit`. @@ -571,7 +243,7 @@ impl CalcNode { ) -> Result<Self, ParseError<'i>> { let location = input.current_source_location(); match (input.next()?, expected_unit) { - (&Token::Number { value, .. }, _) => Ok(CalcNode::Number(value)), + (&Token::Number { value, .. }, _) => Ok(CalcNode::Leaf(Leaf::Number(value))), ( &Token::Dimension { value, ref unit, .. @@ -583,18 +255,22 @@ impl CalcNode { value, ref unit, .. }, CalcUnit::LengthPercentage, - ) => NoCalcLength::parse_dimension(context, value, unit) - .map(CalcNode::Length) - .map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError)), + ) => match NoCalcLength::parse_dimension(context, value, unit) { + Ok(l) => Ok(CalcNode::Leaf(Leaf::Length(l))), + Err(()) => Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)), + }, ( &Token::Dimension { value, ref unit, .. }, CalcUnit::Angle, ) => { - Angle::parse_dimension(value, unit, /* from_calc = */ true) - .map(CalcNode::Angle) - .map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + match Angle::parse_dimension(value, unit, /* from_calc = */ true) { + Ok(a) => Ok(CalcNode::Leaf(Leaf::Angle(a))), + Err(()) => { + Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + }, + } }, ( &Token::Dimension { @@ -602,13 +278,16 @@ impl CalcNode { }, CalcUnit::Time, ) => { - Time::parse_dimension(value, unit, /* from_calc = */ true) - .map(CalcNode::Time) - .map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + match Time::parse_dimension(value, unit, /* from_calc = */ true) { + Ok(t) => Ok(CalcNode::Leaf(Leaf::Time(t))), + Err(()) => { + Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + }, + } }, (&Token::Percentage { unit_value, .. }, CalcUnit::LengthPercentage) | (&Token::Percentage { unit_value, .. }, CalcUnit::Percentage) => { - Ok(CalcNode::Percentage(unit_value)) + Ok(CalcNode::Leaf(Leaf::Percentage(unit_value))) }, (&Token::ParenthesisBlock, _) => input.parse_nested_block(|input| { CalcNode::parse_argument(context, input, expected_unit) @@ -654,11 +333,9 @@ impl CalcNode { // // Consider adding an API to cssparser to specify the // initial vector capacity? - let arguments = input - .parse_comma_separated(|input| { - Self::parse_argument(context, input, expected_unit) - })? - .into_boxed_slice(); + let arguments = input.parse_comma_separated(|input| { + Self::parse_argument(context, input, expected_unit) + })?; let op = match function { MathFunction::Min => MinMaxOp::Min, @@ -666,7 +343,7 @@ impl CalcNode { _ => unreachable!(), }; - Ok(Self::MinMax(arguments, op)) + Ok(Self::MinMax(arguments.into(), op)) }, } }) @@ -712,7 +389,7 @@ impl CalcNode { Ok(if sum.len() == 1 { sum.drain(..).next().unwrap() } else { - Self::Sum(sum.into_boxed_slice()) + Self::Sum(sum.into_boxed_slice().into()) }) } @@ -773,106 +450,64 @@ impl CalcNode { Ok(node) } - /// Tries to simplify this expression into a `<length>` or `<percentage`> + /// Tries to simplify this expression into a `<length>` or `<percentage>` /// value. - fn to_length_or_percentage( - &mut self, + fn into_length_or_percentage( + mut self, clamping_mode: AllowedNumericType, ) -> Result<CalcLengthPercentage, ()> { - let mut ret = CalcLengthPercentage { - clamping_mode, - ..Default::default() - }; - self.simplify_and_sort_children(); - self.add_length_or_percentage_to(&mut ret, 1.0)?; - Ok(ret) - } + // Keep track of whether there's any invalid member of the calculation, + // so as to reject the calculation properly at parse-time. + let mut any_invalid = false; + self.visit_depth_first(|node| { + if let CalcNode::Leaf(ref l) = *node { + any_invalid |= !matches!(*l, Leaf::Percentage(..) | Leaf::Length(..)); + } + node.simplify_and_sort_direct_children(); + }); - /// Puts this `<length>` or `<percentage>` into `ret`, or error. - /// - /// `factor` is the sign or multiplicative factor to account for the sign - /// (this allows adding and substracting into the return value). - fn add_length_or_percentage_to( - &self, - ret: &mut CalcLengthPercentage, - factor: CSSFloat, - ) -> Result<(), ()> { - match *self { - CalcNode::Percentage(pct) => { - ret.percentage = Some(computed::Percentage( - ret.percentage.map_or(0., |p| p.0) + pct * factor, - )); - }, - CalcNode::Length(ref l) => match *l { - NoCalcLength::Absolute(abs) => { - ret.absolute = Some(match ret.absolute { - Some(value) => value + abs * factor, - None => abs * factor, - }); - }, - NoCalcLength::FontRelative(rel) => match rel { - FontRelativeLength::Em(em) => { - ret.em = Some(ret.em.unwrap_or(0.) + em * factor); - }, - FontRelativeLength::Ex(ex) => { - ret.ex = Some(ret.ex.unwrap_or(0.) + ex * factor); - }, - FontRelativeLength::Ch(ch) => { - ret.ch = Some(ret.ch.unwrap_or(0.) + ch * factor); - }, - FontRelativeLength::Rem(rem) => { - ret.rem = Some(ret.rem.unwrap_or(0.) + rem * factor); - }, - }, - NoCalcLength::ViewportPercentage(rel) => match rel { - ViewportPercentageLength::Vh(vh) => { - ret.vh = Some(ret.vh.unwrap_or(0.) + vh * factor) - }, - ViewportPercentageLength::Vw(vw) => { - ret.vw = Some(ret.vw.unwrap_or(0.) + vw * factor) - }, - ViewportPercentageLength::Vmax(vmax) => { - ret.vmax = Some(ret.vmax.unwrap_or(0.) + vmax * factor) - }, - ViewportPercentageLength::Vmin(vmin) => { - ret.vmin = Some(ret.vmin.unwrap_or(0.) + vmin * factor) - }, - }, - NoCalcLength::ServoCharacterWidth(..) => unreachable!(), - }, - CalcNode::Sum(ref children) => { - for child in &**children { - child.add_length_or_percentage_to(ret, factor)?; - } - }, - CalcNode::MinMax(..) | CalcNode::Clamp { .. } => { - // FIXME(emilio): Implement min/max/clamp for length-percentage. - return Err(()); - }, - CalcNode::Angle(..) | CalcNode::Time(..) | CalcNode::Number(..) => return Err(()), + if any_invalid { + return Err(()); } - Ok(()) + Ok(CalcLengthPercentage { + clamping_mode, + node: self, + }) } /// Tries to simplify this expression into a `<time>` value. fn to_time(&self) -> Result<Time, ()> { - impl_generic_to_type!(self, Time, to_time, seconds, Time::from_calc) + let seconds = self.resolve(|leaf| match *leaf { + Leaf::Time(ref t) => Ok(t.seconds()), + _ => Err(()), + })?; + Ok(Time::from_calc(seconds)) } /// Tries to simplify this expression into an `Angle` value. fn to_angle(&self) -> Result<Angle, ()> { - impl_generic_to_type!(self, Angle, to_angle, degrees, Angle::from_calc) + let degrees = self.resolve(|leaf| match *leaf { + Leaf::Angle(ref angle) => Ok(angle.degrees()), + _ => Err(()), + })?; + Ok(Angle::from_calc(degrees)) } /// Tries to simplify this expression into a `<number>` value. fn to_number(&self) -> Result<CSSFloat, ()> { - impl_generic_to_type!(self, Number, to_number, clone, From::from) + self.resolve(|leaf| match *leaf { + Leaf::Number(n) => Ok(n), + _ => Err(()), + }) } /// Tries to simplify this expression into a `<percentage>` value. fn to_percentage(&self) -> Result<CSSFloat, ()> { - impl_generic_to_type!(self, Percentage, to_percentage, clone, From::from) + self.resolve(|leaf| match *leaf { + Leaf::Percentage(p) => Ok(p), + _ => Err(()), + }) } /// Given a function name, and the location from where the token came from, @@ -926,7 +561,7 @@ impl CalcNode { function: MathFunction, ) -> Result<CalcLengthPercentage, ParseError<'i>> { Self::parse(context, input, function, CalcUnit::LengthPercentage)? - .to_length_or_percentage(clamping_mode) + .into_length_or_percentage(clamping_mode) .map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) } @@ -949,7 +584,7 @@ impl CalcNode { function: MathFunction, ) -> Result<CalcLengthPercentage, ParseError<'i>> { Self::parse(context, input, function, CalcUnit::Length)? - .to_length_or_percentage(clamping_mode) + .into_length_or_percentage(clamping_mode) .map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) } diff --git a/components/style/values/specified/color.rs b/components/style/values/specified/color.rs index be969f27cd4..e697f2523c9 100644 --- a/components/style/values/specified/color.rs +++ b/components/style/values/specified/color.rs @@ -140,8 +140,10 @@ pub enum SystemColor { Windowframe, Windowtext, MozButtondefault, - MozDefaultColor, - MozDefaultBackgroundColor, + #[parse(aliases = "-moz-default-color")] + Canvastext, + #[parse(aliases = "-moz-default-background-color")] + Canvas, MozDialog, MozDialogtext, /// Used to highlight valid regions to drop something onto. @@ -230,9 +232,12 @@ pub enum SystemColor { /// colors. MozNativehyperlinktext, - MozHyperlinktext, - MozActivehyperlinktext, - MozVisitedhyperlinktext, + #[parse(aliases = "-moz-hyperlinktext")] + Linktext, + #[parse(aliases = "-moz-activehyperlinktext")] + Activetext, + #[parse(aliases = "-moz-visitedhyperlinktext")] + Visitedtext, /// Combobox widgets MozComboboxtext, @@ -253,11 +258,11 @@ impl SystemColor { let prefs = cx.device().pref_sheet_prefs(); convert_nscolor_to_computedcolor(match *self { - SystemColor::MozDefaultColor => prefs.mDefaultColor, - SystemColor::MozDefaultBackgroundColor => prefs.mDefaultBackgroundColor, - SystemColor::MozHyperlinktext => prefs.mLinkColor, - SystemColor::MozActivehyperlinktext => prefs.mActiveLinkColor, - SystemColor::MozVisitedhyperlinktext => prefs.mVisitedLinkColor, + SystemColor::Canvastext => prefs.mDefaultColor, + SystemColor::Canvas => prefs.mDefaultBackgroundColor, + SystemColor::Linktext => prefs.mLinkColor, + SystemColor::Activetext => prefs.mActiveLinkColor, + SystemColor::Visitedtext => prefs.mVisitedLinkColor, _ => unsafe { bindings::Gecko_GetLookAndFeelSystemColor(*self as i32, cx.device().document()) diff --git a/components/style/values/specified/font.rs b/components/style/values/specified/font.rs index 94c28d068f9..dd9f9d3b86d 100644 --- a/components/style/values/specified/font.rs +++ b/components/style/values/specified/font.rs @@ -492,7 +492,9 @@ impl ToComputedValue for FontStretch { SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, + ToComputedValue, ToCss, + ToResolvedValue, ToShmem, )] #[allow(missing_docs)] @@ -534,7 +536,9 @@ impl Default for KeywordSize { PartialEq, ToAnimatedValue, ToAnimatedZero, + ToComputedValue, ToCss, + ToResolvedValue, ToShmem, )] /// Additional information for keyword-derived font sizes. @@ -567,7 +571,7 @@ impl KeywordInfo { /// Computes the final size for this font-size keyword, accounting for /// text-zoom. fn to_computed_value(&self, context: &Context) -> CSSPixelLength { - let base = context.maybe_zoom_text(self.kw.to_computed_value(context).0); + let base = context.maybe_zoom_text(self.kw.to_length(context).0); base * self.factor + context.maybe_zoom_text(self.offset) } @@ -760,11 +764,10 @@ const LARGER_FONT_SIZE_RATIO: f32 = 1.2; /// The default font size. pub const FONT_MEDIUM_PX: i32 = 16; -#[cfg(feature = "servo")] -impl ToComputedValue for KeywordSize { - type ComputedValue = NonNegativeLength; +impl KeywordSize { #[inline] - fn to_computed_value(&self, _: &Context) -> NonNegativeLength { + #[cfg(feature = "servo")] + fn to_length(&self, _: &Context) -> NonNegativeLength { let medium = Length::new(FONT_MEDIUM_PX as f32); // https://drafts.csswg.org/css-fonts-3/#font-size-prop NonNegative(match *self { @@ -779,17 +782,9 @@ impl ToComputedValue for KeywordSize { }) } + #[cfg(feature = "gecko")] #[inline] - fn from_computed_value(_: &NonNegativeLength) -> Self { - unreachable!() - } -} - -#[cfg(feature = "gecko")] -impl ToComputedValue for KeywordSize { - type ComputedValue = NonNegativeLength; - #[inline] - fn to_computed_value(&self, cx: &Context) -> NonNegativeLength { + fn to_length(&self, cx: &Context) -> NonNegativeLength { use crate::context::QuirksMode; // The tables in this function are originally from @@ -857,11 +852,6 @@ impl ToComputedValue for KeywordSize { base_size * FONT_SIZE_FACTORS[html_size] as f32 / 100.0 }) } - - #[inline] - fn from_computed_value(_: &NonNegativeLength) -> Self { - unreachable!() - } } impl FontSize { diff --git a/components/style/values/specified/grid.rs b/components/style/values/specified/grid.rs index 4830aea24d6..54d31d5826d 100644 --- a/components/style/values/specified/grid.rs +++ b/components/style/values/specified/grid.rs @@ -185,16 +185,6 @@ impl TrackRepeat<LengthPercentage, Integer> { values.push(track_size); names.push(current_names); - if is_auto { - // FIXME: In the older version of the spec - // (https://www.w3.org/TR/2015/WD-css-grid-1-20150917/#typedef-auto-repeat), - // if the repeat type is `<auto-repeat>` we shouldn't try to parse more than - // one `TrackSize`. But in current version of the spec, this is deprecated - // but we are adding this for gecko parity. We should remove this when - // gecko implements new spec. - names.push(input.try(parse_line_names).unwrap_or_default()); - break; - } } else { if values.is_empty() { // expecting at least one <track-size> diff --git a/components/style/values/specified/image.rs b/components/style/values/specified/image.rs index 14a2a9ad9c8..59250c45a6f 100644 --- a/components/style/values/specified/image.rs +++ b/components/style/values/specified/image.rs @@ -19,7 +19,8 @@ use crate::values::specified::position::{HorizontalPositionKeyword, VerticalPosi use crate::values::specified::position::{Position, PositionComponent, Side}; use crate::values::specified::url::SpecifiedImageUrl; use crate::values::specified::{ - Angle, Color, Length, LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage, + Angle, AngleOrPercentage, Color, Length, LengthPercentage, NonNegativeLength, + NonNegativeLengthPercentage, }; use crate::values::specified::{Number, NumberOrPercentage, Percentage}; use crate::Atom; @@ -32,24 +33,6 @@ use std::fmt::{self, Write}; use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError}; use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss}; -/// A specified image layer. -pub type ImageLayer = generic::GenericImageLayer<Image>; - -impl ImageLayer { - /// This is a specialization of Either with an alternative parse - /// method to provide anonymous CORS headers for the Image url fetch. - pub fn parse_with_cors_anonymous<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result<Self, ParseError<'i>> { - if let Ok(v) = input.try(|i| Image::parse_with_cors_anonymous(context, i)) { - return Ok(generic::GenericImageLayer::Image(v)); - } - input.expect_ident_matching("none")?; - Ok(generic::GenericImageLayer::None) - } -} - /// Specified values for an image according to CSS-IMAGES. /// <https://drafts.csswg.org/css-images/#image-values> pub type Image = generic::Image<Gradient, MozImageRect, SpecifiedImageUrl>; @@ -62,9 +45,23 @@ pub type Gradient = generic::Gradient< NonNegativeLength, NonNegativeLengthPercentage, Position, + Angle, + AngleOrPercentage, Color, >; +type LengthPercentageItemList = crate::OwnedSlice<generic::GradientItem<Color, LengthPercentage>>; + +#[cfg(feature = "gecko")] +fn conic_gradients_enabled() -> bool { + static_prefs::pref!("layout.css.conic-gradient.enabled") +} + +#[cfg(feature = "servo")] +fn conic_gradients_enabled() -> bool { + false +} + impl SpecifiedValueInfo for Gradient { const SUPPORTED_TYPES: u8 = CssType::GRADIENT; @@ -85,13 +82,13 @@ impl SpecifiedValueInfo for Gradient { "-moz-repeating-radial-gradient", "-webkit-gradient", ]); + + if conic_gradients_enabled() { + f(&["conic-gradient", "repeating-conic-gradient"]); + } } } -/// A specified gradient kind. -pub type GradientKind = - generic::GradientKind<LineDirection, NonNegativeLength, NonNegativeLengthPercentage, Position>; - /// A specified gradient line direction. /// /// FIXME(emilio): This should be generic over Angle. @@ -110,16 +107,10 @@ pub enum LineDirection { /// A specified ending shape. pub type EndingShape = generic::EndingShape<NonNegativeLength, NonNegativeLengthPercentage>; -/// A specified gradient item. -pub type GradientItem = generic::GradientItem<Color, LengthPercentage>; - -/// A computed color stop. -pub type ColorStop = generic::ColorStop<Color, LengthPercentage>; - /// Specified values for `moz-image-rect` /// -moz-image-rect(<uri>, top, right, bottom, left); -#[cfg(feature = "gecko")] -pub type MozImageRect = generic::MozImageRect<NumberOrPercentage, SpecifiedImageUrl>; +#[cfg(all(feature = "gecko", not(feature = "cbindgen")))] +pub type MozImageRect = generic::GenericMozImageRect<NumberOrPercentage, SpecifiedImageUrl>; #[cfg(not(feature = "gecko"))] #[derive( @@ -141,6 +132,9 @@ impl Parse for Image { context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Image, ParseError<'i>> { + if input.try(|i| i.expect_ident_matching("none")).is_ok() { + return Ok(generic::Image::None); + } if let Ok(url) = input.try(|input| SpecifiedImageUrl::parse(context, input)) { return Ok(generic::Image::Url(url)); } @@ -211,10 +205,11 @@ impl Parse for Gradient { enum Shape { Linear, Radial, + Conic, } let func = input.expect_function()?; - let (shape, repeating, mut compat_mode) = match_ignore_ascii_case! { &func, + let (shape, repeating, compat_mode) = match_ignore_ascii_case! { &func, "linear-gradient" => { (Shape::Linear, false, GradientCompatMode::Modern) }, @@ -255,6 +250,12 @@ impl Parse for Gradient { "-moz-repeating-radial-gradient" => { (Shape::Radial, true, GradientCompatMode::Moz) }, + "conic-gradient" if conic_gradients_enabled() => { + (Shape::Conic, false, GradientCompatMode::Modern) + }, + "repeating-conic-gradient" if conic_gradients_enabled() => { + (Shape::Conic, true, GradientCompatMode::Modern) + }, "-webkit-gradient" => { return input.parse_nested_block(|i| { Self::parse_webkit_gradient_argument(context, i) @@ -266,25 +267,13 @@ impl Parse for Gradient { } }; - let (kind, items) = input.parse_nested_block(|i| { - let shape = match shape { - Shape::Linear => GradientKind::parse_linear(context, i, &mut compat_mode)?, - Shape::Radial => GradientKind::parse_radial(context, i, &mut compat_mode)?, - }; - let items = GradientItem::parse_comma_separated(context, i)?; - Ok((shape, items)) - })?; - - if items.len() < 2 { - return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); - } - - Ok(Gradient { - items, - repeating, - kind, - compat_mode, - }) + Ok(input.parse_nested_block(|i| { + Ok(match shape { + Shape::Linear => Self::parse_linear(context, i, repeating, compat_mode)?, + Shape::Radial => Self::parse_radial(context, i, repeating, compat_mode)?, + Shape::Conic => Self::parse_conic(context, i, repeating)?, + }) + })?) } } @@ -404,16 +393,21 @@ impl Gradient { let ident = input.expect_ident_cloned()?; input.expect_comma()?; - let (kind, reverse_stops) = match_ignore_ascii_case! { &ident, + Ok(match_ignore_ascii_case! { &ident, "linear" => { let first = Point::parse(context, input)?; input.expect_comma()?; let second = Point::parse(context, input)?; let direction = LineDirection::from_points(first, second); - let kind = generic::GradientKind::Linear(direction); + let items = Gradient::parse_webkit_gradient_stops(context, input, false)?; - (kind, false) + generic::Gradient::Linear { + direction, + items, + repeating: false, + compat_mode: GradientCompatMode::Modern, + } }, "radial" => { let first_point = Point::parse(context, input)?; @@ -433,16 +427,28 @@ impl Gradient { let rad = Circle::Radius(NonNegative(Length::from_px(radius.value))); let shape = generic::EndingShape::Circle(rad); let position: Position = point.into(); - - let kind = generic::GradientKind::Radial(shape, position); - (kind, reverse_stops) + let items = Gradient::parse_webkit_gradient_stops(context, input, reverse_stops)?; + + generic::Gradient::Radial { + shape, + position, + items, + repeating: false, + compat_mode: GradientCompatMode::Modern, + } }, _ => { let e = SelectorParseErrorKind::UnexpectedIdent(ident.clone()); return Err(input.new_custom_error(e)); }, - }; + }) + } + fn parse_webkit_gradient_stops<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + reverse_stops: bool, + ) -> Result<LengthPercentageItemList, ParseError<'i>> { let mut items = input .try(|i| { i.expect_comma()?; @@ -521,46 +527,62 @@ impl Gradient { } }) } + Ok(items.into()) + } - Ok(generic::Gradient { - kind, - items: items.into(), - repeating: false, - compat_mode: GradientCompatMode::Modern, - }) + /// Not used for -webkit-gradient syntax and conic-gradient + fn parse_stops<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result<LengthPercentageItemList, ParseError<'i>> { + let items = + generic::GradientItem::parse_comma_separated(context, input, LengthPercentage::parse)?; + if items.len() < 2 { + return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); + } + Ok(items) } -} -impl GradientKind { /// Parses a linear gradient. /// GradientCompatMode can change during `-moz-` prefixed gradient parsing if it come across a `to` keyword. fn parse_linear<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, - compat_mode: &mut GradientCompatMode, + repeating: bool, + mut compat_mode: GradientCompatMode, ) -> Result<Self, ParseError<'i>> { - let direction = if let Ok(d) = input.try(|i| LineDirection::parse(context, i, compat_mode)) - { - input.expect_comma()?; - d - } else { - match *compat_mode { - GradientCompatMode::Modern => { - LineDirection::Vertical(VerticalPositionKeyword::Bottom) - }, - _ => LineDirection::Vertical(VerticalPositionKeyword::Top), - } - }; - Ok(generic::GradientKind::Linear(direction)) + let direction = + if let Ok(d) = input.try(|i| LineDirection::parse(context, i, &mut compat_mode)) { + input.expect_comma()?; + d + } else { + match compat_mode { + GradientCompatMode::Modern => { + LineDirection::Vertical(VerticalPositionKeyword::Bottom) + }, + _ => LineDirection::Vertical(VerticalPositionKeyword::Top), + } + }; + let items = Gradient::parse_stops(context, input)?; + + Ok(Gradient::Linear { + direction, + items, + repeating, + compat_mode, + }) } + + /// Parses a radial gradient. fn parse_radial<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, - compat_mode: &mut GradientCompatMode, + repeating: bool, + compat_mode: GradientCompatMode, ) -> Result<Self, ParseError<'i>> { - let (shape, position) = match *compat_mode { + let (shape, position) = match compat_mode { GradientCompatMode::Modern => { - let shape = input.try(|i| EndingShape::parse(context, i, *compat_mode)); + let shape = input.try(|i| EndingShape::parse(context, i, compat_mode)); let position = input.try(|i| { i.expect_ident_matching("at")?; Position::parse(context, i) @@ -573,7 +595,7 @@ impl GradientKind { if position.is_ok() { i.expect_comma()?; } - EndingShape::parse(context, i, *compat_mode) + EndingShape::parse(context, i, compat_mode) }); (shape, position.ok()) }, @@ -588,7 +610,54 @@ impl GradientKind { }); let position = position.unwrap_or(Position::center()); - Ok(generic::GradientKind::Radial(shape, position)) + + let items = Gradient::parse_stops(context, input)?; + + Ok(Gradient::Radial { + shape, + position, + items, + repeating, + compat_mode, + }) + } + fn parse_conic<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + repeating: bool, + ) -> Result<Self, ParseError<'i>> { + let angle = input.try(|i| { + i.expect_ident_matching("from")?; + // Spec allows unitless zero start angles + // https://drafts.csswg.org/css-images-4/#valdef-conic-gradient-angle + Angle::parse_with_unitless(context, i) + }); + let position = input.try(|i| { + i.expect_ident_matching("at")?; + Position::parse(context, i) + }); + if angle.is_ok() || position.is_ok() { + input.expect_comma()?; + } + + let angle = angle.unwrap_or(Angle::zero()); + let position = position.unwrap_or(Position::center()); + let items = generic::GradientItem::parse_comma_separated( + context, + input, + AngleOrPercentage::parse_with_unitless, + )?; + + if items.len() < 2 { + return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); + } + + Ok(Gradient::Conic { + angle, + position, + items, + repeating, + }) } } @@ -793,10 +862,12 @@ impl ShapeExtent { } } -impl GradientItem { +impl<T> generic::GradientItem<Color, T> { fn parse_comma_separated<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, + parse_position: impl for<'i1, 't1> Fn(&ParserContext, &mut Parser<'i1, 't1>) -> Result<T, ParseError<'i1>> + + Copy, ) -> Result<crate::OwnedSlice<Self>, ParseError<'i>> { let mut items = Vec::new(); let mut seen_stop = false; @@ -804,20 +875,20 @@ impl GradientItem { loop { input.parse_until_before(Delimiter::Comma, |input| { if seen_stop { - if let Ok(hint) = input.try(|i| LengthPercentage::parse(context, i)) { + if let Ok(hint) = input.try(|i| parse_position(context, i)) { seen_stop = false; items.push(generic::GradientItem::InterpolationHint(hint)); return Ok(()); } } - let stop = ColorStop::parse(context, input)?; + let stop = generic::ColorStop::parse(context, input, parse_position)?; - if let Ok(multi_position) = input.try(|i| LengthPercentage::parse(context, i)) { + if let Ok(multi_position) = input.try(|i| parse_position(context, i)) { let stop_color = stop.color.clone(); items.push(stop.into_item()); items.push( - ColorStop { + generic::ColorStop { color: stop_color, position: Some(multi_position), } @@ -845,14 +916,18 @@ impl GradientItem { } } -impl Parse for ColorStop { +impl<T> generic::ColorStop<Color, T> { fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, + parse_position: impl for<'i1, 't1> Fn( + &ParserContext, + &mut Parser<'i1, 't1>, + ) -> Result<T, ParseError<'i1>>, ) -> Result<Self, ParseError<'i>> { - Ok(ColorStop { + Ok(generic::ColorStop { color: Color::parse(context, input)?, - position: input.try(|i| LengthPercentage::parse(context, i)).ok(), + position: input.try(|i| parse_position(context, i)).ok(), }) } } diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index ff24404c09a..0b1bf0b68a7 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -16,7 +16,7 @@ use crate::values::generics::length::{ GenericLengthOrNumber, GenericLengthPercentageOrNormal, GenericMaxSize, GenericSize, }; use crate::values::generics::NonNegative; -use crate::values::specified::calc::CalcNode; +use crate::values::specified::calc::{self, CalcNode}; use crate::values::specified::NonNegativeNumber; use crate::values::CSSFloat; use crate::Zero; @@ -28,8 +28,8 @@ use std::ops::{Add, Mul}; use style_traits::values::specified::AllowedNumericType; use style_traits::{ParseError, SpecifiedValueInfo, StyleParseErrorKind}; -pub use super::image::{ColorStop, EndingShape as GradientEndingShape, Gradient}; -pub use super::image::{GradientKind, Image}; +pub use super::image::Image; +pub use super::image::{EndingShape as GradientEndingShape, Gradient}; pub use crate::values::specified::calc::CalcLengthPercentage; /// Number of app units per pixel @@ -92,7 +92,16 @@ impl FontRelativeLength { FontRelativeLength::Em(v) | FontRelativeLength::Ex(v) | FontRelativeLength::Ch(v) | - FontRelativeLength::Rem(v) => v == 0.0, + FontRelativeLength::Rem(v) => v == 0., + } + } + + fn is_negative(&self) -> bool { + match *self { + FontRelativeLength::Em(v) | + FontRelativeLength::Ex(v) | + FontRelativeLength::Ch(v) | + FontRelativeLength::Rem(v) => v < 0., } } @@ -266,7 +275,16 @@ impl ViewportPercentageLength { ViewportPercentageLength::Vw(v) | ViewportPercentageLength::Vh(v) | ViewportPercentageLength::Vmin(v) | - ViewportPercentageLength::Vmax(v) => v == 0.0, + ViewportPercentageLength::Vmax(v) => v == 0., + } + } + + fn is_negative(&self) -> bool { + match *self { + ViewportPercentageLength::Vw(v) | + ViewportPercentageLength::Vh(v) | + ViewportPercentageLength::Vmin(v) | + ViewportPercentageLength::Vmax(v) => v < 0., } } @@ -370,6 +388,18 @@ impl AbsoluteLength { } } + fn is_negative(&self) -> bool { + match *self { + AbsoluteLength::Px(v) | + AbsoluteLength::In(v) | + AbsoluteLength::Cm(v) | + AbsoluteLength::Mm(v) | + AbsoluteLength::Q(v) | + AbsoluteLength::Pt(v) | + AbsoluteLength::Pc(v) => v < 0., + } + } + /// Convert this into a pixel value. #[inline] pub fn to_px(&self) -> CSSFloat { @@ -484,6 +514,16 @@ impl Mul<CSSFloat> for NoCalcLength { } impl NoCalcLength { + /// Returns whether the value of this length without unit is less than zero. + pub fn is_negative(&self) -> bool { + match *self { + NoCalcLength::Absolute(v) => v.is_negative(), + NoCalcLength::FontRelative(v) => v.is_negative(), + NoCalcLength::ViewportPercentage(v) => v.is_negative(), + NoCalcLength::ServoCharacterWidth(c) => c.0 < 0, + } + } + /// Parse a given absolute or relative dimension. pub fn parse_dimension( context: &ParserContext, @@ -912,9 +952,10 @@ impl From<Percentage> for LengthPercentage { #[inline] fn from(pc: Percentage) -> Self { if pc.is_calc() { + // FIXME(emilio): Hard-coding the clamping mode is suspect. LengthPercentage::Calc(Box::new(CalcLengthPercentage { - percentage: Some(computed::Percentage(pc.get())), - ..Default::default() + clamping_mode: AllowedNumericType::All, + node: CalcNode::Leaf(calc::Leaf::Percentage(pc.get())), })) } else { LengthPercentage::Percentage(computed::Percentage(pc.get())) diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 54401045809..63af3015386 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -55,8 +55,8 @@ pub use self::font::{FontSize, FontSizeAdjust, FontStretch, FontSynthesis}; pub use self::font::{FontVariantAlternates, FontWeight}; pub use self::font::{FontVariantEastAsian, FontVariationSettings}; pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom}; -pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient}; -pub use self::image::{GradientItem, GradientKind, Image, ImageLayer, MozImageRect}; +pub use self::image::{EndingShape as GradientEndingShape, Gradient}; +pub use self::image::{Image, MozImageRect}; pub use self::length::{AbsoluteLength, CalcLengthPercentage, CharacterWidth}; pub use self::length::{FontRelativeLength, Length, LengthOrNumber, NonNegativeLengthOrNumber}; pub use self::length::{LengthOrAuto, LengthPercentage, LengthPercentageOrAuto}; @@ -80,6 +80,7 @@ pub use self::svg::MozContextProperties; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint}; pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; pub use self::svg_path::SVGPathData; +pub use self::text::TextAlignLast; pub use self::text::TextUnderlinePosition; pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight, TextAlign}; pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle, WordBreak}; diff --git a/components/style/values/specified/percentage.rs b/components/style/values/specified/percentage.rs index 75549dca3be..eac4d91cf8f 100644 --- a/components/style/values/specified/percentage.rs +++ b/components/style/values/specified/percentage.rs @@ -120,9 +120,6 @@ impl Percentage { Token::Function(ref name) => { let function = CalcNode::math_function(name, location)?; let value = CalcNode::parse_percentage(context, input, function)?; - - // TODO(emilio): -moz-image-rect is the only thing that uses - // the clamping mode... I guess we could disallow it... Ok(Percentage { value, calc_clamping_mode: Some(num_context), diff --git a/components/style/values/specified/position.rs b/components/style/values/specified/position.rs index 3f01988e49d..b843de29a41 100644 --- a/components/style/values/specified/position.rs +++ b/components/style/values/specified/position.rs @@ -13,6 +13,7 @@ use crate::str::HTML_SPACE_CHARACTERS; use crate::values::computed::LengthPercentage as ComputedLengthPercentage; use crate::values::computed::{Context, Percentage, ToComputedValue}; use crate::values::generics::position::Position as GenericPosition; +use crate::values::generics::position::PositionComponent as GenericPositionComponent; use crate::values::generics::position::PositionOrAuto as GenericPositionOrAuto; use crate::values::generics::position::ZIndex as GenericZIndex; use crate::values::specified::{AllowQuirks, Integer, LengthPercentage}; @@ -262,6 +263,18 @@ impl<S: Parse> PositionComponent<S> { } } +impl<S> GenericPositionComponent for PositionComponent<S> { + fn is_center(&self) -> bool { + match *self { + PositionComponent::Center => true, + PositionComponent::Length(LengthPercentage::Percentage(ref per)) => per.0 == 0.5, + // 50% from any side is still the center. + PositionComponent::Side(_, Some(LengthPercentage::Percentage(ref per))) => per.0 == 0.5, + _ => false, + } + } +} + impl<S> PositionComponent<S> { /// `0%` pub fn zero() -> Self { @@ -295,10 +308,8 @@ impl<S: Side> ToComputedValue for PositionComponent<S> { }, PositionComponent::Side(ref keyword, Some(ref length)) if !keyword.is_start() => { let length = length.to_computed_value(context); - let p = Percentage(1. - length.percentage()); - let l = -length.unclamped_length(); // We represent `<end-side> <length>` as `calc(100% - <length>)`. - ComputedLengthPercentage::new_calc(l, Some(p), AllowedNumericType::All) + ComputedLengthPercentage::hundred_percent_minus(length, AllowedNumericType::All) }, PositionComponent::Side(_, Some(ref length)) | PositionComponent::Length(ref length) => length.to_computed_value(context), @@ -350,66 +361,25 @@ impl Side for VerticalPositionKeyword { } } -#[derive( - Clone, - Copy, - Debug, - Eq, - MallocSizeOf, - PartialEq, - SpecifiedValueInfo, - ToComputedValue, - ToCss, - ToResolvedValue, - ToShmem, -)] -/// Auto-placement algorithm Option -pub enum AutoFlow { - /// The auto-placement algorithm places items by filling each row in turn, - /// adding new rows as necessary. - Row, - /// The auto-placement algorithm places items by filling each column in turn, - /// adding new columns as necessary. - Column, -} - -/// If `dense` is specified, `row` is implied. -fn is_row_dense(autoflow: &AutoFlow, dense: &bool) -> bool { - *autoflow == AutoFlow::Row && *dense -} - -#[derive( - Clone, - Copy, - Debug, - Eq, - MallocSizeOf, - PartialEq, - SpecifiedValueInfo, - ToComputedValue, - ToCss, - ToResolvedValue, - ToShmem, -)] -/// Controls how the auto-placement algorithm works -/// specifying exactly how auto-placed items get flowed into the grid -pub struct GridAutoFlow { - /// Specifiy how auto-placement algorithm fills each `row` or `column` in turn - #[css(contextual_skip_if = "is_row_dense")] - pub autoflow: AutoFlow, - /// Specify use `dense` packing algorithm or not - #[css(represents_keyword)] - pub dense: bool, -} - -impl GridAutoFlow { - #[inline] - /// Get default `grid-auto-flow` as `row` - pub fn row() -> GridAutoFlow { - GridAutoFlow { - autoflow: AutoFlow::Row, - dense: false, - } +bitflags! { + /// Controls how the auto-placement algorithm works + /// specifying exactly how auto-placed items get flowed into the grid + #[derive( + MallocSizeOf, + SpecifiedValueInfo, + ToComputedValue, + ToResolvedValue, + ToShmem + )] + #[value_info(other_values = "row,column,dense")] + #[repr(C)] + pub struct GridAutoFlow: u8 { + /// 'row' - mutually exclusive with 'column' + const ROW = 1 << 0; + /// 'column' - mutually exclusive with 'row' + const COLUMN = 1 << 1; + /// 'dense' + const DENSE = 1 << 2; } } @@ -419,26 +389,26 @@ impl Parse for GridAutoFlow { _context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<GridAutoFlow, ParseError<'i>> { - let mut value = None; - let mut dense = false; + let mut track = None; + let mut dense = GridAutoFlow::empty(); while !input.is_exhausted() { let location = input.current_source_location(); let ident = input.expect_ident()?; let success = match_ignore_ascii_case! { &ident, - "row" if value.is_none() => { - value = Some(AutoFlow::Row); + "row" if track.is_none() => { + track = Some(GridAutoFlow::ROW); true }, - "column" if value.is_none() => { - value = Some(AutoFlow::Column); + "column" if track.is_none() => { + track = Some(GridAutoFlow::COLUMN); true }, - "dense" if !dense => { - dense = true; + "dense" if dense.is_empty() => { + dense = GridAutoFlow::DENSE; true }, - _ => false + _ => false, }; if !success { return Err(location @@ -446,47 +416,37 @@ impl Parse for GridAutoFlow { } } - if value.is_some() || dense { - Ok(GridAutoFlow { - autoflow: value.unwrap_or(AutoFlow::Row), - dense: dense, - }) + if track.is_some() || !dense.is_empty() { + Ok(track.unwrap_or(GridAutoFlow::ROW) | dense) } else { Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) } } } -#[cfg(feature = "gecko")] -impl From<u8> for GridAutoFlow { - fn from(bits: u8) -> GridAutoFlow { - use crate::gecko_bindings::structs; - - GridAutoFlow { - autoflow: if bits & structs::NS_STYLE_GRID_AUTO_FLOW_ROW as u8 != 0 { - AutoFlow::Row - } else { - AutoFlow::Column - }, - dense: bits & structs::NS_STYLE_GRID_AUTO_FLOW_DENSE as u8 != 0, +impl ToCss for GridAutoFlow { + fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result + where + W: Write, + { + if *self == GridAutoFlow::ROW { + return dest.write_str("row"); } - } -} -#[cfg(feature = "gecko")] -impl From<GridAutoFlow> for u8 { - fn from(v: GridAutoFlow) -> u8 { - use crate::gecko_bindings::structs; + if *self == GridAutoFlow::COLUMN { + return dest.write_str("column"); + } - let mut result: u8 = match v.autoflow { - AutoFlow::Row => structs::NS_STYLE_GRID_AUTO_FLOW_ROW as u8, - AutoFlow::Column => structs::NS_STYLE_GRID_AUTO_FLOW_COLUMN as u8, - }; + if *self == GridAutoFlow::ROW | GridAutoFlow::DENSE { + return dest.write_str("dense"); + } - if v.dense { - result |= structs::NS_STYLE_GRID_AUTO_FLOW_DENSE as u8; + if *self == GridAutoFlow::COLUMN | GridAutoFlow::DENSE { + return dest.write_str("column dense"); } - result + + debug_assert!(false, "Unknown or invalid grid-autoflow value"); + Ok(()) } } @@ -592,7 +552,7 @@ impl TemplateAreas { Ok(TemplateAreas { areas: areas.into(), strings: strings.into(), - width: width, + width, }) } } @@ -642,7 +602,16 @@ impl Parse for TemplateAreasArc { /// A range of rows or columns. Using this instead of std::ops::Range for FFI /// purposes. #[repr(C)] -#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToShmem)] +#[derive( + Clone, + Debug, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToResolvedValue, + ToShmem, +)] pub struct UnsignedRange { /// The start of the range. pub start: u32, @@ -650,7 +619,16 @@ pub struct UnsignedRange { pub end: u32, } -#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToShmem)] +#[derive( + Clone, + Debug, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToResolvedValue, + ToShmem, +)] #[repr(C)] /// Not associated with any particular grid item, but can be referenced from the /// grid-placement properties. diff --git a/components/style/values/specified/svg.rs b/components/style/values/specified/svg.rs index e603ddfda07..cff899fce35 100644 --- a/components/style/values/specified/svg.rs +++ b/components/style/values/specified/svg.rs @@ -21,13 +21,13 @@ use style_traits::{StyleParseErrorKind, ToCss}; pub type SVGPaint = generic::GenericSVGPaint<Color, SpecifiedUrl>; /// <length> | <percentage> | <number> | context-value -pub type SVGLength = generic::SVGLength<LengthPercentage>; +pub type SVGLength = generic::GenericSVGLength<LengthPercentage>; /// A non-negative version of SVGLength. -pub type SVGWidth = generic::SVGLength<NonNegativeLengthPercentage>; +pub type SVGWidth = generic::GenericSVGLength<NonNegativeLengthPercentage>; /// [ <length> | <percentage> | <number> ]# | context-value -pub type SVGStrokeDashArray = generic::SVGStrokeDashArray<NonNegativeLengthPercentage>; +pub type SVGStrokeDashArray = generic::GenericSVGStrokeDashArray<NonNegativeLengthPercentage>; /// Whether the `context-value` value is enabled. #[cfg(feature = "gecko")] diff --git a/components/style/values/specified/svg_path.rs b/components/style/values/specified/svg_path.rs index 288f396b73c..9f1c5c5e32c 100644 --- a/components/style/values/specified/svg_path.rs +++ b/components/style/values/specified/svg_path.rs @@ -159,6 +159,8 @@ impl ComputeSquaredDistance for SVGPathData { Serialize, SpecifiedValueInfo, ToAnimatedZero, + ToComputedValue, + ToResolvedValue, ToShmem, )] #[allow(missing_docs)] @@ -488,6 +490,8 @@ impl ToCss for PathCommand { Serialize, SpecifiedValueInfo, ToAnimatedZero, + ToComputedValue, + ToResolvedValue, ToShmem, )] #[repr(u8)] @@ -518,7 +522,9 @@ impl IsAbsolute { Serialize, SpecifiedValueInfo, ToAnimatedZero, + ToComputedValue, ToCss, + ToResolvedValue, ToShmem, )] #[repr(C)] @@ -534,7 +540,17 @@ impl CoordPair { /// The EllipticalArc flag type. #[derive( - Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, SpecifiedValueInfo, ToShmem, + Clone, + Copy, + Debug, + Deserialize, + MallocSizeOf, + PartialEq, + Serialize, + SpecifiedValueInfo, + ToComputedValue, + ToResolvedValue, + ToShmem, )] #[repr(C)] pub struct ArcFlag(bool); diff --git a/components/style/values/specified/text.rs b/components/style/values/specified/text.rs index 0228d5123ce..703e51a5248 100644 --- a/components/style/values/specified/text.rs +++ b/components/style/values/specified/text.rs @@ -122,7 +122,18 @@ impl ToComputedValue for LineHeight { } /// A generic value for the `text-overflow` property. -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] +#[derive( + Clone, + Debug, + Eq, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] #[repr(C, u8)] pub enum TextOverflowSide { /// Clip inline content. @@ -517,6 +528,35 @@ impl ToCss for TextTransformOther { } } +/// Specified and computed value of text-align-last. +#[derive( + Clone, + Copy, + Debug, + Eq, + FromPrimitive, + Hash, + MallocSizeOf, + Parse, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] +#[allow(missing_docs)] +#[repr(u8)] +pub enum TextAlignLast { + Auto, + Start, + End, + Left, + Right, + Center, + Justify, +} + /// Specified value of text-align keyword value. #[derive( Clone, @@ -535,14 +575,18 @@ impl ToCss for TextTransformOther { ToShmem, )] #[allow(missing_docs)] +#[repr(u8)] pub enum TextAlignKeyword { Start, - End, Left, Right, Center, #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] Justify, + #[css(skip)] + #[cfg(feature = "gecko")] + Char, + End, #[cfg(feature = "gecko")] MozCenter, #[cfg(feature = "gecko")] @@ -555,9 +599,6 @@ pub enum TextAlignKeyword { ServoLeft, #[cfg(feature = "servo-layout-2013")] ServoRight, - #[css(skip)] - #[cfg(feature = "gecko")] - Char, } /// Specified value of text-align property. @@ -579,14 +620,6 @@ pub enum TextAlign { MozCenterOrInherit, } -impl TextAlign { - /// Convert an enumerated value coming from Gecko to a `TextAlign`. - #[cfg(feature = "gecko")] - pub fn from_gecko_keyword(kw: u32) -> Self { - TextAlign::Keyword(TextAlignKeyword::from_gecko_keyword(kw)) - } -} - impl ToComputedValue for TextAlign { type ComputedValue = TextAlignKeyword; @@ -665,7 +698,19 @@ pub enum TextEmphasisStyle { } /// Fill mode for the text-emphasis-style property -#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] +#[derive( + Clone, + Copy, + Debug, + MallocSizeOf, + Parse, + PartialEq, + SpecifiedValueInfo, + ToCss, + ToComputedValue, + ToResolvedValue, + ToShmem, +)] #[repr(u8)] pub enum TextEmphasisFillMode { /// `filled` @@ -684,7 +729,18 @@ impl TextEmphasisFillMode { /// Shape keyword for the text-emphasis-style property #[derive( - Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem, + Clone, + Copy, + Debug, + Eq, + MallocSizeOf, + Parse, + PartialEq, + SpecifiedValueInfo, + ToCss, + ToComputedValue, + ToResolvedValue, + ToShmem, )] #[repr(u8)] pub enum TextEmphasisShapeKeyword { @@ -1010,7 +1066,7 @@ pub enum OverflowWrap { Anywhere, } -/// Implements text-decoration-skip-ink which takes the keywords auto | none +/// Implements text-decoration-skip-ink which takes the keywords auto | none | all /// /// https://drafts.csswg.org/css-text-decor-4/#text-decoration-skip-ink-property #[repr(u8)] @@ -1033,6 +1089,7 @@ pub enum OverflowWrap { pub enum TextDecorationSkipInk { Auto, None, + All, } /// Implements type for `text-decoration-thickness` property diff --git a/components/style/values/specified/ui.rs b/components/style/values/specified/ui.rs index 46272b2ae85..b94267162c9 100644 --- a/components/style/values/specified/ui.rs +++ b/components/style/values/specified/ui.rs @@ -14,10 +14,10 @@ use std::fmt::{self, Write}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; /// A specified value for the `cursor` property. -pub type Cursor = generics::Cursor<CursorImage>; +pub type Cursor = generics::GenericCursor<CursorImage>; /// A specified value for item of `image cursors`. -pub type CursorImage = generics::CursorImage<SpecifiedImageUrl, Number>; +pub type CursorImage = generics::GenericCursorImage<SpecifiedImageUrl, Number>; impl Parse for Cursor { /// cursor: [<url> [<number> <number>]?]# [auto | default | ...] @@ -34,7 +34,7 @@ impl Parse for Cursor { input.expect_comma()?; } Ok(Self { - images: images.into_boxed_slice(), + images: images.into(), keyword: CursorKind::parse(input)?, }) } @@ -45,12 +45,24 @@ impl Parse for CursorImage { context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> { + use crate::Zero; + + let url = SpecifiedImageUrl::parse(context, input)?; + let mut has_hotspot = false; + let mut hotspot_x = Number::zero(); + let mut hotspot_y = Number::zero(); + + if let Ok(x) = input.try(|input| Number::parse(context, input)) { + has_hotspot = true; + hotspot_x = x; + hotspot_y = Number::parse(context, input)?; + } + Ok(Self { - url: SpecifiedImageUrl::parse(context, input)?, - hotspot: match input.try(|input| Number::parse(context, input)) { - Ok(number) => Some((number, Number::parse(context, input)?)), - Err(_) => None, - }, + url, + has_hotspot, + hotspot_x, + hotspot_y, }) } } diff --git a/components/style_derive/animate.rs b/components/style_derive/animate.rs index 190568514fc..59b19214971 100644 --- a/components/style_derive/animate.rs +++ b/components/style_derive/animate.rs @@ -6,12 +6,11 @@ use darling::util::PathList; use derive_common::cg; use proc_macro2::TokenStream; use quote::TokenStreamExt; -use syn::{DeriveInput, Path, WhereClause}; +use syn::{DeriveInput, WhereClause}; use synstructure::{Structure, VariantInfo}; pub fn derive(mut input: DeriveInput) -> TokenStream { let animation_input_attrs = cg::parse_input_attrs::<AnimationInputAttrs>(&input); - let input_attrs = cg::parse_input_attrs::<AnimateInputAttrs>(&input); let no_bound = animation_input_attrs.no_bound.unwrap_or_default(); let mut where_clause = input.generics.where_clause.take(); @@ -44,11 +43,6 @@ pub fn derive(mut input: DeriveInput) -> TokenStream { let name = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let fallback = match input_attrs.fallback { - Some(fallback) => quote! { #fallback(self, other, procedure) }, - None => quote! { Err(()) }, - }; - quote! { impl #impl_generics crate::values::animated::Animate for #name #ty_generics #where_clause { #[allow(unused_variables, unused_imports)] @@ -59,7 +53,7 @@ pub fn derive(mut input: DeriveInput) -> TokenStream { procedure: crate::values::animated::Procedure, ) -> Result<Self, ()> { if std::mem::discriminant(self) != std::mem::discriminant(other) { - return #fallback; + return Err(()); } match (self, other) { #match_body @@ -118,12 +112,6 @@ fn derive_variant_arm( } } -#[darling(attributes(animate), default)] -#[derive(Default, FromDeriveInput)] -struct AnimateInputAttrs { - fallback: Option<Path>, -} - #[darling(attributes(animation), default)] #[derive(Default, FromDeriveInput)] pub struct AnimationInputAttrs { diff --git a/components/style_derive/compute_squared_distance.rs b/components/style_derive/compute_squared_distance.rs index 5e130e75b06..b4e67f6c984 100644 --- a/components/style_derive/compute_squared_distance.rs +++ b/components/style_derive/compute_squared_distance.rs @@ -6,12 +6,11 @@ use crate::animate::{AnimationFieldAttrs, AnimationInputAttrs, AnimationVariantA use derive_common::cg; use proc_macro2::TokenStream; use quote::TokenStreamExt; -use syn::{DeriveInput, Path, WhereClause}; +use syn::{DeriveInput, WhereClause}; use synstructure; pub fn derive(mut input: DeriveInput) -> TokenStream { let animation_input_attrs = cg::parse_input_attrs::<AnimationInputAttrs>(&input); - let input_attrs = cg::parse_input_attrs::<DistanceInputAttrs>(&input); let no_bound = animation_input_attrs.no_bound.unwrap_or_default(); let mut where_clause = input.generics.where_clause.take(); for param in input.generics.type_params() { @@ -43,11 +42,6 @@ pub fn derive(mut input: DeriveInput) -> TokenStream { match_body.append_all(quote! { _ => unsafe { debug_unreachable!() } }); } - let fallback = match input_attrs.fallback { - Some(fallback) => quote! { #fallback(self, other) }, - None => quote! { Err(()) }, - }; - let name = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); @@ -60,7 +54,7 @@ pub fn derive(mut input: DeriveInput) -> TokenStream { other: &Self, ) -> Result<crate::values::distance::SquaredDistance, ()> { if std::mem::discriminant(self) != std::mem::discriminant(other) { - return #fallback; + return Err(()); } match (self, other) { #match_body @@ -125,12 +119,6 @@ fn derive_variant_arm( } #[darling(attributes(distance), default)] -#[derive(Default, FromDeriveInput)] -struct DistanceInputAttrs { - fallback: Option<Path>, -} - -#[darling(attributes(distance), default)] #[derive(Default, FromField)] struct DistanceFieldAttrs { field_bound: bool, diff --git a/components/style_derive/to_animated_value.rs b/components/style_derive/to_animated_value.rs index 51a73cbf4e1..45282f0c448 100644 --- a/components/style_derive/to_animated_value.rs +++ b/components/style_derive/to_animated_value.rs @@ -11,33 +11,25 @@ pub fn derive(input: DeriveInput) -> TokenStream { let trait_impl = |from_body, to_body| { quote! { #[inline] - fn from_animated_value(animated: Self::AnimatedValue) -> Self { - match animated { - #from_body - } + fn from_animated_value(from: Self::AnimatedValue) -> Self { + #from_body } #[inline] fn to_animated_value(self) -> Self::AnimatedValue { - match self { - #to_body - } + #to_body } } }; - // TODO(emilio): Consider optimizing away non-generic cases as well? - let non_generic_implementation = || None; - to_computed_value::derive_to_value( input, parse_quote!(crate::values::animated::ToAnimatedValue), parse_quote!(AnimatedValue), BindStyle::Move, - |_| false, + |_| Default::default(), |binding| quote!(crate::values::animated::ToAnimatedValue::from_animated_value(#binding)), |binding| quote!(crate::values::animated::ToAnimatedValue::to_animated_value(#binding)), trait_impl, - non_generic_implementation, ) } diff --git a/components/style_derive/to_computed_value.rs b/components/style_derive/to_computed_value.rs index ed6e07a2f5a..fe6bddb7ed2 100644 --- a/components/style_derive/to_computed_value.rs +++ b/components/style_derive/to_computed_value.rs @@ -13,7 +13,7 @@ pub fn derive_to_value( output_type_name: Ident, bind_style: BindStyle, // Returns whether to apply the field bound for a given item. - mut field_bound: impl FnMut(&BindingInfo) -> bool, + mut binding_attrs: impl FnMut(&BindingInfo) -> ToValueAttrs, // Returns a token stream of the form: trait_path::from_foo(#binding) mut call_from: impl FnMut(&BindingInfo) -> TokenStream, mut call_to: impl FnMut(&BindingInfo) -> TokenStream, @@ -26,25 +26,9 @@ pub fn derive_to_value( // #second_arg // } mut trait_impl: impl FnMut(TokenStream, TokenStream) -> TokenStream, - // if this is provided, the derive for non-generic types will be simplified - // to this token stream, which should be the body of the impl block. - non_generic_implementation: impl FnOnce() -> Option<TokenStream>, ) -> TokenStream { let name = &input.ident; - if input.generics.type_params().next().is_none() { - if let Some(non_generic_implementation) = non_generic_implementation() { - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - return quote! { - impl #impl_generics #trait_path for #name #ty_generics - #where_clause - { - #non_generic_implementation - } - }; - } - } - let mut where_clause = input.generics.where_clause.take(); cg::propagate_clauses_to_output_type( &mut where_clause, @@ -52,33 +36,107 @@ pub fn derive_to_value( &trait_path, &output_type_name, ); - let (to_body, from_body) = { - let params = input.generics.type_params().collect::<Vec<_>>(); - for param in ¶ms { - cg::add_predicate(&mut where_clause, parse_quote!(#param: #trait_path)); - } - let to_body = cg::fmap_match(&input, bind_style, |binding| { - if field_bound(&binding) { - let ty = &binding.ast().ty; + let moves = match bind_style { + BindStyle::Move | BindStyle::MoveMut => true, + BindStyle::Ref | BindStyle::RefMut => false, + }; - let output_type = cg::map_type_params( - ty, - ¶ms, - &mut |ident| parse_quote!(<#ident as #trait_path>::#output_type_name), - ); + let params = input.generics.type_params().collect::<Vec<_>>(); + for param in ¶ms { + cg::add_predicate(&mut where_clause, parse_quote!(#param: #trait_path)); + } - cg::add_predicate( - &mut where_clause, - parse_quote!( - #ty: #trait_path<#output_type_name = #output_type> - ), + let mut add_field_bound = |binding: &BindingInfo| { + let ty = &binding.ast().ty; + + let output_type = cg::map_type_params( + ty, + ¶ms, + &mut |ident| parse_quote!(<#ident as #trait_path>::#output_type_name), + ); + + cg::add_predicate( + &mut where_clause, + parse_quote!( + #ty: #trait_path<#output_type_name = #output_type> + ), + ); + }; + + let (to_body, from_body) = if params.is_empty() { + let mut s = synstructure::Structure::new(&input); + s.variants_mut().iter_mut().for_each(|v| { + v.bind_with(|_| bind_style); + }); + + for variant in s.variants() { + for binding in variant.bindings() { + let attrs = binding_attrs(&binding); + assert!( + !attrs.field_bound, + "It is default on a non-generic implementation", ); + if !attrs.no_field_bound { + // Add field bounds to all bindings except the manually + // excluded. This ensures the correctness of the clone() / + // move based implementation. + add_field_bound(binding); + } + } + } + + let to_body = if moves { + quote! { self } + } else { + quote! { std::clone::Clone::clone(self) } + }; + + let from_body = if moves { + quote! { from } + } else { + quote! { std::clone::Clone::clone(from) } + }; + + (to_body, from_body) + } else { + let to_body = cg::fmap_match(&input, bind_style, |binding| { + let attrs = binding_attrs(&binding); + assert!( + !attrs.no_field_bound, + "It doesn't make sense on a generic implementation" + ); + if attrs.field_bound { + add_field_bound(&binding); } call_to(&binding) }); + let from_body = cg::fmap_match(&input, bind_style, |binding| call_from(&binding)); + let self_ = if moves { + quote! { self } + } else { + quote! { *self } + }; + let from_ = if moves { + quote! { from } + } else { + quote! { *from } + }; + + let to_body = quote! { + match #self_ { + #to_body + } + }; + + let from_body = quote! { + match #from_ { + #from_body + } + }; + (to_body, from_body) }; @@ -101,53 +159,45 @@ pub fn derive(input: DeriveInput) -> TokenStream { let trait_impl = |from_body, to_body| { quote! { #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - match *computed { - #from_body - } + fn from_computed_value(from: &Self::ComputedValue) -> Self { + #from_body } #[allow(unused_variables)] #[inline] fn to_computed_value(&self, context: &crate::values::computed::Context) -> Self::ComputedValue { - match *self { - #to_body - } + #to_body } } }; - let non_generic_implementation = || { - Some(quote! { - type ComputedValue = Self; - - #[inline] - fn to_computed_value(&self, _: &crate::values::computed::Context) -> Self::ComputedValue { - std::clone::Clone::clone(self) - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - std::clone::Clone::clone(computed) - } - }) - }; - derive_to_value( input, parse_quote!(crate::values::computed::ToComputedValue), parse_quote!(ComputedValue), BindStyle::Ref, - |binding| cg::parse_field_attrs::<ComputedValueAttrs>(&binding.ast()).field_bound, + |binding| { + let attrs = cg::parse_field_attrs::<ComputedValueAttrs>(&binding.ast()); + ToValueAttrs { + field_bound: attrs.field_bound, + no_field_bound: attrs.no_field_bound, + } + }, |binding| quote!(crate::values::computed::ToComputedValue::from_computed_value(#binding)), |binding| quote!(crate::values::computed::ToComputedValue::to_computed_value(#binding, context)), trait_impl, - non_generic_implementation, ) } +#[derive(Default)] +pub struct ToValueAttrs { + pub field_bound: bool, + pub no_field_bound: bool, +} + #[darling(attributes(compute), default)] #[derive(Default, FromField)] struct ComputedValueAttrs { field_bound: bool, + no_field_bound: bool, } diff --git a/components/style_derive/to_resolved_value.rs b/components/style_derive/to_resolved_value.rs index 040cda954a8..f7ba2645e89 100644 --- a/components/style_derive/to_resolved_value.rs +++ b/components/style_derive/to_resolved_value.rs @@ -12,10 +12,8 @@ pub fn derive(input: DeriveInput) -> TokenStream { let trait_impl = |from_body, to_body| { quote! { #[inline] - fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { - match resolved { - #from_body - } + fn from_resolved_value(from: Self::ResolvedValue) -> Self { + #from_body } #[inline] @@ -23,42 +21,26 @@ pub fn derive(input: DeriveInput) -> TokenStream { self, context: &crate::values::resolved::Context, ) -> Self::ResolvedValue { - match self { - #to_body - } + #to_body } } }; - let non_generic_implementation = || { - Some(quote! { - type ResolvedValue = Self; - - #[inline] - fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { - resolved - } - - #[inline] - fn to_resolved_value( - self, - context: &crate::values::resolved::Context, - ) -> Self { - self - } - }) - }; - to_computed_value::derive_to_value( input, parse_quote!(crate::values::resolved::ToResolvedValue), parse_quote!(ResolvedValue), BindStyle::Move, - |binding| cg::parse_field_attrs::<ResolvedValueAttrs>(&binding.ast()).field_bound, + |binding| { + let attrs = cg::parse_field_attrs::<ResolvedValueAttrs>(&binding.ast()); + to_computed_value::ToValueAttrs { + field_bound: attrs.field_bound, + no_field_bound: attrs.no_field_bound, + } + }, |binding| quote!(crate::values::resolved::ToResolvedValue::from_resolved_value(#binding)), |binding| quote!(crate::values::resolved::ToResolvedValue::to_resolved_value(#binding, context)), trait_impl, - non_generic_implementation, ) } @@ -66,4 +48,5 @@ pub fn derive(input: DeriveInput) -> TokenStream { #[derive(Default, FromField)] struct ResolvedValueAttrs { field_bound: bool, + no_field_bound: bool, } diff --git a/components/style_traits/arc_slice.rs b/components/style_traits/arc_slice.rs index f5d0c56e7fc..8d55beff3c5 100644 --- a/components/style_traits/arc_slice.rs +++ b/components/style_traits/arc_slice.rs @@ -26,7 +26,7 @@ const ARC_SLICE_CANARY: u64 = 0xf3f3f3f3f3f3f3f3; /// cbindgen:derive-eq=false /// cbindgen:derive-neq=false #[repr(C)] -#[derive(Clone, Debug, Eq, PartialEq, ToShmem)] +#[derive(Debug, Eq, PartialEq, ToShmem)] pub struct ArcSlice<T>(#[shmem(field_bound)] ThinArc<u64, T>); impl<T> Deref for ArcSlice<T> { @@ -39,6 +39,12 @@ impl<T> Deref for ArcSlice<T> { } } +impl<T> Clone for ArcSlice<T> { + fn clone(&self) -> Self { + ArcSlice(self.0.clone()) + } +} + lazy_static! { // ThinArc doesn't support alignments greater than align_of::<u64>. static ref EMPTY_ARC_SLICE: ArcSlice<u64> = { diff --git a/components/style_traits/lib.rs b/components/style_traits/lib.rs index 516e7b6efba..be2d275b654 100644 --- a/components/style_traits/lib.rs +++ b/components/style_traits/lib.rs @@ -137,6 +137,8 @@ pub enum StyleParseErrorKind<'i> { UnexpectedNamespaceRule, /// @import must be before any rule but @charset UnexpectedImportRule, + /// @import rules are disallowed in the parser. + DisallowedImportRule, /// Unexpected @charset rule encountered. UnexpectedCharsetRule, /// Unsupported @ rule @@ -149,7 +151,6 @@ pub enum StyleParseErrorKind<'i> { ValueError(ValueParseErrorKind<'i>), /// An error was encountered while parsing a selector SelectorError(SelectorParseErrorKind<'i>), - /// The property declaration was for an unknown property. UnknownProperty(CowRcStr<'i>), /// The property declaration was for a disabled experimental property. diff --git a/ports/glutin/main.rs b/ports/glutin/main.rs index 50da58121bc..85c237c55db 100644 --- a/ports/glutin/main.rs +++ b/ports/glutin/main.rs @@ -15,8 +15,6 @@ //! //! [glutin]: https://github.com/tomaka/glutin -#![feature(core_intrinsics)] - #[cfg(not(target_os = "android"))] include!("main2.rs"); diff --git a/ports/libsimpleservo/capi/src/lib.rs b/ports/libsimpleservo/capi/src/lib.rs index 60bd6a2f7a4..1fb3e5359c6 100644 --- a/ports/libsimpleservo/capi/src/lib.rs +++ b/ports/libsimpleservo/capi/src/lib.rs @@ -27,17 +27,20 @@ use std::os::raw::{c_char, c_uint, c_void}; use std::panic::{self, UnwindSafe}; use std::slice; use std::str::FromStr; -use std::sync::RwLock; +use std::sync::{Mutex, RwLock}; extern "C" fn default_panic_handler(msg: *const c_char) { let c_str: &CStr = unsafe { CStr::from_ptr(msg) }; error!("{}", c_str.to_str().unwrap()); } +type LogHandlerFn = extern "C" fn(buffer: *const c_char, len: u32); + lazy_static! { static ref ON_PANIC: RwLock<extern "C" fn(*const c_char)> = RwLock::new(default_panic_handler); static ref SERVO_VERSION: CString = CString::new(simpleservo::servo_version()).expect("Can't create string"); + pub(crate) static ref OUTPUT_LOG_HANDLER: Mutex<Option<LogHandlerFn>> = Mutex::new(None); } #[no_mangle] @@ -64,13 +67,13 @@ fn catch_any_panic<T, F: FnOnce() -> T + UnwindSafe>(function: F) -> T { } #[cfg(not(target_os = "windows"))] -fn redirect_stdout_stderr() -> Result<(), String> { +fn redirect_stdout_stderr(_handler: LogHandlerFn) -> Result<(), String> { Ok(()) } #[cfg(target_os = "windows")] -fn redirect_stdout_stderr() -> Result<(), String> { - do_redirect_stdout_stderr().map_err(|()| { +fn redirect_stdout_stderr(handler: LogHandlerFn) -> Result<(), String> { + do_redirect_stdout_stderr(handler).map_err(|()| { format!("GetLastError() = {}", unsafe { winapi::um::errhandlingapi::GetLastError() }) @@ -83,10 +86,9 @@ fn redirect_stdout_stderr() -> Result<(), String> { // Return Value: Result<(), String> // Ok() - stdout and stderr redirects. // Err(str) - The Err value can contain the string value of GetLastError. -fn do_redirect_stdout_stderr() -> Result<(), ()> { +fn do_redirect_stdout_stderr(handler: LogHandlerFn) -> Result<(), ()> { use std::thread; use winapi::shared; - use winapi::um::debugapi; use winapi::um::handleapi; use winapi::um::minwinbase; use winapi::um::namedpipeapi; @@ -163,24 +165,20 @@ fn do_redirect_stdout_stderr() -> Result<(), ()> { } // Spawn a thread. The thread will redirect all STDOUT and STDERR messages - // to OutputDebugString() - let _handler = thread::spawn(move || { - loop { - let mut read_buf: [i8; BUF_LENGTH] = [0; BUF_LENGTH]; - - let result = libc::read( - h_read_pipe_fd, - read_buf.as_mut_ptr() as *mut _, - read_buf.len() as u32 - 1, - ); - - if result == -1 { - break; - } - - // Write to Debug port. - debugapi::OutputDebugStringA(read_buf.as_mut_ptr() as winnt::LPSTR); + // to the provided handler function. + let _handler = thread::spawn(move || loop { + let mut read_buf: [i8; BUF_LENGTH] = [0; BUF_LENGTH]; + + let result = libc::read( + h_read_pipe_fd, + read_buf.as_mut_ptr() as *mut _, + read_buf.len() as u32 - 1, + ); + + if result == -1 { + break; } + handler(read_buf.as_ptr(), result as u32); }); } @@ -232,6 +230,7 @@ pub struct CHostCallbacks { pub on_devtools_started: extern "C" fn(result: CDevtoolsServerState, port: c_uint), pub show_context_menu: extern "C" fn(title: *const c_char, items_list: *const *const c_char, items_size: u32), + pub on_log_output: extern "C" fn(buffer: *const c_char, buffer_length: u32), } /// Servo options @@ -422,9 +421,10 @@ unsafe fn init( slice::from_raw_parts(opts.vslogger_mod_list, opts.vslogger_mod_size as usize) }; + *OUTPUT_LOG_HANDLER.lock().unwrap() = Some(callbacks.on_log_output); init_logger(logger_modules, logger_level); - if let Err(reason) = redirect_stdout_stderr() { + if let Err(reason) = redirect_stdout_stderr(callbacks.on_log_output) { warn!("Error redirecting stdout/stderr: {}", reason); } diff --git a/ports/libsimpleservo/capi/src/vslogger.rs b/ports/libsimpleservo/capi/src/vslogger.rs index 31e7159af0d..d9471302084 100644 --- a/ports/libsimpleservo/capi/src/vslogger.rs +++ b/ports/libsimpleservo/capi/src/vslogger.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 crate::OUTPUT_LOG_HANDLER; use log::{self, Metadata, Record}; use std::sync::{Arc, Mutex}; @@ -9,10 +10,6 @@ lazy_static! { pub static ref LOG_MODULE_FILTERS: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![])); } -extern "C" { - fn OutputDebugStringA(s: *const u8); -} - pub struct VSLogger; impl log::Log for VSLogger { @@ -33,9 +30,9 @@ impl log::Log for VSLogger { record.target(), record.args() ); - unsafe { - OutputDebugStringA(log.as_ptr()); - }; + if let Some(handler) = OUTPUT_LOG_HANDLER.lock().unwrap().as_ref() { + (handler)(log.as_ptr() as _, log.len() as u32); + } } } diff --git a/python/servo/build_commands.py b/python/servo/build_commands.py index cb54497377a..3b87e9aba7e 100644 --- a/python/servo/build_commands.py +++ b/python/servo/build_commands.py @@ -256,10 +256,11 @@ class MachCommands(CommandBase): vs_dirs = self.vs_dirs() if host != target_triple and 'windows' in target_triple: - if os.environ.get('VisualStudioVersion'): + if os.environ.get('VisualStudioVersion') or os.environ.get('VCINSTALLDIR'): print("Can't cross-compile for Windows inside of a Visual Studio shell.\n" "Please run `python mach build [arguments]` to bypass automatic " - "Visual Studio shell.") + "Visual Studio shell, and make sure the VisualStudioVersion and " + "VCINSTALLDIR environment variables are not set.") sys.exit(1) vcinstalldir = vs_dirs['vcdir'] if not os.path.exists(vcinstalldir): @@ -315,11 +316,15 @@ class MachCommands(CommandBase): process = subprocess.Popen('("%s" %s > nul) && "python" -c "import os; print(repr(os.environ))"' % (os.path.join(vs_dirs['vcdir'], "Auxiliary", "Build", "vcvarsall.bat"), "x64"), stdout=subprocess.PIPE, shell=True) - stdout, _ = process.communicate() + stdout, stderr = process.communicate() exitcode = process.wait() encoding = locale.getpreferredencoding() # See https://stackoverflow.com/a/9228117 if exitcode == 0: os.environ.update(eval(stdout.decode(encoding))) + else: + print("Failed to run vcvarsall. stderr:") + print(stderr.decode(encoding)) + exit(1) # Ensure that GStreamer libraries are accessible when linking. if 'windows' in target_triple: diff --git a/python/servo/package_commands.py b/python/servo/package_commands.py index a0aa3865b6f..8df106e2a9e 100644 --- a/python/servo/package_commands.py +++ b/python/servo/package_commands.py @@ -31,7 +31,7 @@ from mach.decorators import ( from mach.registrar import Registrar # Note: mako cannot be imported at the top level because it breaks mach bootstrap sys.path.append(path.join(path.dirname(__file__), "..", "..", - "components", "style", "properties", "Mako-0.9.1.zip")) + "components", "style", "properties", "Mako-1.1.2-py2.py3-none-any.whl")) from servo.command_base import ( archive_deterministically, diff --git a/python/servo/packages.py b/python/servo/packages.py index db22558f0d4..ea903a3913b 100644 --- a/python/servo/packages.py +++ b/python/servo/packages.py @@ -4,7 +4,7 @@ WINDOWS_MSVC = { "cmake": "3.14.3", - "llvm": "8.0.1", + "llvm": "9.0.0", "moztools": "3.2", "ninja": "1.7.1", "nuget": "08-08-2019", diff --git a/python/servo/testing_commands.py b/python/servo/testing_commands.py index 3fad465277b..7bee7633f90 100644 --- a/python/servo/testing_commands.py +++ b/python/servo/testing_commands.py @@ -49,7 +49,7 @@ WEB_PLATFORM_TESTS_PATH = os.path.join("tests", "wpt", "web-platform-tests") SERVO_TESTS_PATH = os.path.join("tests", "wpt", "mozilla", "tests") CLANGFMT_CPP_DIRS = ["support/hololens/"] -CLANGFMT_VERSION = "8" +CLANGFMT_VERSION = "9" TEST_SUITES = OrderedDict([ ("tidy", {"kwargs": {"all_files": False, "no_progress": False, "self_test": False, diff --git a/servo-tidy.toml b/servo-tidy.toml index d308abedc4a..c70ac96877b 100644 --- a/servo-tidy.toml +++ b/servo-tidy.toml @@ -89,6 +89,7 @@ files = [ # Python 3 syntax causes "E901 SyntaxError" when flake8 runs in Python 2 "./etc/taskcluster/decision_task.py", "./etc/taskcluster/decisionlib.py", + "./components/style/properties/build.py", ] # Directories that are ignored for the non-WPT tidy check. directories = [ diff --git a/support/hololens/ServoApp/App.cpp b/support/hololens/ServoApp/App.cpp index a505da34d5a..22b6f4586f4 100644 --- a/support/hololens/ServoApp/App.cpp +++ b/support/hololens/ServoApp/App.cpp @@ -103,10 +103,14 @@ void App::OnActivated(IActivatedEventArgs const &args) { } void App::OnSuspending(IInspectable const &, SuspendingEventArgs const &) { - auto content = Window::Current().Content(); + // FIXME: Apps can be suspended for various reasons, not just closing them. + // * Figure out how to save state like the current URL so it can be + // restored if necessary. + // * Determine if the user has actually closed the app and shutdown. + /*auto content = Window::Current().Content(); Frame rootFrame = content.try_as<Frame>(); auto page = rootFrame.Content().try_as<BrowserPage>(); - page->Shutdown(); + page->Shutdown();*/ } void App::OnNavigationFailed(IInspectable const &, diff --git a/support/hololens/ServoApp/Package.appxmanifest b/support/hololens/ServoApp/Package.appxmanifest index 5ada19983d7..26091d47f0a 100644 --- a/support/hololens/ServoApp/Package.appxmanifest +++ b/support/hololens/ServoApp/Package.appxmanifest @@ -9,7 +9,7 @@ </Properties> <Dependencies> <TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" /> - <PackageDependency Name="Microsoft.WindowsMixedReality.Runtime" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" MinVersion="0.0.1.0" /> + <PackageDependency Name="Microsoft.WindowsMixedReality.Runtime" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" MinVersion="100.2004.3007.0"/> </Dependencies> <Resources> <Resource Language="x-generate" /> diff --git a/support/hololens/ServoApp/ServoControl/Servo.cpp b/support/hololens/ServoApp/ServoControl/Servo.cpp index 76753d0758f..17c86f17271 100644 --- a/support/hololens/ServoApp/ServoControl/Servo.cpp +++ b/support/hololens/ServoApp/ServoControl/Servo.cpp @@ -36,6 +36,10 @@ void on_animating_changed(bool aAnimating) { } void on_panic(const char *backtrace) { + if (sLogHandle != INVALID_HANDLE_VALUE) { + CloseHandle(sLogHandle); + sLogHandle = INVALID_HANDLE_VALUE; + } throw hresult_error(E_FAIL, char2hstring(backtrace)); } @@ -86,6 +90,23 @@ void on_devtools_started(Servo::DevtoolsServerState result, result == Servo::DevtoolsServerState::Started, port); } +void on_log_output(const char *buffer, uint32_t buffer_length) { + OutputDebugStringA(buffer); + + if (sLogHandle == INVALID_HANDLE_VALUE) { + return; + } + + DWORD bytesWritten; + auto writeResult = + WriteFile(sLogHandle, buffer, buffer_length, &bytesWritten, nullptr); + + if (writeResult == FALSE || bytesWritten != buffer_length) + throw std::runtime_error( + "Failed to write log message to the log file: error code " + + std::to_string(GetLastError())); +} + Servo::PromptResult prompt_ok_cancel(const char *message, bool trusted) { return sServo->Delegate().OnServoPromptOkCancel(char2hstring(message), trusted); @@ -109,6 +130,7 @@ const char *prompt_input(const char *message, const char *default, Servo::Servo(hstring url, hstring args, GLsizei width, GLsizei height, float dpi, ServoDelegate &aDelegate) : mWindowHeight(height), mWindowWidth(width), mDelegate(aDelegate) { + SetEnvironmentVariableA("PreviewRuntimeEnabled", "1"); capi::CInitOptions o; hstring defaultPrefs = L" --pref dom.webxr.enabled --devtools"; @@ -140,6 +162,22 @@ Servo::Servo(hstring url, hstring args, GLsizei width, GLsizei height, sServo = this; // FIXME; +#ifdef _DEBUG + auto current = winrt::Windows::Storage::ApplicationData::Current(); + auto filePath = std::wstring(current.LocalFolder().Path()) + L"\\stdout.txt"; + sLogHandle = + CreateFile2(filePath.c_str(), GENERIC_WRITE, 0, CREATE_ALWAYS, nullptr); + if (sLogHandle == INVALID_HANDLE_VALUE) + throw std::runtime_error("Failed to open the log file: error code " + + std::to_string(GetLastError())); + + if (SetFilePointer(sLogHandle, 0, nullptr, FILE_END) == + INVALID_SET_FILE_POINTER) + throw std::runtime_error( + "Failed to set file pointer to the end of file: error code " + + std::to_string(GetLastError())); +#endif + capi::CHostCallbacks c; c.flush = &flush; c.make_current = &make_current; @@ -163,13 +201,18 @@ Servo::Servo(hstring url, hstring args, GLsizei width, GLsizei height, c.prompt_input = &prompt_input; c.on_devtools_started = &on_devtools_started; c.show_context_menu = &show_context_menu; + c.on_log_output = &on_log_output; capi::register_panic_handler(&on_panic); capi::init_with_egl(o, &wakeup, c); } -Servo::~Servo() { sServo = nullptr; } +Servo::~Servo() { + sServo = nullptr; + if (sLogHandle != INVALID_HANDLE_VALUE) + CloseHandle(sLogHandle); +} winrt::hstring char2hstring(const char *c_str) { // FIXME: any better way of doing this? diff --git a/support/hololens/ServoApp/ServoControl/Servo.h b/support/hololens/ServoApp/ServoControl/Servo.h index 7b3b3b00ed3..ccc8c1efa06 100644 --- a/support/hololens/ServoApp/ServoControl/Servo.h +++ b/support/hololens/ServoApp/ServoControl/Servo.h @@ -119,5 +119,6 @@ protected: // pointer as callback in Servo, and these functions need a way to get // the Servo instance. See https://github.com/servo/servo/issues/22967 static Servo *sServo = nullptr; +static HANDLE sLogHandle = INVALID_HANDLE_VALUE; } // namespace winrt::servo diff --git a/tests/unit/style/parsing/image.rs b/tests/unit/style/parsing/image.rs index 33ccb88cb0c..1082f8e0b90 100644 --- a/tests/unit/style/parsing/image.rs +++ b/tests/unit/style/parsing/image.rs @@ -29,126 +29,3 @@ fn test_linear_gradient() { // Parsing without <angle> and <side-or-corner> assert_roundtrip_with_context!(Image::parse, "linear-gradient(red, green)"); } - -#[test] -fn test_radial_gradient() { - // Parsing with all values - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(circle closest-side at 20px 30px, red, green)" - ); - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(ellipse closest-side at 20px 30px, red, green)", - "radial-gradient(closest-side at 20px 30px, red, green)" - ); - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(closest-side circle at 20px 30px, red, green)", - "radial-gradient(circle closest-side at 20px 30px, red, green)" - ); - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(closest-side ellipse at 20px 30px, red, green)", - "radial-gradient(closest-side at 20px 30px, red, green)" - ); - - // Parsing with <shape-keyword> and <size> reversed - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(closest-side circle at 20px 30px, red, green)", - "radial-gradient(circle closest-side at 20px 30px, red, green)" - ); - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(closest-corner ellipse at 20px 30px, red, green)", - "radial-gradient(closest-corner at 20px 30px, red, green)" - ); - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(30px circle, red, green)", - "radial-gradient(30px at center center, red, green)" - ); - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(30px 40px ellipse, red, green)", - "radial-gradient(30px 40px at center center, red, green)" - ); - - // Parsing without <size> - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(circle, red, green)", - "radial-gradient(circle at center center, red, green)" - ); - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(ellipse, red, green)", - "radial-gradient(at center center, red, green)" - ); - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(circle at 20px 30px, red, green)" - ); - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(ellipse at 20px 30px, red, green)", - "radial-gradient(at 20px 30px, red, green)" - ); - - // Parsing without <shape-keyword> - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(20px at 20px 30px, red, green)" - ); - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(20px 30px at left center, red, green)" - ); - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(closest-side at center, red, green)", - "radial-gradient(closest-side at center center, red, green)" - ); - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(20px, red, green)", - "radial-gradient(20px at center center, red, green)" - ); - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(20px 30px, red, green)", - "radial-gradient(20px 30px at center center, red, green)" - ); - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(closest-side, red, green)", - "radial-gradient(closest-side at center center, red, green)" - ); - - // Parsing without <shape-keyword> and <size> - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(at center, red, green)", - "radial-gradient(at center center, red, green)" - ); - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(at center bottom, red, green)" - ); - assert_roundtrip_with_context!(Image::parse, "radial-gradient(at 40px 50px, red, green)"); - - // Parsing with just color stops - assert_roundtrip_with_context!( - Image::parse, - "radial-gradient(red, green)", - "radial-gradient(at center center, red, green)" - ); - - // Parsing repeating radial gradient - assert_roundtrip_with_context!( - Image::parse, - "repeating-radial-gradient(red, green)", - "repeating-radial-gradient(at center center, red, green)" - ); -} diff --git a/tests/unit/style/rule_tree/bench.rs b/tests/unit/style/rule_tree/bench.rs index a11174c6c35..9da1eb698e3 100644 --- a/tests/unit/style/rule_tree/bench.rs +++ b/tests/unit/style/rule_tree/bench.rs @@ -12,7 +12,7 @@ use style::media_queries::MediaList; use style::properties::{longhands, Importance, PropertyDeclaration, PropertyDeclarationBlock}; use style::rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource}; use style::shared_lock::{SharedRwLock, StylesheetGuards}; -use style::stylesheets::{CssRule, Origin, Stylesheet}; +use style::stylesheets::{AllowImportRules, CssRule, Origin, Stylesheet}; use style::thread_state::{self, ThreadState}; use test::{self, Bencher}; @@ -67,6 +67,7 @@ fn parse_rules(lock: &SharedRwLock, css: &str) -> Vec<(StyleSource, CascadeLevel Some(&ErrorringErrorReporter), QuirksMode::NoQuirks, 0, + AllowImportRules::Yes, ); let guard = s.shared_lock.read(); let rules = s.contents.rules.read_with(&guard); diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs index d346a42b4cd..c70aaa08f5c 100644 --- a/tests/unit/style/stylesheets.rs +++ b/tests/unit/style/stylesheets.rs @@ -11,8 +11,7 @@ use style::context::QuirksMode; use style::error_reporting::{ContextualParseError, ParseErrorReporter}; use style::media_queries::MediaList; use style::shared_lock::SharedRwLock; -use style::stylesheets::Origin; -use style::stylesheets::Stylesheet; +use style::stylesheets::{AllowImportRules, Origin, Stylesheet}; #[derive(Debug)] struct CSSError { @@ -106,6 +105,7 @@ fn test_report_error_stylesheet() { Some(&error_reporter), QuirksMode::NoQuirks, 5, + AllowImportRules::Yes, ); error_reporter.assert_messages_contain(&[ @@ -116,7 +116,7 @@ fn test_report_error_stylesheet() { ), ( 9, - 27, + 43, "Unsupported property declaration: 'background-image:", ), // FIXME: column should be around 56 (10, 17, "Unsupported property declaration: 'invalid: true;'"), @@ -169,6 +169,7 @@ fn test_no_report_unrecognized_vendor_properties() { Some(&error_reporter), QuirksMode::NoQuirks, 0, + AllowImportRules::Yes, ); error_reporter.assert_messages_contain(&[( @@ -202,6 +203,7 @@ fn test_source_map_url() { None, QuirksMode::NoQuirks, 0, + AllowImportRules::Yes, ); let url_opt = stylesheet.contents.source_map_url.read(); assert_eq!(*url_opt, test.1); @@ -229,6 +231,7 @@ fn test_source_url() { None, QuirksMode::NoQuirks, 0, + AllowImportRules::Yes, ); let url_opt = stylesheet.contents.source_url.read(); assert_eq!(*url_opt, test.1); diff --git a/tests/unit/style/viewport.rs b/tests/unit/style/viewport.rs index eeedc653fc8..445ec4bf8fd 100644 --- a/tests/unit/style/viewport.rs +++ b/tests/unit/style/viewport.rs @@ -12,7 +12,7 @@ use style::media_queries::{Device, MediaList, MediaType}; use style::parser::ParserContext; use style::shared_lock::{SharedRwLock, StylesheetGuards}; use style::stylesheets::viewport_rule::*; -use style::stylesheets::{CssRuleType, Origin, Stylesheet, StylesheetInDocument}; +use style::stylesheets::{AllowImportRules, CssRuleType, Origin, Stylesheet, StylesheetInDocument}; use style::values::generics::length::LengthPercentageOrAuto::{self, Auto}; use style::values::generics::NonNegative; use style::values::specified::LengthPercentage; @@ -36,6 +36,7 @@ macro_rules! stylesheet { None, QuirksMode::NoQuirks, 0, + AllowImportRules::Yes, )) }; } diff --git a/tests/wpt/metadata-layout-2020/2dcontext/path-objects/2d.path.isPointInStroke.scaleddashes.html.ini b/tests/wpt/metadata-layout-2020/2dcontext/path-objects/2d.path.isPointInStroke.scaleddashes.html.ini new file mode 100644 index 00000000000..3a956f90011 --- /dev/null +++ b/tests/wpt/metadata-layout-2020/2dcontext/path-objects/2d.path.isPointInStroke.scaleddashes.html.ini @@ -0,0 +1,4 @@ +[2d.path.isPointInStroke.scaleddashes.html] + [isPointInStroke() should return correct results on dashed paths at high scale factors] + expected: FAIL + diff --git a/tests/wpt/metadata-layout-2020/FileAPI/url/url-in-tags-revoke.window.js.ini b/tests/wpt/metadata-layout-2020/FileAPI/url/url-in-tags-revoke.window.js.ini index 76b44d9e9cf..3605e8f3fc9 100644 --- a/tests/wpt/metadata-layout-2020/FileAPI/url/url-in-tags-revoke.window.js.ini +++ b/tests/wpt/metadata-layout-2020/FileAPI/url/url-in-tags-revoke.window.js.ini @@ -4,7 +4,7 @@ expected: TIMEOUT [Opening a blob URL in a new window immediately before revoking it works.] - expected: FAIL + expected: TIMEOUT [Fetching a blob URL immediately before revoking it works in an iframe.] expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/floats/hit-test-floats-004.html.ini b/tests/wpt/metadata-layout-2020/css/CSS2/floats/hit-test-floats-004.html.ini deleted file mode 100644 index 4bfb0c2053a..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/floats/hit-test-floats-004.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[hit-test-floats-004.html] - [Miss float below something else] - expected: FAIL - diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/floats/hit-test-floats-005.html.ini b/tests/wpt/metadata-layout-2020/css/CSS2/floats/hit-test-floats-005.html.ini new file mode 100644 index 00000000000..baa9f1a7541 --- /dev/null +++ b/tests/wpt/metadata-layout-2020/css/CSS2/floats/hit-test-floats-005.html.ini @@ -0,0 +1,4 @@ +[hit-test-floats-005.html] + [Miss clipped float] + expected: FAIL + diff --git a/tests/wpt/metadata-layout-2020/css/css-animations/animation-base-response-004.html.ini b/tests/wpt/metadata-layout-2020/css/css-animations/animation-base-response-004.html.ini new file mode 100644 index 00000000000..6e98c32bc87 --- /dev/null +++ b/tests/wpt/metadata-layout-2020/css/css-animations/animation-base-response-004.html.ini @@ -0,0 +1,4 @@ +[animation-base-response-004.html] + [Base is responsive to font-affecting appearing via setKeyframes] + expected: FAIL + diff --git a/tests/wpt/metadata-layout-2020/css/css-text/white-space/break-spaces-newline-011.html.ini b/tests/wpt/metadata-layout-2020/css/css-text/white-space/break-spaces-newline-011.html.ini new file mode 100644 index 00000000000..fdf5abac767 --- /dev/null +++ b/tests/wpt/metadata-layout-2020/css/css-text/white-space/break-spaces-newline-011.html.ini @@ -0,0 +1,2 @@ +[break-spaces-newline-011.html] + expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/css-text/white-space/break-spaces-newline-012.html.ini b/tests/wpt/metadata-layout-2020/css/css-text/white-space/break-spaces-newline-012.html.ini new file mode 100644 index 00000000000..098fde40fb1 --- /dev/null +++ b/tests/wpt/metadata-layout-2020/css/css-text/white-space/break-spaces-newline-012.html.ini @@ -0,0 +1,2 @@ +[break-spaces-newline-012.html] + expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/css-text/white-space/break-spaces-newline-013.html.ini b/tests/wpt/metadata-layout-2020/css/css-text/white-space/break-spaces-newline-013.html.ini new file mode 100644 index 00000000000..b3b08d61395 --- /dev/null +++ b/tests/wpt/metadata-layout-2020/css/css-text/white-space/break-spaces-newline-013.html.ini @@ -0,0 +1,2 @@ +[break-spaces-newline-013.html] + expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/css-text/white-space/break-spaces-newline-014.html.ini b/tests/wpt/metadata-layout-2020/css/css-text/white-space/break-spaces-newline-014.html.ini new file mode 100644 index 00000000000..61a082b5e0f --- /dev/null +++ b/tests/wpt/metadata-layout-2020/css/css-text/white-space/break-spaces-newline-014.html.ini @@ -0,0 +1,2 @@ +[break-spaces-newline-014.html] + expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/css-text/white-space/break-spaces-newline-015.html.ini b/tests/wpt/metadata-layout-2020/css/css-text/white-space/break-spaces-newline-015.html.ini new file mode 100644 index 00000000000..c1b8824ba0f --- /dev/null +++ b/tests/wpt/metadata-layout-2020/css/css-text/white-space/break-spaces-newline-015.html.ini @@ -0,0 +1,2 @@ +[break-spaces-newline-015.html] + expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/css-text/white-space/break-spaces-newline-016.html.ini b/tests/wpt/metadata-layout-2020/css/css-text/white-space/break-spaces-newline-016.html.ini new file mode 100644 index 00000000000..c329c7f08b9 --- /dev/null +++ b/tests/wpt/metadata-layout-2020/css/css-text/white-space/break-spaces-newline-016.html.ini @@ -0,0 +1,2 @@ +[break-spaces-newline-016.html] + expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/cssom-view/elementFromPoint-001.html.ini b/tests/wpt/metadata-layout-2020/css/cssom-view/elementFromPoint-001.html.ini new file mode 100644 index 00000000000..e38782d8c85 --- /dev/null +++ b/tests/wpt/metadata-layout-2020/css/cssom-view/elementFromPoint-001.html.ini @@ -0,0 +1,4 @@ +[elementFromPoint-001.html] + [CSSOM View - 5 - extensions to the Document interface] + expected: FAIL + diff --git a/tests/wpt/metadata-layout-2020/css/cssom-view/elementsFromPoint-iframes.html.ini b/tests/wpt/metadata-layout-2020/css/cssom-view/elementsFromPoint-iframes.html.ini index 171592fc08f..6ef8bb1049f 100644 --- a/tests/wpt/metadata-layout-2020/css/cssom-view/elementsFromPoint-iframes.html.ini +++ b/tests/wpt/metadata-layout-2020/css/cssom-view/elementsFromPoint-iframes.html.ini @@ -2,3 +2,6 @@ [elementsFromPoint on the root document for points in iframe elements] expected: FAIL + [elementsFromPoint on inner documents] + expected: FAIL + diff --git a/tests/wpt/metadata-layout-2020/css/cssom-view/elementsFromPoint-invalid-cases.html.ini b/tests/wpt/metadata-layout-2020/css/cssom-view/elementsFromPoint-invalid-cases.html.ini deleted file mode 100644 index e181af5397f..00000000000 --- a/tests/wpt/metadata-layout-2020/css/cssom-view/elementsFromPoint-invalid-cases.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[elementsFromPoint-invalid-cases.html] - [The root element is the last element returned for otherwise empty queries within the viewport] - expected: FAIL - diff --git a/tests/wpt/metadata-layout-2020/custom-elements/custom-element-reaction-queue.html.ini b/tests/wpt/metadata-layout-2020/custom-elements/custom-element-reaction-queue.html.ini new file mode 100644 index 00000000000..bd5d04c5256 --- /dev/null +++ b/tests/wpt/metadata-layout-2020/custom-elements/custom-element-reaction-queue.html.ini @@ -0,0 +1,4 @@ +[custom-element-reaction-queue.html] + [Upgrading a custom element must not invoke attributeChangedCallback for the attribute that is changed during upgrading] + expected: FAIL + diff --git a/tests/wpt/metadata-layout-2020/fetch/content-type/response.window.js.ini b/tests/wpt/metadata-layout-2020/fetch/content-type/response.window.js.ini index 1dfe13d8870..d1bbeb58882 100644 --- a/tests/wpt/metadata-layout-2020/fetch/content-type/response.window.js.ini +++ b/tests/wpt/metadata-layout-2020/fetch/content-type/response.window.js.ini @@ -312,12 +312,27 @@ [Response: combined response Content-Type: text/html;" \\" text/plain ";charset=GBK] expected: NOTRUN - [<iframe>: combined response Content-Type: text/html;x=" text/plain] + [<iframe>: separate response Content-Type: text/plain */*;charset=gbk] expected: FAIL - [<iframe>: separate response Content-Type: text/html;" \\" text/plain] + [<iframe>: separate response Content-Type: text/html;" text/plain] expected: FAIL - [<iframe>: separate response Content-Type: text/plain */*;charset=gbk] + [<iframe>: separate response Content-Type: text/html */*] + expected: FAIL + + [<iframe>: combined response Content-Type: text/html;" \\" text/plain] + expected: FAIL + + [<iframe>: combined response Content-Type: text/html;" text/plain] + expected: FAIL + + [<iframe>: combined response Content-Type: text/html */*] + expected: FAIL + + [<iframe>: separate response Content-Type: text/plain */*] + expected: FAIL + + [<iframe>: combined response Content-Type: text/html */*;charset=gbk] expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/fetch/nosniff/parsing-nosniff.window.js.ini b/tests/wpt/metadata-layout-2020/fetch/nosniff/parsing-nosniff.window.js.ini index 2023a855086..87c807a49ff 100644 --- a/tests/wpt/metadata-layout-2020/fetch/nosniff/parsing-nosniff.window.js.ini +++ b/tests/wpt/metadata-layout-2020/fetch/nosniff/parsing-nosniff.window.js.ini @@ -11,6 +11,3 @@ [X-Content-Type-Options%3A%20nosniff%0C] expected: FAIL - [X-Content-Type-Options%3A%20no%0D%0AX-Content-Type-Options%3A%20nosniff] - expected: FAIL - diff --git a/tests/wpt/metadata-layout-2020/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini b/tests/wpt/metadata-layout-2020/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini deleted file mode 100644 index 51f8272a6de..00000000000 --- a/tests/wpt/metadata-layout-2020/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[traverse_the_history_3.html] - [Multiple history traversals, last would be aborted] - expected: FAIL - diff --git a/tests/wpt/metadata-layout-2020/html/interaction/focus/the-autofocus-attribute/skip-document-with-fragment.html.ini b/tests/wpt/metadata-layout-2020/html/interaction/focus/the-autofocus-attribute/skip-document-with-fragment.html.ini index 6852d7663de..c12c0f8ae48 100644 --- a/tests/wpt/metadata-layout-2020/html/interaction/focus/the-autofocus-attribute/skip-document-with-fragment.html.ini +++ b/tests/wpt/metadata-layout-2020/html/interaction/focus/the-autofocus-attribute/skip-document-with-fragment.html.ini @@ -1,8 +1,4 @@ [skip-document-with-fragment.html] - expected: TIMEOUT [Autofocus elements in iframed documents with URL fragments should be skipped.] expected: FAIL - [Autofocus elements in top-level browsing context's documents with URI fragments should be skipped.] - expected: TIMEOUT - diff --git a/tests/wpt/metadata-layout-2020/html/interaction/focus/the-autofocus-attribute/supported-elements.html.ini b/tests/wpt/metadata-layout-2020/html/interaction/focus/the-autofocus-attribute/supported-elements.html.ini index c9d963b55d2..af14e19a466 100644 --- a/tests/wpt/metadata-layout-2020/html/interaction/focus/the-autofocus-attribute/supported-elements.html.ini +++ b/tests/wpt/metadata-layout-2020/html/interaction/focus/the-autofocus-attribute/supported-elements.html.ini @@ -7,7 +7,7 @@ expected: NOTRUN [Element with tabindex should support autofocus] - expected: FAIL + expected: TIMEOUT [Area element should support autofocus] expected: NOTRUN @@ -16,5 +16,5 @@ expected: NOTRUN [Non-HTMLElement should not support autofocus] - expected: TIMEOUT + expected: NOTRUN diff --git a/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html.ini b/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html.ini index 0218bc9ba9d..0407f0cc2b7 100644 --- a/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html.ini +++ b/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html.ini @@ -1,4 +1,5 @@ [iframe_sandbox_popups_nonescaping-2.html] + expected: TIMEOUT [Check that popups from a sandboxed iframe do not escape the sandbox] - expected: FAIL + expected: NOTRUN diff --git a/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini b/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini index 7d2b5231af2..f4f994c5d6f 100644 --- a/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini +++ b/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini @@ -1,5 +1,5 @@ [iframe_sandbox_popups_nonescaping-3.html] - expected: CRASH + expected: TIMEOUT [Check that popups from a sandboxed iframe do not escape the sandbox] - expected: FAIL + expected: NOTRUN diff --git a/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-img-element/currentSrc-blob-cache.html.ini b/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-img-element/currentSrc-blob-cache.html.ini new file mode 100644 index 00000000000..2c4a51d2910 --- /dev/null +++ b/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-img-element/currentSrc-blob-cache.html.ini @@ -0,0 +1,4 @@ +[currentSrc-blob-cache.html] + [currentSrc is right even if underlying image is a shared blob] + expected: FAIL + diff --git a/tests/wpt/metadata-layout-2020/performance-timeline/po-observe-type.any.js.ini b/tests/wpt/metadata-layout-2020/performance-timeline/po-observe-type.any.js.ini new file mode 100644 index 00000000000..6cfbce70872 --- /dev/null +++ b/tests/wpt/metadata-layout-2020/performance-timeline/po-observe-type.any.js.ini @@ -0,0 +1,15 @@ +[po-observe-type.any.html] + [Calling observe() with type and entryTypes should throw a TypeError] + expected: FAIL + + [Calling observe() without 'type' or 'entryTypes' throws a TypeError] + expected: FAIL + + +[po-observe-type.any.worker.html] + [Calling observe() with type and entryTypes should throw a TypeError] + expected: FAIL + + [Calling observe() without 'type' or 'entryTypes' throws a TypeError] + expected: FAIL + diff --git a/tests/wpt/metadata-layout-2020/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels.html.ini b/tests/wpt/metadata-layout-2020/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels.html.ini index da6575fdae8..2a3c2ce7c0a 100644 --- a/tests/wpt/metadata-layout-2020/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels.html.ini +++ b/tests/wpt/metadata-layout-2020/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels.html.ini @@ -80,3 +80,9 @@ [X Rendered audio for channel 5 does not equal [0,0.0626220703125,0.125030517578125,0.18695068359375,0.24810791015625,0.308319091796875,0.3673095703125,0.42486572265625,0.480743408203125,0.53472900390625,0.58660888671875,0.636199951171875,0.68328857421875,0.727691650390625,0.76922607421875,0.8077392578125...\] with an element-wise tolerance of {"absoluteThreshold":0.000030517578125,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[1\]\t3.6732959747314453e-1\t6.2622070312500000e-2\t3.0470752716064453e-1\t4.8658168859649127e+0\t3.0517578125000000e-5\n\t[2\]\t6.8329977989196777e-1\t1.2503051757812500e-1\t5.5826926231384277e-1\t4.4650639949963384e+0\t3.0517578125000000e-5\n\t[3\]\t9.0373212099075317e-1\t1.8695068359375000e-1\t7.1678143739700317e-1\t3.8340669508039502e+0\t3.0517578125000000e-5\n\t[4\]\t9.9780619144439697e-1\t2.4810791015625000e-1\t7.4969828128814697e-1\t3.0216621502152523e+0\t3.0517578125000000e-5\n\t[5\]\t9.5236867666244507e-1\t3.0831909179687500e-1\t6.4404958486557007e-1\t2.0889059484187866e+0\t3.0517578125000000e-5\n\t...and 44054 more errors.\n\tMax AbsError of 1.9961981773376465e+0 at index of 18538.\n\t[18538\]\t-9.9879217147827148e-1\t9.9740600585937500e-1\t1.9961981773376465e+0\t2.0013897706758867e+0\t3.0517578125000000e-5\n\tMax RelError of Infinity at index of 12348.\n\t[12348\]\t9.5105654001235962e-1\t0.0000000000000000e+0\t9.5105654001235962e-1\tInfinity\t3.0517578125000000e-5\n] expected: FAIL + [X Rendered audio for channel 5 does not equal [0,0.0626220703125,0.125030517578125,0.18695068359375,0.24810791015625,0.308319091796875,0.3673095703125,0.42486572265625,0.480743408203125,0.53472900390625,0.58660888671875,0.636199951171875,0.68328857421875,0.727691650390625,0.76922607421875,0.8077392578125...\] with an element-wise tolerance of {"absoluteThreshold":0.000030517578125,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[1\]\t3.6732959747314453e-1\t6.2622070312500000e-2\t3.0470752716064453e-1\t4.8658168859649127e+0\t3.0517578125000000e-5\n\t[2\]\t6.8329977989196777e-1\t1.2503051757812500e-1\t5.5826926231384277e-1\t4.4650639949963384e+0\t3.0517578125000000e-5\n\t[3\]\t9.0373212099075317e-1\t1.8695068359375000e-1\t7.1678143739700317e-1\t3.8340669508039502e+0\t3.0517578125000000e-5\n\t[4\]\t9.9780619144439697e-1\t2.4810791015625000e-1\t7.4969828128814697e-1\t3.0216621502152523e+0\t3.0517578125000000e-5\n\t[5\]\t9.5236867666244507e-1\t3.0831909179687500e-1\t6.4404958486557007e-1\t2.0889059484187866e+0\t3.0517578125000000e-5\n\t...and 44051 more errors.\n\tMax AbsError of 1.9999794363975525e+0 at index of 19632.\n\t[19632\]\t9.9997943639755249e-1\t-1.0000000000000000e+0\t1.9999794363975525e+0\t1.9999794363975525e+0\t3.0517578125000000e-5\n\tMax RelError of Infinity at index of 12348.\n\t[12348\]\t9.5105654001235962e-1\t0.0000000000000000e+0\t9.5105654001235962e-1\tInfinity\t3.0517578125000000e-5\n] + expected: FAIL + + [X Rendered audio for channel 5 does not equal [0,0.0626220703125,0.125030517578125,0.18695068359375,0.24810791015625,0.308319091796875,0.3673095703125,0.42486572265625,0.480743408203125,0.53472900390625,0.58660888671875,0.636199951171875,0.68328857421875,0.727691650390625,0.76922607421875,0.8077392578125...\] with an element-wise tolerance of {"absoluteThreshold":0.000030517578125,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[1\]\t3.6732959747314453e-1\t6.2622070312500000e-2\t3.0470752716064453e-1\t4.8658168859649127e+0\t3.0517578125000000e-5\n\t[2\]\t6.8329977989196777e-1\t1.2503051757812500e-1\t5.5826926231384277e-1\t4.4650639949963384e+0\t3.0517578125000000e-5\n\t[3\]\t9.0373212099075317e-1\t1.8695068359375000e-1\t7.1678143739700317e-1\t3.8340669508039502e+0\t3.0517578125000000e-5\n\t[4\]\t9.9780619144439697e-1\t2.4810791015625000e-1\t7.4969828128814697e-1\t3.0216621502152523e+0\t3.0517578125000000e-5\n\t[5\]\t9.5236867666244507e-1\t3.0831909179687500e-1\t6.4404958486557007e-1\t2.0889059484187866e+0\t3.0517578125000000e-5\n\t...and 44047 more errors.\n\tMax AbsError of 1.9999794363975525e+0 at index of 37272.\n\t[37272\]\t9.9997943639755249e-1\t-1.0000000000000000e+0\t1.9999794363975525e+0\t1.9999794363975525e+0\t3.0517578125000000e-5\n\tMax RelError of Infinity at index of 12348.\n\t[12348\]\t9.5105654001235962e-1\t0.0000000000000000e+0\t9.5105654001235962e-1\tInfinity\t3.0517578125000000e-5\n] + expected: FAIL + diff --git a/tests/wpt/metadata-layout-2020/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini b/tests/wpt/metadata-layout-2020/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini index 7e05d1788d4..6c35c286437 100644 --- a/tests/wpt/metadata-layout-2020/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini +++ b/tests/wpt/metadata-layout-2020/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini @@ -134,3 +134,9 @@ [X Stitched sine-wave buffers at sample rate 44100 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.000090957,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[31080\]\t-1.1377083450655894e+22\t5.6332010030746460e-1\t1.1377083450655894e+22\t2.0196480552435802e+22\t9.0957000000000003e-5\n\t[31081\]\t4.5654303967702540e-41\t6.1397600173950195e-1\t6.1397600173950195e-1\t1.0000000000000000e+0\t9.0957000000000003e-5\n\tMax AbsError of 1.1377083450655894e+22 at index of 31080.\n\tMax RelError of 2.0196480552435802e+22 at index of 31080.\n] expected: FAIL + [X Stitched sine-wave buffers at sample rate 44100 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.000090957,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[31080\]\t-1.7359996676420403e+17\t5.6332010030746460e-1\t1.7359996676420403e+17\t3.0817286063368198e+17\t9.0957000000000003e-5\n\t[31081\]\t4.5750993561740953e-41\t6.1397600173950195e-1\t6.1397600173950195e-1\t1.0000000000000000e+0\t9.0957000000000003e-5\n\tMax AbsError of 1.7359996676420403e+17 at index of 31080.\n\tMax RelError of 3.0817286063368198e+17 at index of 31080.\n] + expected: FAIL + + [X SNR (-301.35690681171843 dB) is not greater than or equal to 85.58. Got -301.35690681171843.] + expected: FAIL + diff --git a/tests/wpt/metadata-layout-2020/workers/semantics/multiple-workers/005.html.ini b/tests/wpt/metadata-layout-2020/workers/semantics/multiple-workers/005.html.ini index 268949ced5c..f584fce5df1 100644 --- a/tests/wpt/metadata-layout-2020/workers/semantics/multiple-workers/005.html.ini +++ b/tests/wpt/metadata-layout-2020/workers/semantics/multiple-workers/005.html.ini @@ -1,4 +1,5 @@ [005.html] + expected: ERROR [dedicated worker in shared worker in dedicated worker] expected: FAIL diff --git a/tests/wpt/metadata/2dcontext/path-objects/2d.path.isPointInStroke.scaleddashes.html.ini b/tests/wpt/metadata/2dcontext/path-objects/2d.path.isPointInStroke.scaleddashes.html.ini new file mode 100644 index 00000000000..3a956f90011 --- /dev/null +++ b/tests/wpt/metadata/2dcontext/path-objects/2d.path.isPointInStroke.scaleddashes.html.ini @@ -0,0 +1,4 @@ +[2d.path.isPointInStroke.scaleddashes.html] + [isPointInStroke() should return correct results on dashed paths at high scale factors] + expected: FAIL + diff --git a/tests/wpt/metadata/FileAPI/url/url-in-tags-revoke.window.js.ini b/tests/wpt/metadata/FileAPI/url/url-in-tags-revoke.window.js.ini index d4f62ed7113..faa00f45ecf 100644 --- a/tests/wpt/metadata/FileAPI/url/url-in-tags-revoke.window.js.ini +++ b/tests/wpt/metadata/FileAPI/url/url-in-tags-revoke.window.js.ini @@ -7,7 +7,7 @@ expected: FAIL [Opening a blob URL in a new window immediately before revoking it works.] - expected: FAIL + expected: TIMEOUT [Opening a blob URL in a noopener about:blank window immediately before revoking it works.] expected: TIMEOUT diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index eb05c2af50b..aa4827c60e6 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -61,6 +61,34 @@ ] }, "css-flexbox": { + "flex-shrink-large-value-crash.html": [ + "a48bec65581e9f350a74d2b7b937df8fbe9113d5", + [ + null, + {} + ] + ], + "inline-flex-editing-crash.html": [ + "01917e3726c99b6bdb57101c368085b565cc3002", + [ + null, + {} + ] + ], + "inline-flex-editing-with-updating-text-crash.html": [ + "bdf7df85d7b33c937b28c574e60e5695c6aa8a97", + [ + null, + {} + ] + ], + "inline-flex-frameset-main-axis-crash.html": [ + "434897cc7ac0636d7c494a217e6a870aadd4f829", + [ + null, + {} + ] + ], "negative-flex-margins-crash.html": [ "8bcc566c0f702ef6a8e581bb6790476c71f19bcb", [ @@ -114,6 +142,22 @@ ] ] }, + "grid-definition": { + "grid-add-item-with-positioned-items-crash.html": [ + "7b2ed99f223ed4333c265f242b3f043afd9232b6", + [ + null, + {} + ] + ], + "grid-add-positioned-block-item-after-inline-item-crash.html": [ + "4b7aa9913a7cdf7c8156ad33419ca2349905319f", + [ + null, + {} + ] + ] + }, "subgrid": { "contain-strict-nested-subgrid-crash.html": [ "a98e43777eee9347ba1d69a4b133140cea0577fc", @@ -318,6 +362,13 @@ ] ] }, + "effect-reference-reset-style-delete-crash.html": [ + "e1c0eb9aeca3b5e21dfaac85b1ca7d3397f7703e", + [ + null, + {} + ] + ], "feimage-circular-reference-foreign-object-crash.html": [ "00f0e362237ab3fdb856ea648e950608e8c3f06c", [ @@ -117226,6 +117277,19 @@ {} ] ], + "root-element-opacity-change.html": [ + "de2599de4911dc99c997de16d8908a180e4f3bc6", + [ + null, + [ + [ + "/css/compositing/root-element-opacity-change-ref.html", + "==" + ] + ], + {} + ] + ], "root-element-opacity.html": [ "4885d805ad3f3b59d60ccbf3047e8694d7be0f18", [ @@ -124999,6 +125063,19 @@ "css-color-adjust": { "rendering": { "dark-color-scheme": { + "color-scheme-change-checkbox.html": [ + "ae0dc62b7c8760862fe6c279cec425db0afac474", + [ + null, + [ + [ + "/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-change-checkbox-notref.html", + "!=" + ] + ], + {} + ] + ], "color-scheme-iframe-background-mismatch-alpha.html": [ "26c58198c46b0ed2b1c6037aa0ca50ea2e059241", [ @@ -140409,6 +140486,45 @@ ] }, "alignment": { + "grid-baseline-001.html": [ + "ef8c0e4d3403f6aab952ae844d84490d7e569055", + [ + null, + [ + [ + "/css/css-grid/alignment/references/grid-baseline-001-ref.html", + "==" + ] + ], + {} + ] + ], + "grid-baseline-002.html": [ + "b52eeff27e51e3136c4425e7761838ab8ceecc9f", + [ + null, + [ + [ + "/css/css-grid/alignment/references/grid-baseline-002-ref.html", + "==" + ] + ], + {} + ] + ], + "grid-baseline-003.html": [ + "bd411abed91841b00a518e12cbd24a2bb60a4f57", + [ + null, + [ + [ + "/css/css-grid/alignment/references/grid-baseline-003-ref.html", + "==" + ] + ], + {} + ] + ], "grid-baseline-align-cycles-001.html": [ "cc6b3b50f984a97838f05e340c51f33f335e0f97", [ @@ -141663,6 +141779,19 @@ ] ], "grid-definition": { + "flex-item-grid-container-percentage-rows-001.html": [ + "ba655ce8a17d6482071d39e66684b50ebe749822", + [ + null, + [ + [ + "/css/css-grid/reference/flex-item-grid-container-percentage-rows-001-ref.html", + "==" + ] + ], + {} + ] + ], "fr-unit-with-percentage.html": [ "82c97abdd5740d466f049d8b45b67e241f204899", [ @@ -141728,6 +141857,19 @@ {} ] ], + "grid-auto-repeat-positioned-container-001.html": [ + "309ad85671204b52def9309a3147ee031f72948f", + [ + null, + [ + [ + "/css/css-grid/grid-definition/grid-auto-repeat-positioned-container-001-ref.html", + "==" + ] + ], + {} + ] + ], "grid-layout-auto-tracks.html": [ "2cc3614d9ec60581f01b4e5ff7ffe624d7f3ce11", [ @@ -142276,6 +142418,19 @@ {} ] ], + "grid-item-margins-and-writing-modes-001.html": [ + "5209940a9699d6a108f815f81eb4d3b4527dcf79", + [ + null, + [ + [ + "/css/css-grid/grid-items/grid-item-margins-and-writing-modes-001-ref.html", + "==" + ] + ], + {} + ] + ], "grid-item-overflow-auto-max-height-percentage.html": [ "62273b87e49170853bc14e36ecc3fb7b148ff6ac", [ @@ -143355,6 +143510,19 @@ {} ] ], + "remove-svg-grid-item-001.html": [ + "5e196c82c64bb52ee5b445b664eb5bc0dbd60573", + [ + null, + [ + [ + "/css/css-grid/reference/grid-item-script-001-ref.html", + "==" + ] + ], + {} + ] + ], "table-with-infinite-max-intrinsic-width.html": [ "877e982cd4c5987f131587da33a23f3b7a49d538", [ @@ -143367,6 +143535,19 @@ ], {} ] + ], + "whitespace-in-grid-item-001.html": [ + "f79baab6f058faea696b63d4be9fa9894228e17c", + [ + null, + [ + [ + "/css/css-grid/grid-items/whitespace-in-grid-item-001-ref.html", + "==" + ] + ], + {} + ] ] }, "grid-model": { @@ -143695,6 +143876,19 @@ {} ] ], + "grid-floats-no-intrude-002.html": [ + "9c26e021050597761a8db26c8a0e71429e1323e7", + [ + null, + [ + [ + "/css/css-grid/grid-model/grid-floats-no-intrude-002-ref.html", + "==" + ] + ], + {} + ] + ], "grid-inline-first-letter-001.html": [ "bc62c1770d2ba46644aed25b26d3955d6745d0ea", [ @@ -143877,6 +144071,19 @@ {} ] ], + "grid-margins-no-collapse-002.html": [ + "f644a6fb53c970f723019e2cc0399f63585f0509", + [ + null, + [ + [ + "/css/css-grid/grid-model/grid-margins-no-collapse-002-ref.html", + "==" + ] + ], + {} + ] + ], "grid-multicol-001.html": [ "553a33e6a3417557bc6fdb1f34375c4117a2e04f", [ @@ -148806,6 +149013,19 @@ {} ] ], + "clip-path-descendant-text-mutated-001.html": [ + "e41dacc0b54f3f1936d23b3fb6204f394395db37", + [ + null, + [ + [ + "/css/css-masking/clip-path/reference/clip-path-descendant-text-mutated-001-ref.html", + "==" + ] + ], + {} + ] + ], "clip-path-element-userSpaceOnUse-001.html": [ "1381f53cb0c0aefc82a91a232b712d18be625b97", [ @@ -149287,6 +149507,19 @@ {} ] ], + "clip-path-reference-restore.html": [ + "eccebd8fbcc3a556a13829be3e25c4efead3aafc", + [ + null, + [ + [ + "/css/css-masking/clip-path/reference/clip-path-reference-restore-ref.html", + "==" + ] + ], + {} + ] + ], "clip-path-svg-invalidate.html": [ "0bf921c7cf125c1e8a9e6842c62f294b13104790", [ @@ -149313,6 +149546,19 @@ {} ] ], + "clip-path-transform-mutated-002.html": [ + "de00a013ad44b3f5c928e46829b75151e936c2af", + [ + null, + [ + [ + "/css/css-masking/clip-path/reference/clip-path-transform-mutated-002-ref.html", + "==" + ] + ], + {} + ] + ], "clip-path-url-reference-change-from-empty.html": [ "2de0bb866f1c837887d6fa3c5889f8d38da3c055", [ @@ -163589,12 +163835,16 @@ ] ], "hyphens-auto-inline-010.html": [ - "cb6a6222b7b44ff8f5956c3c5041ccb5b3b058de", + "03776617bf6ec5266e1f0ade3c5e4241242589fd", [ null, [ [ - "/css/css-text/hyphens/reference/hyphens-auto-inline-010-ref.html", + "/css/css-text/hyphens/reference/hyphens-auto-inline-010M-ref.html", + "==" + ], + [ + "/css/css-text/hyphens/reference/hyphens-auto-inline-010H-ref.html", "==" ] ], @@ -163615,12 +163865,16 @@ ] ], "hyphens-manual-011.html": [ - "060dc75619a188cdfe4452b2a1ea941992d38cb4", + "862ca80fc647c96016ce15062fa7084ff6bfd5ef", [ null, [ [ - "/css/css-text/hyphens/reference/hyphens-manual-011-ref.html", + "/css/css-text/hyphens/reference/hyphens-manual-011M-ref.html", + "==" + ], + [ + "/css/css-text/hyphens/reference/hyphens-manual-011H-ref.html", "==" ] ], @@ -163628,12 +163882,16 @@ ] ], "hyphens-manual-012.html": [ - "871f7c39b69ddd8b37a3e57acaae92c6fe8e56f8", + "7ffece5ff6dd6a1cbf82afbafdd50ce0d5f0142c", [ null, [ [ - "/css/css-text/hyphens/reference/hyphens-manual-011-ref.html", + "/css/css-text/hyphens/reference/hyphens-manual-011M-ref.html", + "==" + ], + [ + "/css/css-text/hyphens/reference/hyphens-manual-011H-ref.html", "==" ] ], @@ -163641,12 +163899,16 @@ ] ], "hyphens-manual-013.html": [ - "17e3f6f8157aeb302789fa04e8366e44109cf6b8", + "31c57c5382a1800050c9a9ae5262ea39397e661c", [ null, [ [ - "/css/css-text/hyphens/reference/hyphens-manual-013-ref.html", + "/css/css-text/hyphens/reference/hyphens-manual-013M-ref.html", + "==" + ], + [ + "/css/css-text/hyphens/reference/hyphens-manual-013H-ref.html", "==" ] ], @@ -163667,12 +163929,16 @@ ] ], "hyphens-manual-inline-011.html": [ - "ec08f4d3887a15efd3540b7696a2b60ed6c4b2f2", + "9eba15b5291798f29f1796dbf38b45043c94893f", [ null, [ [ - "/css/css-text/hyphens/reference/hyphens-manual-inline-011-ref.html", + "/css/css-text/hyphens/reference/hyphens-manual-inline-011M-ref.html", + "==" + ], + [ + "/css/css-text/hyphens/reference/hyphens-manual-inline-011H-ref.html", "==" ] ], @@ -163680,12 +163946,16 @@ ] ], "hyphens-manual-inline-012.html": [ - "0267fa7baaaa95e6c40221b1d85f490b5485bc7e", + "b2aa04f7a6fb5eea3872d5b4337cd218f8abfa2b", [ null, [ [ - "/css/css-text/hyphens/reference/hyphens-manual-inline-012-ref.html", + "/css/css-text/hyphens/reference/hyphens-manual-inline-012M-ref.html", + "==" + ], + [ + "/css/css-text/hyphens/reference/hyphens-manual-inline-012H-ref.html", "==" ] ], @@ -171577,6 +171847,84 @@ {} ] ], + "break-spaces-newline-011.html": [ + "068119c29290fdded0dee4e7fa425af397706ea9", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "break-spaces-newline-012.html": [ + "766bcc1feeed581a9bb54cb48a80d187a791af7d", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "break-spaces-newline-013.html": [ + "5b45e5c1ccede4b4a1a5bfa77dedb31b14199bee", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "break-spaces-newline-014.html": [ + "56281dee347143147049e4c9c8a8ab4fda1a4e8a", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "break-spaces-newline-015.html": [ + "96a7d83663887bd3cf7c8efd9edd4be8e0112d0b", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "break-spaces-newline-016.html": [ + "4156e6a7da10e7bff9468d96982bfc359ba42a1d", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "break-spaces-tab-001.html": [ "4b01a60395a6c1133c7af8af957dd70859db4823", [ @@ -176900,7 +177248,7 @@ ] ], "text-underline-position-from-font-variable.html": [ - "0459a2ea1d48edca515b4d14add39ffa82a4469b", + "dc7ede0cd1f60a21fa19bdada52fee03f1cce272", [ null, [ @@ -234651,6 +234999,19 @@ ] ], "reftests": { + "display-none-mask.html": [ + "5a746c9fdaec71c5c530e393aaa1f641f55c89b8", + [ + null, + [ + [ + "/svg/painting/reftests/display-none-mask-ref.html", + "==" + ] + ], + {} + ] + ], "marker-path-001.svg": [ "7fb4adf4277321eb69e50fecb9018c1950aef4ca", [ @@ -235645,6 +236006,19 @@ {} ] ], + "use-adopted-with-external-resource.tentative.svg": [ + "830d4555e5ada27aabb6f3cb128340646000fba9", + [ + null, + [ + [ + "/svg/struct/reftests/reference/green-100x100.svg", + "==" + ] + ], + {} + ] + ], "use-external-resource-with-revalidation.tentative.html": [ "d899165fa9ccef15d893b599ec6a8f4e005bcb36", [ @@ -239525,7 +239899,7 @@ [] ], ".taskcluster.yml": [ - "815648df5121e596dced15ce9384815d2e6c426f", + "556b9914d5b53f72010dd59831c710623a64ed57", [] ], ".well-known": { @@ -240427,7 +240801,7 @@ [] ], "tests2d.yaml": [ - "42a572995a6997b5f61a54ae65abd0dc6b59626d", + "d8ccbe13f6dbb3edf891c9e507dbf6449ec942af", [] ], "tests2dtext.yaml": [ @@ -283316,6 +283690,10 @@ "27cfb11b8f480cdd3cc94c5467bf6b3dc9b831db", [] ], + "root-element-opacity-change-ref.html": [ + "be3d3713694f8ff7112edf3b87162125eb4eaf16", + [] + ], "root-element-opacity-ref.html": [ "be2348ab967f2ff4c161f8bbb9999a0bd8523e82", [] @@ -285022,6 +285400,10 @@ }, "rendering": { "dark-color-scheme": { + "color-scheme-change-checkbox-notref.html": [ + "921482afcdf10cc38d113d0d428e1df43d09dd66", + [] + ], "color-scheme-iframe-background-ref.html": [ "8cc4618ede4af030adc8fe5f119deccf3c2e3882", [] @@ -294372,6 +294754,18 @@ [] ], "references": { + "grid-baseline-001-ref.html": [ + "6a02ae4796a0d462ad21fe866c2bed035a5032e6", + [] + ], + "grid-baseline-002-ref.html": [ + "43634e58c381681883211711c4bcb4a3aae97db7", + [] + ], + "grid-baseline-003-ref.html": [ + "446c42f1a29694445b485e413dde57aa40b4b7ea", + [] + ], "grid-baseline-align-cycles-001-ref.html": [ "ca1097e171e8f4b18fd72c1e7614bff860b2cb36", [] @@ -294411,6 +294805,10 @@ "975c94b795c1c1e53759a5f1e0ec0f6ee1a6889f", [] ], + "grid-auto-repeat-positioned-container-001-ref.html": [ + "a017563aa36082944feb7fe88a50f3dcc8a50358", + [] + ], "grid-support-named-grid-lines-002-ref.html": [ "d65696428c2542c4851207df24e1d3638e6c49af", [] @@ -294439,6 +294837,10 @@ [] ], "grid-items": { + "grid-item-margins-and-writing-modes-001-ref.html": [ + "86553ef6f4077f3c6bc348496e513d7960d7b79f", + [] + ], "grid-item-overflow-auto-max-height-percentage-ref.html": [ "96a3ca1d5032e10e0c4491cc17541084543daab2", [] @@ -294504,7 +294906,11 @@ "f709bf09e5ae6bf48911b69691b0acb5c6f2760e", [] ] - } + }, + "whitespace-in-grid-item-001-ref.html": [ + "1531d98a64f705394d4c09240e6fadd7d69fb87f", + [] + ] }, "grid-model": { "grid-container-ignores-first-letter-002-ref.html": [ @@ -294523,6 +294929,14 @@ "a51134751616fdb1eede6a1774c3edd6571ddc28", [] ], + "grid-floats-no-intrude-002-ref.html": [ + "070980ed27cebf226e21583c64c39e6ac195e8dc", + [] + ], + "grid-margins-no-collapse-002-ref.html": [ + "ce56a5664565796e16f82f71ed1dc6b5a51db7ed", + [] + ], "reference": { "100x100-grey-box-with-horizontal-scrollbar.html": [ "ba8335873d254e66cad25c0e61d3b0173edefb16", @@ -294591,6 +295005,10 @@ "422185a8e3f855cfffa1cb4b8b91b1ef6dc5cb42", [] ], + "flex-item-grid-container-percentage-rows-001-ref.html": [ + "1f4b23952e13511927637e047dd6ecf78d9c73bb", + [] + ], "fr-unit-ref.html": [ "e7999ae7d18b36177e277a4baaddb3d30fbf3c90", [] @@ -295762,6 +296180,10 @@ "4337cdf63758c06d261eb42bd0abc595261350c1", [] ], + "clip-path-descendant-text-mutated-001-ref.html": [ + "f718ea6abfbab54333ba674ff0dcd320d8672bcd", + [] + ], "clip-path-ellipse-ref.html": [ "5adc91a5c00f27f0d3225c99a6c2534b5b868a8d", [] @@ -295810,6 +296232,10 @@ "f718ea6abfbab54333ba674ff0dcd320d8672bcd", [] ], + "clip-path-reference-restore-ref.html": [ + "683511fd8007f87aa34cf98edc0b5c327b8036a7", + [] + ], "clip-path-square-001-ref.html": [ "6bc5a16754b1d174bec65817d02d25fb7615f305", [] @@ -295834,6 +296260,10 @@ "f718ea6abfbab54333ba674ff0dcd320d8672bcd", [] ], + "clip-path-transform-mutated-002-ref.html": [ + "f718ea6abfbab54333ba674ff0dcd320d8672bcd", + [] + ], "green-100x100.html": [ "f718ea6abfbab54333ba674ff0dcd320d8672bcd", [] @@ -299418,32 +299848,52 @@ "13841121c6429428bdccde7f971e9e582b6b7ad3", [] ], - "hyphens-auto-inline-010-ref.html": [ - "ce1296eb78ce970e4396cc6ee4ab21bbe7d5be64", + "hyphens-auto-inline-010H-ref.html": [ + "c3e6271c19fe044463352258f89f72c00842bdc6", + [] + ], + "hyphens-auto-inline-010M-ref.html": [ + "ace0c5e7537816c5807321eee0360be0ff87e9fc", [] ], "hyphens-manual-010-ref.html": [ "f79ce17a4c71bfac19b543b70bb8e95510bad321", [] ], - "hyphens-manual-011-ref.html": [ - "98581bd37c0d3e2be1381bb2829a3146821e63b8", + "hyphens-manual-011H-ref.html": [ + "99612206f8ed6e026b199ccd87fab1165bdc21df", + [] + ], + "hyphens-manual-011M-ref.html": [ + "191095a413bd42bb84ed71ddfaf73f363833e465", [] ], - "hyphens-manual-013-ref.html": [ - "9fa6bee4215ea277224d0bf0469a8abe304beb26", + "hyphens-manual-013H-ref.html": [ + "12ad0ed5059f4dd67d9ad722bc539695334562f9", + [] + ], + "hyphens-manual-013M-ref.html": [ + "3c7121242b732d7257bb07ecc143a8eeff7d4c7d", [] ], "hyphens-manual-inline-010-ref.html": [ "a55fe859ff225322e96e5bb259a1f89722c16e7f", [] ], - "hyphens-manual-inline-011-ref.html": [ - "17254a09f17266c0f1e9470c80827b91b9b84958", + "hyphens-manual-inline-011H-ref.html": [ + "0cd1ef9f9b3901315e757b0a3f89930afa6afe85", + [] + ], + "hyphens-manual-inline-011M-ref.html": [ + "836919648e7df642016927d72926ccddabed1f58", + [] + ], + "hyphens-manual-inline-012H-ref.html": [ + "8b2ff04ade5e1322b30a66d849a6a4b58be82e40", [] ], - "hyphens-manual-inline-012-ref.html": [ - "5dfc2b8e221c14549b60f02a60fc0f33171f9fd7", + "hyphens-manual-inline-012M-ref.html": [ + "0c8db033c8b8356e6201d58e83d6f5f6d0c1481c", [] ], "hyphens-out-of-flow-001-ref.html": [ @@ -302390,7 +302840,7 @@ [] ], "text-underline-position-from-font-variable-ref.html": [ - "e621545772d1baa59a8cd37c44d18384551d9d98", + "e9e5252194b66f348595b42ae58c0d2c823d422e", [] ] }, @@ -309422,6 +309872,10 @@ "4007ebba43631ad69dafe6cf3dae74481ab219af", [] ], + "height-keyword-classes.css": [ + "2f8477959343b306c4bed7820f0e5a77596f1c0e", + [] + ], "import-green.css": [ "537104e663364492c6ef388e4afce190e9c5bc58", [] @@ -309577,7 +310031,7 @@ [] ], "width-keyword-classes.css": [ - "b5c84a5d5f4611ffe3570c60ab2f55cf093f8ca8", + "138433c11415025d431c9dab37dbcdcd557c6ffa", [] ] }, @@ -313803,7 +314257,7 @@ [] ], "testharness-api.md": [ - "2ee52786add43f036fe0ac7c8b66acc892d876ff", + "bb855b1723890c809539294159bb815ea1356f25", [] ], "testharness-tutorial.md": [ @@ -319748,7 +320202,7 @@ [] ], "reporting-empty-frame.html.headers": [ - "66302f108fd5fc9142460a60f6f20b5303b46780", + "b7c8b304178b4f4aa213703d6870e84267acba6c", [] ], "require-corp-sw-import-scripts.js": [ @@ -329410,7 +329864,7 @@ [] ], "netinfo.idl": [ - "729678396884a19874239468075bfd587c621305", + "530deb998c4656a4fda32af7f6286e895a15e082", [] ], "notifications.idl": [ @@ -329634,7 +330088,7 @@ [] ], "webauthn.idl": [ - "8dceeb5768b3b31934f126d40bcce70e0209ebca", + "34a3df1ce1afbf925fa6166857429e5cd69660a5", [] ], "webdriver.idl": [ @@ -329809,7 +330263,7 @@ [] ], "invisible-images.js": [ - "fd13e9454deda3c69228aab096ce032e8e1b7cff", + "bad078e35f0cd124eb688fe5937ad2686d7c5bbe", [] ], "largest-contentful-paint-helpers.js": [ @@ -332027,7 +332481,7 @@ [] ], "utils.js": [ - "a1fb993eb90e9e24f6502e4aed53a79420d360a6", + "2ee0e3d0626da211089f43e5484b7fc7d8140e52", [] ] } @@ -334723,7 +335177,7 @@ [] ], "webxr-test.js": [ - "a04aa37229cbf4fbc3df984fac90b03bc216fcdd", + "a9dd9b1d7c7c05d5aebe2f5a19f7dc3bc989239c", [] ], "webxr-test.js.headers": [ @@ -335068,8 +335522,16 @@ [] ] }, + "assert_implements.html": [ + "6e35f385027a53135f433dea27a63907c7771754", + [] + ], + "assert_implements_optional.html": [ + "4f23e203c57a50352b686bf0c73930029186aa4d", + [] + ], "assert_object_equals.html": [ - "bb3a97e471a0ddf89836560c4db004ea577f758f", + "19296b8293f25055a2100ebd884dc9dbbd7999ff", [] ], "basic.html": [ @@ -335088,6 +335550,10 @@ "13d01b81f351801e4d7dbb2d03ca68d1b594bff2", [] ], + "helpers.js": [ + "b273a72589f7d334de58ee780abbc4c0f4e22ebd", + [] + ], "late-test.html": [ "693d7e3c818ed7fbc5503d09c91b9da7f7139bac", [] @@ -335152,7 +335618,7 @@ [] ], "testharness.js": [ - "63883e15504d78c60344338d8b4e97da2d0109a3", + "15df5b6a342b2586d50b6de0fed1b60a8b752452", [] ], "testharness.js.headers": [ @@ -338679,6 +339145,10 @@ [] ], "reftests": { + "display-none-mask-ref.html": [ + "7835597d961a9c9feb0fff92b0f651e164456c12", + [] + ], "marker-path-001-ref.svg": [ "202ac3420dc080f85c4a2cac5e13ccbea6d0235e", [] @@ -339009,6 +339479,10 @@ "etag-max-age-zero-icons.svg.headers": [ "3f0c26c8feaf58e51ef387c972c2b772166d0fe8", [] + ], + "sprites.svg": [ + "f73b8851913f402aa41adac40360b15acbad1119", + [] ] } }, @@ -339343,7 +339817,7 @@ [] ], "jobs.py": [ - "3d809efa37ccff2c258343b64791762fc507a90f", + "a8ae5d237a448bd45f049b446827c8c73244778a", [] ], "make_hosts_file.py": [ @@ -339359,7 +339833,7 @@ [] ], "run_tc.py": [ - "69625710ad91edbc8db25c3be380f52f4db797a8", + "e8dfa6163e55054e5a18743cb89d94925f92f405", [] ], "taskcluster-run.py": [ @@ -339428,7 +339902,7 @@ }, "tests": { "test_jobs.py": [ - "94f7998770cf5d8bad36d188dd63e253f98199a8", + "3790c04e7b290aac274fa48048439759d4478f81", [] ], "test_pr_preview.py": [ @@ -339455,7 +339929,7 @@ [] ], "README.md": [ - "450981f686bface2d9243e5628040bb6b2f6c4e0", + "8b0737359ea5fa64f4a8c1c7536705951166bc18", [] ], "__init__.py": [ @@ -339473,7 +339947,7 @@ ] }, "frontend.py": [ - "976156cf65a00821a11a3351301b47c1078c8416", + "59a1cff2ebd0efda06fadd144a84b5d35b2d81c8", [] ], "retry.py": [ @@ -339774,7 +340248,7 @@ [] ], "test_manifest.py": [ - "6d329ad38f969106c28e73de81dcbf1c468f9adf", + "b618d75ec1ed2e955e27f763446c1b0fc3987f1c", [] ], "test_sourcefile.py": [ @@ -344637,7 +345111,7 @@ ] }, "requirements.txt": [ - "c7ddcd75456a5fd532e84d227ba3daa71accc4d9", + "9b84e7334bbcb0702e9379d49192e4cc38a5e1c5", [] ], "requirements_android_webview.txt": [ @@ -346458,12 +346932,16 @@ "animation-model": { "animation-types": { "property-list.js": [ - "2f91ebc372cadb044282707f6a1a3e3f1fec47f5", + "32de670ed3c8f302baa5f156372fbd539485840c", [] ], "property-types.js": [ "dba946d38869f925a990c8889a2eb06d0e2aeb21", [] + ], + "property-utils.js": [ + "d3a7b12a61f94653cb86e84cbbbe0d56efafe4de", + [] ] } }, @@ -347519,320 +347997,272 @@ "c7a75d7d221561df02c42470ad5e751324de645d", [] ], - "constants.js": [ - "28771fb0e3e96d273436446e8c254a28c92aebeb", - [] - ], - "framework": { - "allowed_characters.js": [ - "af8f45172b52b3cdc6246218c40e5484a7517a63", - [] - ], - "collect_garbage.js": [ - "dc5a9caf850b967ea0779fee6b7c725376c0bbbb", - [] - ], - "fixture.js": [ - "11b5f405456b4d5e635571b00247cce4e1fc5942", - [] - ], - "generate_minimal_query_list.js": [ - "12311acac0516009516147e2914910176613dd81", - [] - ], - "gpu": { - "implementation.js": [ - "653b60ab433c04ae08af73971950d125e209f447", - [] - ] - }, - "id.js": [ - "cb21a667d6035cbbf1e0a83b01f1460d2c51d927", - [] - ], - "index.js": [ - "c85a681688881226ebfcb5ae431196fe3ecde439", - [] - ], - "listing.js": [ - "856afa99c36ebae161250be0023de7f2947ec8bc", - [] - ], - "loader.js": [ - "328989a8d7b0a9a305953e735cd2eef58a47d8e0", - [] - ], - "logger.js": [ - "b3ddbb6155588bd4d15e081c06f8445313c9ef96", + "common": { + "constants.js": [ + "9d3dd1a32defa22fd3a0cd0e17504cb4727b9622", [] ], - "params": { - "combine.js": [ - "20b2be113525b20d36036fbb5de8dbabefcad6d9", + "framework": { + "allowed_characters.js": [ + "af8f45172b52b3cdc6246218c40e5484a7517a63", [] ], - "exclude.js": [ - "23bc6ee0f69fa3d87853881cdf01ab224fcb58b1", + "collect_garbage.js": [ + "dc5a9caf850b967ea0779fee6b7c725376c0bbbb", [] ], - "filter.js": [ - "6a5d99e765f4dc502223502e168b37442d735daa", + "fixture.js": [ + "55f8ec48b22acdd553c093eaba8a568b0d8f1f56", [] ], - "index.js": [ - "de922526696d7921d2ed8139964b85996d811dc1", + "generate_minimal_query_list.js": [ + "f53445457257ce9b01e3fce2270f13aac8786628", [] ], - "options.js": [ - "6906863880ce99d3a29a3c7021ae3859798c34eb", - [] - ] - }, - "test_filter": { - "filter_by_group.js": [ - "b43749f9c5d700d1085b6402a086e38dcc4f2e24", + "gpu": { + "implementation.js": [ + "670872b5d6e32ebf3815935fdd9fec605056a30c", + [] + ] + }, + "id.js": [ + "cb21a667d6035cbbf1e0a83b01f1460d2c51d927", [] ], - "filter_one_file.js": [ - "6c634888810bdb817c2228312290fb2394a77f59", + "listing.js": [ + "856afa99c36ebae161250be0023de7f2947ec8bc", [] ], - "index.js": [ - "743975e13d687848ba8277cdc0adac4352ad5b9e", + "loader.js": [ + "ac175a5b85f2211a6f11c7b7c435cdc943939605", [] ], - "internal.js": [ - "ae55718f3b3df435310bba1808adb09672b8cc8b", + "logger.js": [ + "3f624a86e325daaadd1990e1aa11804ea2ab16d2", [] ], - "load_filter.js": [ - "787747ead06027cb07f42b3485d25e569aa37a47", - [] - ] - }, - "test_group.js": [ - "643e9f60b3150dd870644888d6898a4d5451b5cc", - [] - ], - "tree.js": [ - "fd7e6704c7602a28b3d28b366a614ac60ce13226", - [] - ], - "url_query.js": [ - "1446bc7f7f74b00b74bba7b22a29c553262b3941", - [] - ], - "util": { - "async_mutex.js": [ - "cb900605bcfe77bae785c207419787e317bf1d73", + "params.js": [ + "f8e46b62dbaf0039903a0496d333de5c84315820", [] ], - "index.js": [ - "2cba5f33998f3573db78fcef03c1e3fd535791ef", + "params_utils.js": [ + "cde89843f9e67d7f7e01914823fc807df2f40a66", [] ], - "stack.js": [ - "92b9c0e6bbc7e612fdb3742ab4502a1cd28b7f98", + "test_filter": { + "filter_by_group.js": [ + "b43749f9c5d700d1085b6402a086e38dcc4f2e24", + [] + ], + "filter_one_file.js": [ + "cc261ad2ac1c9d54ddc4c8937b75a76756054433", + [] + ], + "internal.js": [ + "ae55718f3b3df435310bba1808adb09672b8cc8b", + [] + ], + "load_filter.js": [ + "2b13d9ed2c9913534108c6286bae2d77ba81ee20", + [] + ], + "test_filter_result.js": [ + "9e32bdbd931b8d348bfb2093b7f0cfab9dd73450", + [] + ] + }, + "test_group.js": [ + "8837b1e924a412e8fb706d2f0601b72a7a79a28a", [] ], - "timeout.js": [ - "e565a518efc045cfc90e7dd7b23dc65604c6b805", - [] - ] - }, - "version.js": [ - "0b58dd9b3c4430d337b4a6241f2345f4073a12b9", - [] - ] - }, - "runtime": { - "helper": { - "options.js": [ - "1a90beadf1ee459911b2b549fc9359b44fe37bbd", + "tree.js": [ + "8f96c98074942127cd7b781778e5a17eb36f1d0d", [] ], - "test_worker-worker.js": [ - "d382f1e80e4dda805aca7e41cb90273cf84147c2", + "url_query.js": [ + "13671ab7daca794f61efe48d0c5c9bb1369d2a75", [] ], - "test_worker.js": [ - "a67030056f5b8d5ed7665f9e06f9735d0e26b287", - [] - ] - }, - "wpt.js": [ - "fd02f09471bc656a900714dd586101d6acb28c46", - [] - ] - }, - "suites": { - "cts": { - "buffers": { - "create_mapped.spec.js": [ - "0231c95dab2681bda7c32db2ea3dee31072ed053", + "util": { + "async_mutex.js": [ + "cb900605bcfe77bae785c207419787e317bf1d73", [] ], - "map.spec.js": [ - "ecbe7f9c340953d2e39e68d3f7faae5f0e20cc26", + "stack.js": [ + "3d0ec636d853d7b150cf921a931ce2e59963dcbc", [] ], - "map_detach.spec.js": [ - "9174efca59c39c7a52b17aecb231211a214bf82f", + "timeout.js": [ + "e565a518efc045cfc90e7dd7b23dc65604c6b805", [] ], - "map_oom.spec.js": [ - "24adf67fd6a4898690169a025c455aba8bd4ac6b", - [] - ], - "mapping_test.js": [ - "20d6c96ffa2ded3d25990a578d2109548a6f6966", + "util.js": [ + "ca64026916c1a7319674daf254c5eeb7df5c7699", [] ] }, - "canvas": { - "context_creation.spec.js": [ - "a693b002769ae9a1e951bc1888ca49ba393df7d0", + "version.js": [ + "159b3cf420e59692ad87875ce7d760b5a8c956f8", + [] + ] + }, + "runtime": { + "helper": { + "options.js": [ + "1a90beadf1ee459911b2b549fc9359b44fe37bbd", + [] + ], + "test_worker-worker.js": [ + "dd078c313a6287e500c902ee301c310b0c81e81f", + [] + ], + "test_worker.js": [ + "a67030056f5b8d5ed7665f9e06f9735d0e26b287", [] ] }, - "capability_info.js": [ - "10947ee1367e1d943e52a605fe868a06376badbe", + "wpt.js": [ + "fd02f09471bc656a900714dd586101d6acb28c46", [] - ], - "command_buffer": { - "basic.spec.js": [ - "6762a563c56edafeb225df6af27bd4507825e56f", - [] - ], - "compute": { - "basic.spec.js": [ - "536f7a9003eded24dced4ebc206c78472b26acb0", + ] + } + }, + "webgpu": { + "api": { + "operation": { + "buffers": { + "create_mapped.spec.js": [ + "7b2bc39aa3defbd14c1ad2dfa938ca4df6ee495d", + [] + ], + "map.spec.js": [ + "1c73d62a95ff82ed211a8dc6bf9b74b4c2a41fae", + [] + ], + "map_detach.spec.js": [ + "14d5be5a6311cd4eba637d679c7275be811aafb6", + [] + ], + "map_oom.spec.js": [ + "ee642a5c3b34177b815bbac26228567e25f62e37", + [] + ], + "mapping_test.js": [ + "b7349059035d46dffc1156314c7dfe7ec7526d54", [] ] }, - "copies.spec.js": [ - "c5bae2ada80e3ac330625966d69564b3b8280726", - [] - ], - "render": { + "command_buffer": { "basic.spec.js": [ - "46b5c7a27c9bfc7f567de39449673494eb74c2ee", + "bc4020bfeb53afcaa19ccf5f155e358886ffbc29", [] ], - "rendering.spec.js": [ - "b26b9fbc859d5b2a5fbf79e9e1ca3f76cb02e455", + "copies.spec.js": [ + "c330415d8511b9a548706b6019e1a6614804d432", [] ], - "storeop.spec.js": [ - "1f758cc5c2ea74d9f2e36f5dd71d321c76cde822", - [] - ] - } - }, - "copyImageBitmapToTexture.spec.js": [ - "42ad8507ec949c55c441cc3c2808ab8d6ebee7e5", - [] - ], - "examples.spec.js": [ - "e57de1bfc8d9cf0c8d2264b77e68b56c6c2659f8", - [] - ], - "fences.spec.js": [ - "af6482fcab508705e884cd205cf31f7b9762990a", - [] - ], - "gpu_test.js": [ - "7ab5320d6e95c8c3914c26db5f0cc7ee7a0b0843", - [] - ], - "index.js": [ - "e566792357a874aa3fb106479179c26c0357c188", - [] - ], - "resource_init": { - "sampled_texture_clear.spec.js": [ - "a8fb1ad71d1ef0fa7030dd59a58733ad34fc0841", + "render": { + "basic.spec.js": [ + "88710e8aa09287dfd612acf26976406c2576cba5", + [] + ] + } + }, + "fences.spec.js": [ + "386530e08523bdfc9da2a4827d8a04760cab6678", [] ] }, "validation": { "createBindGroup.spec.js": [ - "2f42a8b643d4905a5f15f3abc312e20ce569ecfa", + "97683cf75a92d574147a000e29a69b70e7fb97a1", [] ], "createBindGroupLayout.spec.js": [ - "b48db9598dd62fc933e14b08974c3aa4af6fbd63", + "b03e01591133aa7fd641b805a598cca328d16157", [] ], "createPipelineLayout.spec.js": [ - "0018c24e54075cf1551af3bbb1cb4d1977386907", - [] - ], - "createRenderPipeline.spec.js": [ - "e4dd32af9e8de43bc29f8bd7ced45638d7a1e6a4", + "f1582c4478a2074cbb37b99c32f8e4c5242116d0", [] ], "createTexture.spec.js": [ - "a7317a88f5badd9d65fc881a2a34a8cf652fdee0", + "ab4c6f866b4df74315c69f3cb8bfd483540e54ea", [] ], "createView.spec.js": [ - "a4fe7ac2a930ee9bec57528d743f119c8749b6fc", + "d23af58387440bf7b5d6953a240110a179e8379d", [] ], "error_scope.spec.js": [ - "6c6cfd73ae03b6fab76829aa820d106f6bbbd03b", + "fd69c4e13c0382d95eb2fc5dd535b48b5543c022", [] ], "fences.spec.js": [ - "2bc85261d3dc8107065fd957475ffd412fe071a7", + "7747b5e9dc8592dde77167c2696da0582e1573f0", [] ], "queue_submit.spec.js": [ - "410e3c26e82b82637d45a2bb01e136130d82a6aa", - [] - ], - "render_pass.spec.js": [ - "67f7bec6d66977fbb67539897d64ab0506a5f9f5", + "dbe0bb4d31ed68eec197d7a556e6f9e097b5eeb5", [] ], "render_pass_descriptor.spec.js": [ - "59caf533e6c3674b82ead7cd1e05048c4de3d308", + "7c887a1c0fd112b7d5648edc2698e0376e5f2ae5", [] ], "setBindGroup.spec.js": [ - "73ae4ba502ea31e07fce16dc3b64766e43d53bfa", + "baf590746c33c04c9fedd75b11de7873d4eeec91", [] ], "setBlendColor.spec.js": [ - "a04bcd038ee5f0f957772bb52a63563b400fa502", + "b8905453ac952131698a5b67d9b3a1f6270c9e83", [] ], "setScissorRect.spec.js": [ - "aec75f536a1dca7c4448b6d901060735e7d86f6c", + "e12c90d7cdae1c2271b9b97df8a85816c6e5e5a7", [] ], "setStencilReference.spec.js": [ - "3db37a4908e719212043856b9bdf5e3b31a91065", - [] - ], - "setVertexBuffer.spec.js": [ - "47b861501296fbe517345a54ca7198e237cdf748", + "cbd48aeaad532724977752e524dd106c38cd14df", [] ], "setViewport.spec.js": [ - "715a236b18db388750f672d1caabf1466fe46611", + "9a3009f38ac020893f78cc5f7ad33defaa93101d", [] ], "validation_test.js": [ - "c275f94a80e5b8477838f4b66e4a1c123de9dbd6", - [] - ], - "vertex_state.spec.js": [ - "103a11265c573e7f2873da5893fb92aedcba14ee", + "92d8a0699c4f2c7f1002537c97dd30bf93137b9d", [] ] } + }, + "capability_info.js": [ + "0e336b979f8290152b0ec0e9c7993768106a2fed", + [] + ], + "examples.spec.js": [ + "add23f7250ee70a1f80b7ee1ca2c292e7ae3c0d6", + [] + ], + "gpu_test.js": [ + "0202f34fcf7429a3eb671f786c45efbacae36871", + [] + ], + "listing.js": [ + "5b9ef1afb0184599c0b6f33468356f21677315d5", + [] + ], + "web-platform": { + "canvas": { + "context_creation.spec.js": [ + "fd8593b642ed84440706ca4b1b29dc4f2e1660d5", + [] + ] + }, + "copyImageBitmapToTexture.spec.js": [ + "5e84113b95ad6940517a9c3dc3339ae233b52a10", + [] + ] } } }, @@ -350391,7 +350821,7 @@ [] ], "webxr_test_constants.js": [ - "d92da3d8f34875648a6e503c14daf7d83915023a", + "959859cba2136de61c5e233cd66af9c96776eda5", [] ], "webxr_test_constants_fake_world.js": [ @@ -356163,6 +356593,13 @@ {} ] ], + "2d.path.isPointInStroke.scaleddashes.html": [ + "55a80bc8211feea4eafe8c5927f096d4ce4df8fe", + [ + null, + {} + ] + ], "2d.path.lineTo.basic.html": [ "b3ca9f981e1cff3c1ade6ec2ff5fbe53dbc0a21c", [ @@ -378123,7 +378560,7 @@ ] ], "change_eventhandler_for_no_name_equals_in_value.tentative.https.window.js": [ - "fe6a34b3d697a3a8556bd7e037904753f0fa4c16", + "13d721786c9a140b05ed5291c6096c894053f78b", [ "cookie-store/change_eventhandler_for_no_name_equals_in_value.tentative.https.window.html", { @@ -378427,10 +378864,10 @@ {} ] ], - "cookieStore_event_delete.tenative.https.window.js": [ + "cookieStore_event_delete.tentative.https.window.js": [ "e8c6fc036a76863acf2d8b2b3660550715f1dc0d", [ - "cookie-store/cookieStore_event_delete.tenative.https.window.html", + "cookie-store/cookieStore_event_delete.tentative.https.window.html", {} ] ], @@ -378541,7 +378978,7 @@ ] ], "cookieStore_get_arguments.tentative.https.any.js": [ - "34f7dbcd948fd5e590b0e9f715ad878f4de9694d", + "b0bef77fd895cfff11f463fb94fda801072d6371", [ "cookie-store/cookieStore_get_arguments.tentative.https.any.html", { @@ -378701,7 +379138,7 @@ ] ], "cookieStore_set_arguments.tentative.https.any.js": [ - "b9074c827d2a1ffa9b3ee1a0a28714396c4ae0d8", + "6685f5fd3b7186b88b8ca36e2508b513b513257a", [ "cookie-store/cookieStore_set_arguments.tentative.https.any.html", { @@ -381154,6 +381591,13 @@ {} ] ], + "animation-base-response-004.html": [ + "5638a572e90c745bea220e5301210541817c4593", + [ + null, + {} + ] + ], "animation-before-initial-box-construction-001.html": [ "558c5ea18699f3856c7d34b976f920b1fd7fd5b0", [ @@ -383099,7 +383543,14 @@ ] ], "contain-size-grid-003.html": [ - "fd07602b5686637b94dbc9d332ec1b5466631d0a", + "44b736b1d6b62ec5c4fc0e6fb3314095df6a27f4", + [ + null, + {} + ] + ], + "contain-size-grid-004.html": [ + "c333c03298c7049292913f3e21de52eb0564c8d2", [ null, {} @@ -386282,6 +386733,13 @@ {} ] ], + "grid-baseline-004.html": [ + "baabc70a3f477321f76dff59cfa2e73bcff8e165", + [ + null, + {} + ] + ], "grid-block-axis-alignment-auto-margins-001.html": [ "e3a880f66eaf2e0da945e9683c0c7e4105ca51ce", [ @@ -387364,15 +387822,78 @@ {} ] ], - "flex-and-minmax-content-resolution-columns-001.html": [ + "flex-content-distribution-001.html": [ + "62fb46deebcd46d7275229b154e8fcf8b39b74c3", + [ + null, + {} + ] + ], + "flex-content-resolution-columns-001.html": [ + "ce70aa31de537006d2f0ec62414f7446f2839a24", + [ + null, + {} + ] + ], + "flex-content-resolution-columns-002.html": [ "b92eb9f0dddc63ca5d241c35dca2e0c32d406d24", [ null, {} ] ], - "flex-and-minmax-content-resolution-rows-001.html": [ - "ebaa2c08e4b6fff5042f4c0a4997a28f5cac293a", + "flex-content-resolution-rows-001.html": [ + "d10b84014de8a3f599a9448b4f070719662685f7", + [ + null, + {} + ] + ], + "flex-content-resolution-rows-002.html": [ + "d668a93a324c365c20490d0472a23a5e084ed9b2", + [ + null, + {} + ] + ], + "flex-factor-sum-less-than-1-001.html": [ + "ad7af2d84640ab626cf783e65a2da78a137d48c6", + [ + null, + {} + ] + ], + "grid-auto-fill-columns-001.html": [ + "ed32ee55d5be7f19f468e2f772f3eb2fbbb2cde5", + [ + null, + {} + ] + ], + "grid-auto-fill-rows-001.html": [ + "afce3f5fa91a609f5a4f27f666e97565f4fbc8ee", + [ + null, + {} + ] + ], + "grid-auto-fit-columns-001.html": [ + "b1dab7e32f9dd98f14af9ff885cc688b465ed384", + [ + null, + {} + ] + ], + "grid-auto-fit-rows-001.html": [ + "7619d9e023e2a7cbc9e7d5fb5d49730046bfbcf3", + [ + null, + {} + ] + ], + "grid-auto-repeat-intrinsic-001.html": [ + "a5f6f16407a67b78294fd223345d1254a8241333", [ null, {} @@ -387427,6 +387948,20 @@ {} ] ], + "grid-change-intrinsic-size-with-auto-repeat-tracks-001.html": [ + "437ad818799a94a48baf19bf0753982bf65196fc", + [ + null, + {} + ] + ], + "grid-content-alignment-and-self-alignment-001.html": [ + "cd79210f10d7f5384def836868b2c5394db3e447", + [ + null, + {} + ] + ], "grid-inline-auto-repeat-001.html": [ "deda5656679c29cd8706762deedcf56e11d4b95d", [ @@ -387774,6 +388309,13 @@ {} ] ], + "fixed-width-intrinsic-width-should-exclude-scrollbar-001.html": [ + "26b8f5e01dd932491bec2c365de659359dd14639", + [ + null, + {} + ] + ], "grid-box-sizing-001.html": [ "b99029293466ddfb514f401931161d75cbd5917c", [ @@ -387853,6 +388395,34 @@ ] ], "layout-algorithm": { + "flex-and-intrinsic-sizes-001.html": [ + "5144450dd8cb6106768d55088bd4900405be05ce", + [ + null, + {} + ] + ], + "flex-sizing-columns-min-max-width-001.html": [ + "6b269e5258f9eacd0f0e066035f9f7ea2333aa76", + [ + null, + {} + ] + ], + "flex-sizing-rows-min-max-height-001.html": [ + "0789e4053013e91f5b7b6ee8b2e1698346c0f7c9", + [ + null, + {} + ] + ], + "grid-container-percentage-001.html": [ + "511e0cd99ead89649884ab7cc0852bfab09eb7da", + [ + null, + {} + ] + ], "grid-content-distribution-must-account-for-track-sizing-001.html": [ "907ef68668f2cbe113674e808b4e78ae0e390100", [ @@ -387923,6 +388493,27 @@ {} ] ], + "grid-item-margin-auto-columns-rows-001.html": [ + "6ae1c50c220cdd07c5fb1fb266e2e2bd11bf2a4e", + [ + null, + {} + ] + ], + "grid-item-margin-auto-columns-rows-vertical-lr-001.html": [ + "63bf55f293b0ae6a2a6c430306f9d34ee9e09b25", + [ + null, + {} + ] + ], + "grid-item-margin-auto-columns-rows-vertical-rl-001.html": [ + "d6767e3f4a648cbf54dcd1d5530a8d38824b1be4", + [ + null, + {} + ] + ], "grid-minimum-contribution-baseline-shim-vertical-lr.html": [ "3d1949fc3fa3a1d1951dda03ed8a8bb63f31f0e1", [ @@ -388186,12 +388777,33 @@ ] }, "placement": { + "grid-auto-flow-sparse-001.html": [ + "373371ac2bf16bd112c9e4f190ed5f536bb2f494", + [ + null, + {} + ] + ], "grid-auto-placement-implicit-tracks-001.html": [ "546336a6ce8208d7c30afd66e20fbe33040cbd7c", [ null, {} ] + ], + "grid-container-change-grid-tracks-recompute-child-positions-001.html": [ + "a2485142e1ba84d99809c0eaf8d9a4a6932d5246", + [ + null, + {} + ] + ], + "grid-container-change-named-grid-recompute-child-positions-001.html": [ + "d702d30b3baf846a5d1af0e52741a114f40d53f6", + [ + null, + {} + ] ] }, "subgrid": { @@ -390716,6 +391328,13 @@ {} ] ], + "font-size-animation.html": [ + "4b8ce1c2551fececd578d60411abfa27fe1c75be", + [ + null, + {} + ] + ], "idlharness.html": [ "6f053757c3cef099f0cea41716a942dfa7e66100", [ @@ -391010,6 +391629,27 @@ {} ] ], + "keyframes-003.html": [ + "2e1d799bd0d04d25a2e8391142cac48f268eeed6", + [ + null, + {} + ] + ], + "keyframes-004.html": [ + "67924fb01cdab74e34cf66243429775bf701c665", + [ + null, + {} + ] + ], + "keyframes-005.html": [ + "d9026d2f6aa7042ada567f866e64ab4366157843", + [ + null, + {} + ] + ], "shadow-cascade-order-001.html": [ "c51696e483374e3d7346f105a7e8b85d8fce7606", [ @@ -404552,7 +405192,7 @@ ] ], "custom-element-reaction-queue.html": [ - "737dab117d3bd8d296ca6235d04e7664e35740c0", + "246b15a0af36cffa0b64f1d57e4208538b92bdd7", [ null, {} @@ -409370,84 +410010,84 @@ }, "element-timing": { "background-image-data-uri.html": [ - "540668ae3c3b38fae1c8b09b4931ceaec9096338", + "9722463742ae1e1bbc09677a03fa03383bbc406c", [ null, {} ] ], "background-image-multiple-elements.html": [ - "61a284a5df38dde63afc8216888d20f5bd308415", + "11f8c05f9668bdd1f037e28f8df6773c8f3db951", [ null, {} ] ], "background-image-stretched.html": [ - "d5534c3257a477c0adffa01f707077d14a2f5b75", + "3ad8976ccf1e27dcd77f63344b495ccf39946dbc", [ null, {} ] ], "buffer-before-onload.html": [ - "79dd64e29779675019a599f2e17b4e64ac8cd940", + "17c8238f6e79a1f6c3ba2484191705c023a54818", [ null, {} ] ], "buffered-flag.html": [ - "1fca117879232e17dae2c889dcc245ac0be6f5f1", + "e7fcf059fb1abb10c0697577822a4723b3ef7253", [ null, {} ] ], "cross-origin-element.sub.html": [ - "b5b06f30469b3ea82fee31beeb4657198f2e1af2", + "1052bf246d0fa262ce5370f4152cb60dd758adab", [ null, {} ] ], "cross-origin-iframe-element.sub.html": [ - "b183fe289aa96abb6fbd09953c00086f4fc4f3e4", + "2f49933ab964b7a35bb3226be48f09f5901d6584", [ null, {} ] ], "css-generated-text.html": [ - "4b7dea73ca8d383ab328132d49147e7da171e5c8", + "d1bbf5a7eee74ec74f8e09bfee41faf060b8c250", [ null, {} ] ], "disconnect-image.html": [ - "9c2be0e45ac5457c1bbc73ba1f5ee3194d7e001e", + "6f9f2ce7b9fbd27bc58211e508705b952c23bb90", [ null, {} ] ], "element-only-when-fully-active.html": [ - "001430516dc83c5eb92517ab23b3d3490b8ce118", + "ff08074d574df8b7be98f00f796b271479d05c71", [ null, {} ] ], "first-letter-background.html": [ - "b24ed542c88e2d08ab463cd013ef972a88a8e15a", + "f05f2f92234d740bcf42d13396b187bdbf90282b", [ null, {} ] ], "fixed-id-identifier.html": [ - "ae8303f021d7ff1340a381a8fb3995170201c6cd", + "749b9ada2f383ee7d7d7a5277c3318124a942071", [ null, {} @@ -409472,210 +410112,210 @@ ] ], "image-TAO.sub.html": [ - "ee2b061790094f790464fc4b627d341a14020730", + "7b455dfa4c405de3918efbcd0f9648be09346948", [ null, {} ] ], "image-carousel.html": [ - "ce6ac951e2494de3e6a1b7c7e79cf816effb9776", + "2b3b618f8c447df357d328c234abc3a542dd6d7f", [ null, {} ] ], "image-clipped-svg.html": [ - "c8e4a67cea687b9e54ae905d75cb1ba0b33691c8", + "4c2bb36079432fda085ba44d7d534cf6ac8ee033", [ null, {} ] ], "image-data-uri.html": [ - "afe203ae1bf96297cd96b885377317832654c243", + "02d88fb2448a1aee789061f81bddcec3e71c286f", [ null, {} ] ], "image-not-added.html": [ - "83a6cc6084438042e947e2cebbfe4aec07b61d32", + "d77049ecd4966c2dd1e3746ac6b3a3fbd97659a3", [ null, {} ] ], "image-not-fully-visible.html": [ - "c51c24a965a6dbb09b497827c1817669ca9188e2", + "504d17592f2de93177dd20949d31f14ed51503f7", [ null, {} ] ], "image-rect-iframe.html": [ - "a97ed5a850787aa11fb412fa99dd7b8cb732a41e", + "00986366e612b4285d2dd6d901638053bd8eaef5", [ null, {} ] ], "image-src-change.html": [ - "e9e13742a6505dccd7248b0175b8b9d331b533b9", + "88436123fe9da47520dec1e7283df6bd66131a10", [ null, {} ] ], "image-with-css-scale.html": [ - "9bd71086a75ec42103266588f287512623c4e471", + "a0490f375cc24b2b102ae3974c53d994b553eb00", [ null, {} ] ], "image-with-rotation.html": [ - "64ff942f0cdacb74315044c990041653d30b42f7", + "229e9ae96c8f63b9f458217bc63af0a41fe09634", [ null, {} ] ], "images-repeated-resource.html": [ - "6090e75f26ec0aa920735a9382ac654ab979caa3", + "f7296e05e73d0615faab0bc186ac442c1cadf00c", [ null, {} ] ], "invisible-images.html": [ - "8225996e255b8137af72901a963403d5063f75a1", + "ffde3ce2f6f46819b812c5b8445f2cb7f716e61d", [ null, {} ] ], "multiple-background-images.html": [ - "c2a32c3c8e6b7de76b3b91cb9ee360a828e7e7bc", + "380e5e825e187d970bf156e143c77317ca5fc758", [ null, {} ] ], "multiple-redirects-TAO.html": [ - "6800f7cf6873ef10540e83fc0fa7b249c8050e0e", + "3a45b552bea0f599fd778e62a77759321384fd2f", [ null, {} ] ], "observe-background-image.html": [ - "e02714b702108cbb58cfb33fffb6194bed05cd9d", + "6a43401cd0f4270f52b9167393b1b9fd0a7d9cce", [ null, {} ] ], "observe-child-element.html": [ - "4293e814eb91232c9768633c8684ca5c40a1d6cd", + "c8071998c52b3b601218a7fd658bac68f530e6c3", [ null, {} ] ], "observe-elementtiming.html": [ - "ee8960bd72883409055752be16ce2b3d2198535b", + "a204f0d6772855c58fa6975fe020638e71a4171e", [ null, {} ] ], "observe-empty-attribute.html": [ - "25d3492f73bee7c7c8373d14db86f36de95a9df0", + "baec6ee48d7195465031b3537b8b2ed22fa36e5b", [ null, {} ] ], "observe-multiple-images.html": [ - "9a0657aa60fe73108ae81e0c2bddee320989822e", + "c5ea700553b4b2337bbcbb3925293992758f791d", [ null, {} ] ], "observe-shadow-image.html": [ - "1c12c5fe0310d8c21609ec17778e06063e162ba9", + "e2a81d62449180c47b4d19311046bdd9a41748e1", [ null, {} ] ], "observe-shadow-text.html": [ - "3167a1225c5216b69a99d57e8d58151a27ec3239", + "6e6347e60d26b250ea3c070fcfb1182d9d4d78dc", [ null, {} ] ], "observe-svg-image.html": [ - "83ca4f40aaeb2cdb81236ee9b973f9ea0aaf01fe", + "737f94f92bcb56ce3603c9e21f67efb80d31042d", [ null, {} ] ], "observe-text.html": [ - "a054b2617261fb33d1509a2639794cca86cf1729", + "5d8955269f842d972e4a26ebc03f9299aeaa5294", [ null, {} ] ], "observe-video-poster.html": [ - "f64da173c6f2daa2a811075a75b997982d0af73d", + "5607733529671882bfde5be4c037b7a1614a84a5", [ null, {} ] ], "progressively-loaded-image.html": [ - "0d59052cf3ac069adbe47780fefc8dc75000ac52", + "6695d8f9c324b0c20f9b19c1f064a7349c770d5d", [ null, {} ] ], "rectangular-image.html": [ - "a97c549a9aad387c2beda7971fea985dcb35a4c1", + "65f190e75300e102bbca961ef34518db27b4efa2", [ null, {} ] ], "redirects-tao-star.html": [ - "f8e4d19bd07cf6faa872a5630855414bf229d111", + "e5067d3d6bd7915522bfb670fad0919f0e4101fb", [ null, {} ] ], "retrievability.html": [ - "5c6113bdc933f98d7cb753de904f7b07456daf40", + "cd2c2a956e194cd06b5374a26dc9f1b06fe5f482", [ null, {} ] ], "same-origin-redirects.html": [ - "3527d805f3e01d94a5f1b19085fd63d2f689a8b8", + "e52fcecc1ae69a702dc207367a02be890635043f", [ null, {} ] ], "scroll-to-text.html": [ - "ca06e91c530a73f75220aecbfe9d7ffb2bee18b4", + "0508d2bcf9951c799be84559c5d5721909a2cbbc", [ null, {} @@ -409689,14 +410329,14 @@ ] ], "text-with-display-style.html": [ - "faf644fd8d244a9df52eb96403719b0922fcd2dc", + "94e89fcf7270b43634b4c651c961d539a38f59fa", [ null, {} ] ], "toJSON.html": [ - "ba13a0fa90797c0bc6fb104857d5ab86a0790b3d", + "24c7d1e0a655dff215b0e6a7ad94e0e3f3488b5e", [ null, {} @@ -421209,7 +421849,7 @@ }, "event-timing": { "buffered-flag.html": [ - "dc70ff253ff3c408f052e3d8cca705069ee8fa76", + "7ee152be9388fa8593c3c2a85981a7cb0ed7492a", [ null, { @@ -421218,7 +421858,7 @@ ] ], "click-timing.html": [ - "376372a3f110feb85d65bd3dc0e28465e5a5e71d", + "4544734f73fa2b81d7242f3bd17c605aa45eb078", [ null, { @@ -421227,7 +421867,7 @@ ] ], "crossiframe.html": [ - "55e2becfcbcfa3feba1473ddcd17e15a30adbfc0", + "711408684340ef27d48d0ff36ce41c70e1424d12", [ null, { @@ -421237,7 +421877,7 @@ ] ], "event-click-counts.html": [ - "034e172c1df8d051fde76c2e8787832f2a7c213b", + "d4e87c58969a3af4dadaeead894c7cc843bc51dc", [ null, { @@ -421246,7 +421886,7 @@ ] ], "event-counts-zero.html": [ - "0cc9e2ee38aa9f0a720952d5c27d3b01537fbdd4", + "3ec90dd69138f35197774239dfc12f554c9284b2", [ null, { @@ -421334,7 +421974,7 @@ ] ], "only-observe-firstInput.html": [ - "ad71153d40bca022ebcd9c902710f8d71aeaeb61", + "54a6036f91adb89c7b6528e40850937d70520b77", [ null, { @@ -421343,7 +421983,7 @@ ] ], "programmatic-click-not-observed.html": [ - "1c2921ca48991f46de533e10a7c4a2a924ab3551", + "0a189b0bc2a7fd931de7efbc40de51a11b939c23", [ null, { @@ -421352,7 +421992,7 @@ ] ], "retrievability.html": [ - "d2b6da2439fe5f42091b35d0916c6e36ff3c0e8b", + "087cd13184b6f651a15065a46005872ccb00d318", [ null, { @@ -421362,7 +422002,7 @@ ] ], "retrieve-firstInput.html": [ - "acff788259f5ee85db230d967692b3a35894c387", + "27b17cd18165f975fbbd98e7de07dad71251c1fa", [ null, { @@ -421371,14 +422011,14 @@ ] ], "supported-types.window.js": [ - "5360bdd9e82244350ac19de21bcd67d9fd5a0450", + "1cc43495c096fd0cd568fa5983055c0390f94d40", [ "event-timing/supported-types.window.html", {} ] ], "timingconditions.html": [ - "02da2976ceecc8c5fa648b74a70fcf277bc8ee3f", + "12280cb894a8767b9b3bc7ba1df61b4e9e8630d5", [ null, { @@ -421388,7 +422028,7 @@ ] ], "toJSON.html": [ - "a11073aa9a0eb8436fb0ecfcdc48f4a35c908993", + "a2d7df42da5b86a48daba7fad7e7f2adf76ed039", [ null, { @@ -425848,7 +426488,7 @@ ] ], "portal.https.sub.html": [ - "96067ae82ab7838784f6350dda7cee7840e277f8", + "8403a296fe12786bf75675cde47f4d41b684cdaf", [ null, { @@ -427734,14 +428374,14 @@ }, "the-history-interface": { "001.html": [ - "b4a5fd4bf4de7bff169409913e658af9bb81017b", + "6d48d108bbe84fd13c6bd46ca0650be2507525c4", [ null, {} ] ], "002.html": [ - "dcda248282f494c76ba175eb966137704fdf8010", + "c054246770f03330415732edf95bfddd10ffddcb", [ null, {} @@ -433147,7 +433787,7 @@ ] }, "baseline-alignment-and-overflow.tentative.html": [ - "1c0b312eb4520e789bee93a4669e16035fde1648", + "5f677b5f0f6df7b35cbe789a80f660bcd71ad082", [ null, {} @@ -437286,6 +437926,13 @@ ] ] }, + "currentSrc-blob-cache.html": [ + "a5e108dcd6e1a47ba4573f042523060fb087c376", + [ + null, + {} + ] + ], "data-url.html": [ "808b5c884c564e52beec9e42437ed5fff4264748", [ @@ -437832,7 +438479,7 @@ ] ], "resize-during-playback.html": [ - "3ade1effc4bd0273a46bc45dd0e5218a3af453c9", + "1b057bbeac322e4bcdaa2ab7d1ff664b06402846", [ null, {} @@ -448251,14 +448898,14 @@ }, "largest-contentful-paint": { "contracted-image.html": [ - "ed6adfb2c7c66c65bd13f514be173d1cb48ff19e", + "8816bf4ba99cb71e9f79ba44859a80a4c103ebad", [ null, {} ] ], "cross-origin-image.sub.html": [ - "be0c8a1e11e334aeb62d3cd952072e481c9ee7ea", + "0cfdd1791ba2061c1cc179a84d4f11a47f799868", [ null, {} @@ -448272,21 +448919,21 @@ ] ], "expanded-image.html": [ - "e0b3545c21c2c14bd26feb9720648537a780d20f", + "55adff91f2f45afe47c6fa84f43b8fb98d7d0424", [ null, {} ] ], "first-letter-background.html": [ - "80b8f1891fdc90a07a93f463343644cc38e70734", + "09fe1f5beb6df26c2fa1489ef60855e226a5f707", [ null, {} ] ], "first-paint-equals-lcp-text.html": [ - "7a01cb15943ac3b0b863daa3272d962f78ec5e3f", + "97eb67e320efe52952740f90ab1e3fcea38eaea4", [ null, {} @@ -448300,7 +448947,7 @@ ] ], "iframe-content-not-observed.html": [ - "ea8e0d79f380b723d47f9683000be7ee4985c92b", + "e605e9f21f63f4aa5d8b73c38a53ac3253ece1fc", [ null, {} @@ -448328,7 +448975,7 @@ ] ], "image-src-change.html": [ - "cbe46f402b4e344571932fc501d4d3410eadc125", + "bd78476390c8c9df170bdd59211bb3756142e9aa", [ null, {} @@ -448356,70 +449003,70 @@ ] ], "larger-image.html": [ - "a571b8afe7915609b49197ac8eafbcde76b42d01", + "a9675386a086877aed979ff3fbd8d533fb26a658", [ null, {} ] ], "larger-text.html": [ - "af8bbc06b32c95bc66b0c450b7eb20f7154edcd6", + "ca711f22411c6cba5acf5cc2f8302526e3d37722", [ null, {} ] ], "loadTime-after-appendChild.html": [ - "f320b03df4da612b37c04900a0e702981220987a", + "2d19e73e60ff44d1a593f3338a3cc8120bf3ab20", [ null, {} ] ], "multiple-redirects-TAO.html": [ - "ec8ddc3ec61c6ca854dc55d4b3384e6403e54569", + "ee832c410435b47d9a26c9cb0f9db23c44ed5ad5", [ null, {} ] ], "observe-after-untrusted-scroll.html": [ - "4a1a214c8330a79999e1841fc87c5c27d8e57906", + "c84f922e5e589eea59290ab22731f1bb5eb4415b", [ null, {} ] ], "observe-image.html": [ - "58eb5364a92536597a78f16f76907de182f60d37", + "707840671b16ba815dcd79f948ed02401bf999e8", [ null, {} ] ], "observe-text.html": [ - "402fcd8019586c6b63077ff68fc8ae3a425c1574", + "a0a07d9422d62c2a20d72310c903242af0c56825", [ null, {} ] ], "redirects-tao-star.html": [ - "0667266e6d292337a676bb4f26acbb80701bc3af", + "1daea61486ce4fc050b182d9aabd7d75c0de5a19", [ null, {} ] ], "repeated-image.html": [ - "8c3c8909099296b85cdcda6f25c893f12a4ad3ac", + "a28409a848cc39bb1aeed87eb0d6e0117e2529f5", [ null, {} ] ], "same-origin-redirects.html": [ - "e17fdbb69e6fb8bafabd0dae7e2d23b601fd57d7", + "b5cf9da2d120d4e03852954057fc7171fad9901f", [ null, {} @@ -448433,21 +449080,21 @@ ] ], "text-with-display-style.html": [ - "24541541a8becb116ada2c682e48630932ba1fbf", + "e041a9fc21a5627ed72f898e8e7255ed6cb48810", [ null, {} ] ], "toJSON.html": [ - "25be5eb2dc909fcc2c224538607e3af47377ffc2", + "36e2a7fdfa27371b9295059525430e853029eef5", [ null, {} ] ], "video-poster.html": [ - "535f30e256574d9b734028f0ba7fb13b02ac0dba", + "b3a291886308da132ca07a46850ae71a615b9f26", [ null, {} @@ -448463,14 +449110,14 @@ ] ], "buffer-layout-shift.html": [ - "50cabda8d20406f4a0c8b4ac412f6b391572bf42", + "705569f96cf7d9501865dafd1e16aadf33cb59c4", [ null, {} ] ], "buffered-flag.html": [ - "1d200712c280346b12976c22d38e310ae9df639d", + "1c6726247328cb5605e845c4d9cff0033782348e", [ null, {} @@ -448562,7 +449209,7 @@ ] ], "recent-input.html": [ - "52adbf723ea34ce2ae7d2fb3027be67dcd785d5e", + "292b683bcb58c75044725fa3f6204e8835a0f739", [ null, { @@ -448613,14 +449260,14 @@ ] ], "supported-layout-type.html": [ - "cee4b808c87b585c49d463085e92e7d000ffba0c", + "3ba209f50a427965b651c92701a62f9006b8a2b1", [ null, {} ] ], "toJSON.html": [ - "00f074a4dd88aa17e7c4c7ef36e097738b932015", + "711cd238431a7bdc1e0c0a955c9effd7acd771a5", [ null, {} @@ -448703,14 +449350,14 @@ }, "longtask-timing": { "buffered-flag.window.js": [ - "f1ca54f532280fb0243ece0772a38e51cf9b92c9", + "88e1363beba7dc39fec18a2b89484b2fc527e207", [ "longtask-timing/buffered-flag.window.html", {} ] ], "containerTypes.html": [ - "94daab793c67f49ef858d2bbad56d2be43b38c2a", + "5a703f3995cec7f1aa3f3d4a274bdc1780c2fcc7", [ null, {} @@ -448735,70 +449382,70 @@ ] ], "long-microtask.window.js": [ - "9219fdb5c49b99b646343584fae37380d6f2a2b1", + "ef16f00dbe5643f685edeb52445d8803ff4997f9", [ "longtask-timing/long-microtask.window.html", {} ] ], "longtask-attributes.html": [ - "24540d7c22f04dec0919412a481adf279f685290", + "9af1c7bf95b3ab993a4c325b1c14a2f1172a102b", [ null, {} ] ], "longtask-in-childiframe-crossorigin.html": [ - "20a94a1eef4de998aa1ea9fa8ed4b781e7da9d3e", + "d0fdf742804d722a6682e8f2b455284dc83fa4b9", [ null, {} ] ], "longtask-in-childiframe.html": [ - "4feae7e55c16367025e13dfe1b1364500bcc34bc", + "4c325c42adb3526c32d213e985911139b3da97c7", [ null, {} ] ], "longtask-in-externalscript.html": [ - "db5c9db4a1626417aedd6c0e62c39376d8ee1a02", + "8636025cf286f5772edaba1aefdb1d0050d8d43c", [ null, {} ] ], "longtask-in-parentiframe.html": [ - "c6b7e3e583894ce57b292c3b746009f11a8a43c5", + "7fd5fb672bd4e7a16074e6fcb04f689bc5a2ceba", [ null, {} ] ], "longtask-in-raf.html": [ - "110ae751ee335d6d08b527d0cc7b32174f3371ec", + "40508e1e6778a4ac986ffc5bf0865f4c0d6b3ba4", [ null, {} ] ], "longtask-in-sibling-iframe-crossorigin.html": [ - "ba9c7170626e34b0f36d7680841cb13c048152e2", + "d66fe0c63ba363333c7f1cdc3b75712cddf7de84", [ null, {} ] ], "longtask-in-sibling-iframe.html": [ - "8f530fab06970125589e0594cb5725617c829349", + "396a9beeeaa3aae729ba1180761eea57cfa573a3", [ null, {} ] ], "longtask-tojson.html": [ - "6574b62d348b08e2f43aa5a81a2f3fd8bd2c50c6", + "b1f9b3c9b1cd60fa77eba4fc7ad7e940411cef53", [ null, {} @@ -448806,7 +449453,7 @@ ], "shared-renderer": { "longtask-in-new-window.html": [ - "18d36b1e734bc0ef21af575892690211c420bd5b", + "7668d995d86a369a0099e73f126c6e1d5f5baa55", [ null, {} @@ -448814,7 +449461,7 @@ ] }, "supported-longtask-types.window.js": [ - "aaa6415a8d3e5f73e940ae83551e05caee67311c", + "efb393ad8443f4286ce860749a6d1142734f491a", [ "longtask-timing/supported-longtask-types.window.html", {} @@ -449020,6 +449667,13 @@ {} ] ], + "mo-font-relative-lengths-001.html": [ + "b18d7dbfbe2ede218189d75f67138c8d924bdd88", + [ + null, + {} + ] + ], "operator-dictionary-001.html": [ "e4e5c68b26344195844699e531dceacc835a8597", [ @@ -466199,7 +466853,7 @@ }, "paint-timing": { "basetest.html": [ - "d4dfe7ed822beff3090a58e84d736f5ae79b4620", + "1c875984598024a7d483486e102e91a71b37132f", [ null, {} @@ -466213,14 +466867,14 @@ ] ], "buffered-flag.window.js": [ - "4654c925ca0cf069d3b0a96f0daef25ef67ba187", + "b3a6a6374c70badf103ced74de9b4c54d47da672", [ "paint-timing/buffered-flag.window.html", {} ] ], "child-painting-first-image.html": [ - "d78af081ef8af9e47dac8a042564c0dc4fd38479", + "a7ed2c6f10111911fa4205c4f3a7c0143adfbeac", [ null, {} @@ -466249,14 +466903,14 @@ ] ], "fcp-canvas-context.html": [ - "5f3c9d9983bf0404509fc960d1b7dd66b058950f", + "077c1aa3ddc3c415a12ff2055394d24d4dc30cc8", [ null, {} ] ], "fcp-gradient.html": [ - "1d15812a0f3ea5c274017f028f42cc2c242a83b3", + "b9f86d8dd7381cf07f6d20515313240e93729167", [ null, {} @@ -466368,7 +467022,7 @@ ] ], "fcp-text-input.html": [ - "b22c618c119fd7cf99cfbf2b53c0dfbaaef5983e", + "0b7e568359fc382c8ed6c18216e334abcd05958d", [ null, {} @@ -466382,14 +467036,14 @@ ] ], "fcp-video-frame.html": [ - "0f61b7e5289b69457258258db4b2daea6224b5df", + "cdfd1670715d42fbefc123a40403096be4dd1bad", [ null, {} ] ], "fcp-video-poster.html": [ - "5c1048ac0a7992c454ce9f542036a0b6bcf2edc2", + "eb9b1399b52f50dbcf99639d50db5ad153d7e33a", [ null, {} @@ -466403,7 +467057,7 @@ ] ], "fcp-with-rtl.html": [ - "868d2fcaf8fdfaf3f20713375688aa106c579b03", + "e9fc2857832b83fdd191697c5aa37c9140763447", [ null, {} @@ -466411,42 +467065,42 @@ ] }, "first-contentful-bg-image.html": [ - "9c3b2200fb667f66925be4333a78b23914749617", + "3da3d2553ee81d65c2b9540d49f8ac8352d41e8d", [ null, {} ] ], "first-contentful-canvas.html": [ - "ab47aa0c21c2cc3312f3f370a2566b80ecf8d13b", + "667591cfe363ec4e677b6f808f63790178f9a354", [ null, {} ] ], "first-contentful-image.html": [ - "034391c796cf23e9a99f2ddcfb5d18fcf5607da2", + "5c29bfe070f5144fbd3f52c3e049486fd611ebef", [ null, {} ] ], "first-contentful-paint.html": [ - "67d7b95eaa5525b184b9d4abbc2e6595570caa09", + "de2ac0352328bb007ccac39756578ca4e91db9f2", [ null, {} ] ], "first-contentful-svg.html": [ - "8cda11c95671f98a5ed6e2b1a83cfd77243f6744", + "9909ec659eff2a110f8ff7d8e867509913bf6d60", [ null, {} ] ], "first-image-child.html": [ - "3f073144692ea6732951aff7839b9cf8baf01e14", + "9b48ff89056cf261a5e469e42569d8df726845b5", [ null, { @@ -466455,14 +467109,14 @@ ] ], "first-paint-bg-color.html": [ - "5e863794d41850bc5422b0f759949b25bad63751", + "21271da4cefba4fe06611ec345372d8477ee806c", [ null, {} ] ], "first-paint-only.html": [ - "ea735a246b3c3c2bf47e0772b0b134c7f3663051", + "99f41f97b175cc55d29628d0e9f052a7b5b581e3", [ null, {} @@ -466501,7 +467155,7 @@ ] ], "paint-visited.html": [ - "9a5561d5f7f317738d406d45bf371013f5cf3f25", + "d611197b28873b2a549dd4c90220be5d1f5af92b", [ null, {} @@ -466515,14 +467169,14 @@ ] ], "sibling-painting-first-image.html": [ - "16a6f145db0265b60a10b5f7da9fab9dc97a946a", + "d8fec53047f91ec20faa4a6959f580d3643794c3", [ null, {} ] ], "supported-paint-type.window.js": [ - "c2c3cf5d6dd8786d69e34012eb9453073affffef", + "518faff5cfb2240a0ab70c5729be77b456ebef93", [ "paint-timing/supported-paint-type.window.html", {} @@ -467448,7 +468102,7 @@ ] ], "po-observe-type.any.js": [ - "2c0719a8d146882ad317ff2418e89d4e77a2da18", + "b9854cc1466fa7856c8807e7234db5fe182c558f", [ "performance-timeline/po-observe-type.any.html", { @@ -467473,7 +468127,7 @@ ] ], "po-observe.any.js": [ - "7d7de376b25ceb1b0c3cd26a4dd27e802b10b155", + "5b593374baf157cd33207956273d049926741ad2", [ "performance-timeline/po-observe.any.html", { @@ -468701,7 +469355,7 @@ }, "portals": { "about-blank-cannot-host.html": [ - "7aba015e69b85a173c7a63dc277aedafeefc63a2", + "c43fbc93ba7b97cf4bf38da2924b597809a97bca", [ null, {} @@ -468718,7 +469372,7 @@ ] ], "frame-src.sub.html": [ - "1b37fd4ac2148e10828112876bb8ad0aaa818075", + "13d9e79667f2d43a8c12817bb374a72a0116b33a", [ null, {} @@ -468734,7 +469388,7 @@ ] ], "history-manipulation-inside-portal.html": [ - "efbf1de136cca726701fc1827dd0a00fda93c987", + "d4b0cf4db9e0b4ab7289dafa73de0bd493ed6605", [ null, {} @@ -468742,14 +469396,14 @@ ] }, "htmlportalelement-event-handler-content-attributes.html": [ - "04b4615205ae9f036231370b9d30aa217608f2c4", + "0836c8c00b5ed1a59fd55b942b7840b34317cb9f", [ null, {} ] ], "portal-activate-data.html": [ - "260bb00ff0686cf30034b9b98317cffebdf05d2c", + "54fdca5d8cded9f7e9625e35239c818af43abe20", [ null, {} @@ -468763,77 +469417,77 @@ ] ], "portal-activate-event.html": [ - "990dc2d4b85ac3ca49e246ba17249a2986592e4d", + "69d8a7c930ef5be41d1dc858a8094c9d0a5bda8a", [ null, {} ] ], "portal-non-http-navigation.html": [ - "e2b5d3d3937e4991d99caa3d87901ffe6202a100", + "aa02c15efa975d63ed6f1e4c3e446ca7c5f99074", [ null, {} ] ], "portal-onload-event.html": [ - "da770013e26506cca3a314e39f6deb962e42578f", + "f6b97a814ed79b4178f8b8e0cd8620f98683cc88", [ null, {} ] ], "portals-activate-empty-browsing-context.html": [ - "d904cd58543ff02c280d3f43267b8d54cad7882b", + "b1787782ffde532600cebd55c1e5cc1a29a0232d", [ null, {} ] ], "portals-activate-inside-iframe.html": [ - "587e483479cf8e616694de345ecb681a69214e61", + "f4039540961dda768c07ef8a580581911fbbb12f", [ null, {} ] ], "portals-activate-inside-portal.html": [ - "bd0d9e27bb6b25adbc3844adc8f8f947cf83dce1", + "19b57b3e42e4227d2af780486d3d1d53ceb4a34d", [ null, {} ] ], "portals-activate-network-error.html": [ - "c2094fd4ded233f33f5a7631c2f9d2309567d624", + "60ee5c902da70a5a1027b8f71528ac7599fa7f5e", [ null, {} ] ], "portals-activate-no-browsing-context.html": [ - "bfc45f68c1859401b015d9cd22aaf50cdefb1770", + "ccf1e9504be301331d93412cc25f7205347ff864", [ null, {} ] ], "portals-activate-resolution.html": [ - "ada8d4619a075df9c8c422c5d8ff54a0f9700deb", + "7094768a4f81fe25136f3b2647d4c9b9451ab817", [ null, {} ] ], "portals-activate-twice.html": [ - "eaef8b7cc94e0e62bc34e32d4c48c7b6bcb9f83d", + "0eea5465a2b2d9629579e409325a1cd948892fe8", [ null, {} ] ], "portals-adopt-predecessor.html": [ - "21893987e63839bbfb8a9d67e0f41e7502c88812", + "04c61960627836b54e1a04da168c075b1ba93723", [ null, {} @@ -468847,14 +469501,14 @@ ] ], "portals-cross-origin-load.sub.html": [ - "be817b8a0aa44de1773f7c9448a572a15bec9866", + "04db38a8e9a2d9b2ac5ffe1078f3015dd0b9204e", [ null, {} ] ], "portals-focus.sub.html": [ - "54fcf3a3d4734f0a1a1f49462afbeba21a5a0644", + "ccbac7db906054b4914f179f1a9aadcbd6960cc3", [ null, { @@ -468864,14 +469518,14 @@ ] ], "portals-host-exposure.sub.html": [ - "3ff88413691db6c64b1cdb7a23fe2191640d47c2", + "93ee8ecdc0968b71aa19927cfce39191b8d33e16", [ null, {} ] ], "portals-host-hidden-after-activation.html": [ - "571ec55810aa8e76c3dd977f774b3a1eeb835904", + "9638a6c7c6a84ccf040b80e9d98160b41c5d66bb", [ null, {} @@ -468885,7 +469539,7 @@ ] ], "portals-host-post-message.sub.html": [ - "8750dd43d011ccf48d40f9671bd02c8dd29047c1", + "e547642c9f27e91a1bd911214fba7750f136ed8d", [ null, { @@ -468894,21 +469548,21 @@ ] ], "portals-navigate-after-adoption.html": [ - "f403902031303f21b9019c159d63b39ba1ff00d1", + "1ca1cfb79f3d68f358cdd8fd70f5ca92665d6c51", [ null, {} ] ], "portals-nested.html": [ - "41d053bd48d11a9511168bf570e2d9d08bd78fdb", + "b4b396ff8dd1be5e2af8048160238a9c7a94be3e", [ null, {} ] ], "portals-post-message.sub.html": [ - "f3927a0c05ace4e9e811548d49f6e0114560abf6", + "2f6b25d97dab30d1b8ae86a6ab27526393dad3eb", [ null, { @@ -468918,42 +469572,42 @@ ] ], "portals-referrer-inherit-header.html": [ - "da908cb2c21ff0c7996d36b326f18f400ad8b6be", + "1fbd88893e41ef0e0d638864e45111250bf96470", [ null, {} ] ], "portals-referrer-inherit-meta.html": [ - "eecb247973e838c6fc5e09f32180fe58c81a2727", + "e77894cfa4d905e87accb98d04f363971350be02", [ null, {} ] ], "portals-referrer.html": [ - "b9abcdb80de70dd5ed8135617945d59bdbb35269", + "4cd3b908958bf2d7aaf9bdee44b2cc99b476ea6d", [ null, {} ] ], "portals-repeated-activate.html": [ - "bf8d8ad42641c4d775db4255087383007df07698", + "f2f36cb76828e23570aab88ec839578967b70690", [ null, {} ] ], "portals-set-src-after-activate.html": [ - "f9728170858792aae99aebeffe507bc5c94b0e19", + "e485ef4d51c3d60a1840d1589bac939f2b3296e6", [ null, {} ] ], "predecessor-fires-unload.html": [ - "dce2afb8e6fde03c292456a7e960b52b8558c8ca", + "cb6d98c01d0d19f0cfa42712026fae5beb9f2c6f", [ null, {} @@ -468961,7 +469615,7 @@ ], "xfo": { "portals-xfo-deny.sub.html": [ - "2110d4906f9dd0769beb07cf428ecf3ce40ef370", + "efc925276c9bf3c05c6ab9743e75090a5fea894e", [ null, { @@ -483455,6 +484109,13 @@ null, {} ] + ], + "script-access.tentative.html": [ + "3ecfce55aa3699c8af8ced49cbdad0c1b9b3d0c6", + [ + null, + {} + ] ] }, "event-composed-path-after-dom-mutation.html": [ @@ -484942,7 +485603,7 @@ ] ], "historical.html": [ - "9da70c44de9be25933d95d7e6fd2f3ae69a04333", + "99d2fab5f52654f21f6e8f76878b1a44722b101f", [ null, {} @@ -492951,6 +493612,13 @@ null, {} ] + ], + "stroke-dashes-hit-at-high-scale.svg": [ + "b57a9e0aa7714e7a821c74d24f6578ab7d6286b3", + [ + null, + {} + ] ] } }, @@ -493357,6 +494025,13 @@ {} ] ], + "SVGGeometryElement.isPointInStroke-02.svg": [ + "909b035ef4779dd52f3e923a54efb63c526a3457", + [ + null, + {} + ] + ], "SVGGraphicsElement.getBBox-01.html": [ "a56dc4093203bcdcdc1f8b019a52f85f71eae23a", [ @@ -493534,13 +494209,6 @@ null, {} ] - ], - "has-trust-token.tentative.https.html": [ - "17e037f739391c5adcab67fc54dd8d4f0cb7764f", - [ - null, - {} - ] ] }, "trust-token-parameter-validation-xhr.tentative.https.html": [ @@ -496984,14 +497652,21 @@ ] ], "request-video-frame-callback-repeating.html": [ - "0f9aa55717c73bf0617477fff1fa1b0e258408f7", + "bfdedb4bec00fe99f01ab6225e8b85a47617b3dd", + [ + null, + {} + ] + ], + "request-video-frame-callback-webrtc.https.html": [ + "b6131d6a808759346aa54b9e400e535b6c3ca29c", [ null, {} ] ], "request-video-frame-callback.html": [ - "743cbc60b5479a58f516ff27c0eb8b73b3cce986", + "6660fadeaf47460fb274e2801ff2b2528147e010", [ null, {} @@ -499735,15 +500410,29 @@ "web-animations": { "animation-model": { "animation-types": { - "accumulation-per-property.html": [ - "420617d1194e9c5acf994b7af4a7ff54454c671f", + "accumulation-per-property-001.html": [ + "a3fd115563b3c934bf3f75fad0eabde1eae7e1e9", + [ + null, + {} + ] + ], + "accumulation-per-property-002.html": [ + "5cf411edf6ed3b052fab1f76442daca66433cec0", + [ + null, + {} + ] + ], + "addition-per-property-001.html": [ + "2fbec2c4cd0a4fdc78d3c08486d34780e483e7d9", [ null, {} ] ], - "addition-per-property.html": [ - "f17eedabbdd5035338a723e5dfe8159d79c5c554", + "addition-per-property-002.html": [ + "3b1c40e3c730b1428a2d4f1e4c8d70f8574c7432", [ null, {} @@ -499756,8 +500445,15 @@ {} ] ], - "interpolation-per-property.html": [ - "fe23d89fd06ba28ce6b293c6bea2b8fc03ee1f2d", + "interpolation-per-property-001.html": [ + "97f28224733511e37bf83bc7e653a2b4ff7f88b6", + [ + null, + {} + ] + ], + "interpolation-per-property-002.html": [ + "9ccc613cfc64dff7e4c4d5e9edf5963d3282da40", [ null, {} @@ -503418,137 +504114,105 @@ }, "webgpu": { "cts.html": [ - "058d3b3c4ad6bf098529234bcae42d34c2969dac", - [ - "webgpu/cts.html?q=cts:buffers/create_mapped", - {} - ], - [ - "webgpu/cts.html?q=cts:buffers/map", - {} - ], - [ - "webgpu/cts.html?q=cts:buffers/map_detach", - {} - ], - [ - "webgpu/cts.html?q=cts:buffers/map_oom", - {} - ], - [ - "webgpu/cts.html?q=cts:canvas/context_creation", - {} - ], - [ - "webgpu/cts.html?q=cts:command_buffer/basic", - {} - ], - [ - "webgpu/cts.html?q=cts:command_buffer/compute/basic", - {} - ], - [ - "webgpu/cts.html?q=cts:command_buffer/copies", - {} - ], + "62340be400ed172b3997a68680e7f6c9e36dfeca", [ - "webgpu/cts.html?q=cts:command_buffer/render/basic", + "webgpu/cts.html?q=webgpu:api/operation/buffers/create_mapped", {} ], [ - "webgpu/cts.html?q=cts:command_buffer/render/rendering", + "webgpu/cts.html?q=webgpu:api/operation/buffers/map", {} ], [ - "webgpu/cts.html?q=cts:command_buffer/render/storeop", + "webgpu/cts.html?q=webgpu:api/operation/buffers/map_detach", {} ], [ - "webgpu/cts.html?q=cts:copyImageBitmapToTexture", + "webgpu/cts.html?q=webgpu:api/operation/buffers/map_oom", {} ], [ - "webgpu/cts.html?q=cts:examples", + "webgpu/cts.html?q=webgpu:api/operation/command_buffer/basic", {} ], [ - "webgpu/cts.html?q=cts:fences", + "webgpu/cts.html?q=webgpu:api/operation/command_buffer/copies", {} ], [ - "webgpu/cts.html?q=cts:resource_init/sampled_texture_clear", + "webgpu/cts.html?q=webgpu:api/operation/command_buffer/render/basic", {} ], [ - "webgpu/cts.html?q=cts:validation/createBindGroup", + "webgpu/cts.html?q=webgpu:api/operation/fences", {} ], [ - "webgpu/cts.html?q=cts:validation/createBindGroupLayout", + "webgpu/cts.html?q=webgpu:api/validation/createBindGroup", {} ], [ - "webgpu/cts.html?q=cts:validation/createPipelineLayout", + "webgpu/cts.html?q=webgpu:api/validation/createBindGroupLayout", {} ], [ - "webgpu/cts.html?q=cts:validation/createRenderPipeline", + "webgpu/cts.html?q=webgpu:api/validation/createPipelineLayout", {} ], [ - "webgpu/cts.html?q=cts:validation/createTexture", + "webgpu/cts.html?q=webgpu:api/validation/createTexture", {} ], [ - "webgpu/cts.html?q=cts:validation/createView", + "webgpu/cts.html?q=webgpu:api/validation/createView", {} ], [ - "webgpu/cts.html?q=cts:validation/error_scope", + "webgpu/cts.html?q=webgpu:api/validation/error_scope", {} ], [ - "webgpu/cts.html?q=cts:validation/fences", + "webgpu/cts.html?q=webgpu:api/validation/fences", {} ], [ - "webgpu/cts.html?q=cts:validation/queue_submit", + "webgpu/cts.html?q=webgpu:api/validation/queue_submit", {} ], [ - "webgpu/cts.html?q=cts:validation/render_pass", + "webgpu/cts.html?q=webgpu:api/validation/render_pass_descriptor", {} ], [ - "webgpu/cts.html?q=cts:validation/render_pass_descriptor", + "webgpu/cts.html?q=webgpu:api/validation/setBindGroup", {} ], [ - "webgpu/cts.html?q=cts:validation/setBindGroup", + "webgpu/cts.html?q=webgpu:api/validation/setBlendColor", {} ], [ - "webgpu/cts.html?q=cts:validation/setBlendColor", + "webgpu/cts.html?q=webgpu:api/validation/setScissorRect", {} ], [ - "webgpu/cts.html?q=cts:validation/setScissorRect", + "webgpu/cts.html?q=webgpu:api/validation/setStencilReference", {} ], [ - "webgpu/cts.html?q=cts:validation/setStencilReference", + "webgpu/cts.html?q=webgpu:api/validation/setViewport", {} ], [ - "webgpu/cts.html?q=cts:validation/setVertexBuffer", + "webgpu/cts.html?q=webgpu:examples", {} ], [ - "webgpu/cts.html?q=cts:validation/setViewport", + "webgpu/cts.html?q=webgpu:web-platform/canvas/context_creation", {} ], [ - "webgpu/cts.html?q=cts:validation/vertex_state", + "webgpu/cts.html?q=webgpu:web-platform/copyImageBitmapToTexture", {} ] ] @@ -513584,7 +514248,7 @@ ] ], "shared-worker-parse-error-failure.html": [ - "0d8e390382f1127856ed3c26ec5b3cd0a1648280", + "8f63d5f37aaf6a50ee8b0a7d7dd8268db7749eba", [ null, {} diff --git a/tests/wpt/metadata/css/CSS2/floats/hit-test-floats-004.html.ini b/tests/wpt/metadata/css/CSS2/floats/hit-test-floats-004.html.ini deleted file mode 100644 index 4bfb0c2053a..00000000000 --- a/tests/wpt/metadata/css/CSS2/floats/hit-test-floats-004.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[hit-test-floats-004.html] - [Miss float below something else] - expected: FAIL - diff --git a/tests/wpt/metadata/css/CSS2/floats/hit-test-floats-005.html.ini b/tests/wpt/metadata/css/CSS2/floats/hit-test-floats-005.html.ini new file mode 100644 index 00000000000..baa9f1a7541 --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/floats/hit-test-floats-005.html.ini @@ -0,0 +1,4 @@ +[hit-test-floats-005.html] + [Miss clipped float] + expected: FAIL + diff --git a/tests/wpt/metadata/css/css-animations/animation-base-response-004.html.ini b/tests/wpt/metadata/css/css-animations/animation-base-response-004.html.ini new file mode 100644 index 00000000000..6e98c32bc87 --- /dev/null +++ b/tests/wpt/metadata/css/css-animations/animation-base-response-004.html.ini @@ -0,0 +1,4 @@ +[animation-base-response-004.html] + [Base is responsive to font-affecting appearing via setKeyframes] + expected: FAIL + diff --git a/tests/wpt/metadata/css/css-backgrounds/parsing/background-image-computed.sub.html.ini b/tests/wpt/metadata/css/css-backgrounds/parsing/background-image-computed.sub.html.ini index ec42c320759..1e7e5e2716f 100644 --- a/tests/wpt/metadata/css/css-backgrounds/parsing/background-image-computed.sub.html.ini +++ b/tests/wpt/metadata/css/css-backgrounds/parsing/background-image-computed.sub.html.ini @@ -5,30 +5,9 @@ [Property background-image value 'conic-gradient(from 45deg at 10px 10px, red, blue)'] expected: FAIL - [Property background-image value 'radial-gradient(at 50%, red, blue)'] - expected: FAIL - - [Property background-image value 'radial-gradient(farthest-side, rgb(255, 0, 0), rgb(0, 0, 255))'] - expected: FAIL - - [Property background-image value 'radial-gradient(farthest-corner at 50%, red, blue)'] - expected: FAIL - - [Property background-image value 'radial-gradient(farthest-corner at center, red, blue)'] - expected: FAIL - - [Property background-image value 'radial-gradient(at center, red, blue)'] - expected: FAIL - [Property background-image value 'conic-gradient(from 0deg, red, blue)'] expected: FAIL - [Property background-image value 'radial-gradient(farthest-corner, red, blue)'] - expected: FAIL - - [Property background-image value 'radial-gradient(rgb(255, 0, 0), rgb(0, 0, 255))'] - expected: FAIL - [Property background-image value 'conic-gradient(at 10px 10px, rgb(255, 0, 0), rgb(0, 0, 255))'] expected: FAIL diff --git a/tests/wpt/metadata/css/css-text/white-space/break-spaces-newline-011.html.ini b/tests/wpt/metadata/css/css-text/white-space/break-spaces-newline-011.html.ini new file mode 100644 index 00000000000..fdf5abac767 --- /dev/null +++ b/tests/wpt/metadata/css/css-text/white-space/break-spaces-newline-011.html.ini @@ -0,0 +1,2 @@ +[break-spaces-newline-011.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-text/white-space/break-spaces-newline-012.html.ini b/tests/wpt/metadata/css/css-text/white-space/break-spaces-newline-012.html.ini new file mode 100644 index 00000000000..098fde40fb1 --- /dev/null +++ b/tests/wpt/metadata/css/css-text/white-space/break-spaces-newline-012.html.ini @@ -0,0 +1,2 @@ +[break-spaces-newline-012.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-text/white-space/break-spaces-newline-013.html.ini b/tests/wpt/metadata/css/css-text/white-space/break-spaces-newline-013.html.ini new file mode 100644 index 00000000000..b3b08d61395 --- /dev/null +++ b/tests/wpt/metadata/css/css-text/white-space/break-spaces-newline-013.html.ini @@ -0,0 +1,2 @@ +[break-spaces-newline-013.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-text/white-space/break-spaces-newline-014.html.ini b/tests/wpt/metadata/css/css-text/white-space/break-spaces-newline-014.html.ini new file mode 100644 index 00000000000..61a082b5e0f --- /dev/null +++ b/tests/wpt/metadata/css/css-text/white-space/break-spaces-newline-014.html.ini @@ -0,0 +1,2 @@ +[break-spaces-newline-014.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-text/white-space/break-spaces-newline-015.html.ini b/tests/wpt/metadata/css/css-text/white-space/break-spaces-newline-015.html.ini new file mode 100644 index 00000000000..c1b8824ba0f --- /dev/null +++ b/tests/wpt/metadata/css/css-text/white-space/break-spaces-newline-015.html.ini @@ -0,0 +1,2 @@ +[break-spaces-newline-015.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-text/white-space/break-spaces-newline-016.html.ini b/tests/wpt/metadata/css/css-text/white-space/break-spaces-newline-016.html.ini new file mode 100644 index 00000000000..c329c7f08b9 --- /dev/null +++ b/tests/wpt/metadata/css/css-text/white-space/break-spaces-newline-016.html.ini @@ -0,0 +1,2 @@ +[break-spaces-newline-016.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/css-transitions/events-005.html.ini b/tests/wpt/metadata/css/css-transitions/events-005.html.ini index cb829ed6873..dc242640441 100644 --- a/tests/wpt/metadata/css/css-transitions/events-005.html.ini +++ b/tests/wpt/metadata/css/css-transitions/events-005.html.ini @@ -2,9 +2,6 @@ [padding-left, padding] expected: FAIL - [padding, padding-left] - expected: FAIL - [property repetition] expected: FAIL diff --git a/tests/wpt/metadata/css/css-transitions/properties-value-002.html.ini b/tests/wpt/metadata/css/css-transitions/properties-value-002.html.ini index bea1e56e44e..efcb0d74128 100644 --- a/tests/wpt/metadata/css/css-transitions/properties-value-002.html.ini +++ b/tests/wpt/metadata/css/css-transitions/properties-value-002.html.ini @@ -2,27 +2,3 @@ [vertical-align vertical(keyword) / values] expected: FAIL - [margin-right percentage(%) / events] - expected: FAIL - - [padding-top percentage(%) / events] - expected: FAIL - - [margin-top percentage(%) / events] - expected: FAIL - - [margin-bottom percentage(%) / events] - expected: FAIL - - [padding-right percentage(%) / events] - expected: FAIL - - [padding-left percentage(%) / events] - expected: FAIL - - [padding-bottom percentage(%) / events] - expected: FAIL - - [margin-left percentage(%) / events] - expected: FAIL - diff --git a/tests/wpt/metadata/css/css-variables/variable-substitution-variable-declaration.html.ini b/tests/wpt/metadata/css/css-variables/variable-substitution-variable-declaration.html.ini deleted file mode 100644 index 9e37f672721..00000000000 --- a/tests/wpt/metadata/css/css-variables/variable-substitution-variable-declaration.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[variable-substitution-variable-declaration.html] - [target10 --varC] - expected: FAIL - diff --git a/tests/wpt/metadata/css/cssom-view/elementFromPoint-001.html.ini b/tests/wpt/metadata/css/cssom-view/elementFromPoint-001.html.ini new file mode 100644 index 00000000000..e38782d8c85 --- /dev/null +++ b/tests/wpt/metadata/css/cssom-view/elementFromPoint-001.html.ini @@ -0,0 +1,4 @@ +[elementFromPoint-001.html] + [CSSOM View - 5 - extensions to the Document interface] + expected: FAIL + diff --git a/tests/wpt/metadata/css/cssom-view/elementsFromPoint-iframes.html.ini b/tests/wpt/metadata/css/cssom-view/elementsFromPoint-iframes.html.ini index 171592fc08f..6ef8bb1049f 100644 --- a/tests/wpt/metadata/css/cssom-view/elementsFromPoint-iframes.html.ini +++ b/tests/wpt/metadata/css/cssom-view/elementsFromPoint-iframes.html.ini @@ -2,3 +2,6 @@ [elementsFromPoint on the root document for points in iframe elements] expected: FAIL + [elementsFromPoint on inner documents] + expected: FAIL + diff --git a/tests/wpt/metadata/css/cssom-view/elementsFromPoint-invalid-cases.html.ini b/tests/wpt/metadata/css/cssom-view/elementsFromPoint-invalid-cases.html.ini deleted file mode 100644 index e181af5397f..00000000000 --- a/tests/wpt/metadata/css/cssom-view/elementsFromPoint-invalid-cases.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[elementsFromPoint-invalid-cases.html] - [The root element is the last element returned for otherwise empty queries within the viewport] - expected: FAIL - diff --git a/tests/wpt/metadata/custom-elements/custom-element-reaction-queue.html.ini b/tests/wpt/metadata/custom-elements/custom-element-reaction-queue.html.ini index 03f40d084f0..ba3c2cf771c 100644 --- a/tests/wpt/metadata/custom-elements/custom-element-reaction-queue.html.ini +++ b/tests/wpt/metadata/custom-elements/custom-element-reaction-queue.html.ini @@ -2,3 +2,6 @@ [Custom Elements: Each element must have its own custom element reaction queue] expected: FAIL + [Upgrading a custom element must not invoke attributeChangedCallback for the attribute that is changed during upgrading] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/content-type/response.window.js.ini b/tests/wpt/metadata/fetch/content-type/response.window.js.ini index 87354d1e79a..6dcb54ae103 100644 --- a/tests/wpt/metadata/fetch/content-type/response.window.js.ini +++ b/tests/wpt/metadata/fetch/content-type/response.window.js.ini @@ -312,12 +312,27 @@ [fetch(): separate response Content-Type: text/plain ] expected: NOTRUN - [<iframe>: combined response Content-Type: text/html;x=" text/plain] + [<iframe>: separate response Content-Type: text/plain */*;charset=gbk] expected: FAIL - [<iframe>: separate response Content-Type: text/html;" \\" text/plain] + [<iframe>: separate response Content-Type: text/html;" text/plain] expected: FAIL - [<iframe>: separate response Content-Type: text/plain */*;charset=gbk] + [<iframe>: separate response Content-Type: text/html */*] + expected: FAIL + + [<iframe>: combined response Content-Type: text/html;" \\" text/plain] + expected: FAIL + + [<iframe>: combined response Content-Type: text/html;" text/plain] + expected: FAIL + + [<iframe>: combined response Content-Type: text/html */*] + expected: FAIL + + [<iframe>: separate response Content-Type: text/plain */*] + expected: FAIL + + [<iframe>: combined response Content-Type: text/html */*;charset=gbk] expected: FAIL diff --git a/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini b/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini index 70efd28ddfc..30e1b851fd4 100644 --- a/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini +++ b/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini @@ -11,6 +11,3 @@ [X-Content-Type-Options%3A%20nosniff%2C%2C%40%23%24%23%25%25%26%5E%26%5E*()()11!] expected: FAIL - [X-Content-Type-Options%3A%20no%0D%0AX-Content-Type-Options%3A%20nosniff] - expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini deleted file mode 100644 index 51f8272a6de..00000000000 --- a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[traverse_the_history_3.html] - [Multiple history traversals, last would be aborted] - expected: FAIL - diff --git a/tests/wpt/metadata/html/interaction/focus/the-autofocus-attribute/skip-document-with-fragment.html.ini b/tests/wpt/metadata/html/interaction/focus/the-autofocus-attribute/skip-document-with-fragment.html.ini index 6852d7663de..c12c0f8ae48 100644 --- a/tests/wpt/metadata/html/interaction/focus/the-autofocus-attribute/skip-document-with-fragment.html.ini +++ b/tests/wpt/metadata/html/interaction/focus/the-autofocus-attribute/skip-document-with-fragment.html.ini @@ -1,8 +1,4 @@ [skip-document-with-fragment.html] - expected: TIMEOUT [Autofocus elements in iframed documents with URL fragments should be skipped.] expected: FAIL - [Autofocus elements in top-level browsing context's documents with URI fragments should be skipped.] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/html/interaction/focus/the-autofocus-attribute/supported-elements.html.ini b/tests/wpt/metadata/html/interaction/focus/the-autofocus-attribute/supported-elements.html.ini index f1aa94c7ced..8b743f36e1d 100644 --- a/tests/wpt/metadata/html/interaction/focus/the-autofocus-attribute/supported-elements.html.ini +++ b/tests/wpt/metadata/html/interaction/focus/the-autofocus-attribute/supported-elements.html.ini @@ -4,7 +4,7 @@ expected: FAIL [Element with tabindex should support autofocus] - expected: FAIL + expected: TIMEOUT [Host element with delegatesFocus including no focusable descendants should be skipped] expected: NOTRUN @@ -16,5 +16,5 @@ expected: NOTRUN [Non-HTMLElement should not support autofocus] - expected: TIMEOUT + expected: NOTRUN diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html.ini index 3a32693ffa8..d43f38b40cd 100644 --- a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html.ini +++ b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html.ini @@ -1,5 +1,6 @@ [iframe_sandbox_popups_nonescaping-2.html] type: testharness + expected: TIMEOUT [Check that popups from a sandboxed iframe do not escape the sandbox] - expected: FAIL + expected: NOTRUN diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini index 2568040e6e5..e440b1e38c6 100644 --- a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini +++ b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini @@ -1,6 +1,6 @@ [iframe_sandbox_popups_nonescaping-3.html] type: testharness - expected: CRASH + expected: TIMEOUT [Check that popups from a sandboxed iframe do not escape the sandbox] - expected: FAIL + expected: NOTRUN diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/currentSrc-blob-cache.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/currentSrc-blob-cache.html.ini new file mode 100644 index 00000000000..2c4a51d2910 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/currentSrc-blob-cache.html.ini @@ -0,0 +1,4 @@ +[currentSrc-blob-cache.html] + [currentSrc is right even if underlying image is a shared blob] + expected: FAIL + diff --git a/tests/wpt/metadata/performance-timeline/po-observe-type.any.js.ini b/tests/wpt/metadata/performance-timeline/po-observe-type.any.js.ini new file mode 100644 index 00000000000..6cfbce70872 --- /dev/null +++ b/tests/wpt/metadata/performance-timeline/po-observe-type.any.js.ini @@ -0,0 +1,15 @@ +[po-observe-type.any.html] + [Calling observe() with type and entryTypes should throw a TypeError] + expected: FAIL + + [Calling observe() without 'type' or 'entryTypes' throws a TypeError] + expected: FAIL + + +[po-observe-type.any.worker.html] + [Calling observe() with type and entryTypes should throw a TypeError] + expected: FAIL + + [Calling observe() without 'type' or 'entryTypes' throws a TypeError] + expected: FAIL + diff --git a/tests/wpt/metadata/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels.html.ini b/tests/wpt/metadata/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels.html.ini index 8fd17170541..636cb8a14da 100644 --- a/tests/wpt/metadata/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels.html.ini +++ b/tests/wpt/metadata/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels.html.ini @@ -149,3 +149,9 @@ [X Rendered audio for channel 5 does not equal [0,0.0626220703125,0.125030517578125,0.18695068359375,0.24810791015625,0.308319091796875,0.3673095703125,0.42486572265625,0.480743408203125,0.53472900390625,0.58660888671875,0.636199951171875,0.68328857421875,0.727691650390625,0.76922607421875,0.8077392578125...\] with an element-wise tolerance of {"absoluteThreshold":0.000030517578125,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[1\]\t3.6732959747314453e-1\t6.2622070312500000e-2\t3.0470752716064453e-1\t4.8658168859649127e+0\t3.0517578125000000e-5\n\t[2\]\t6.8329977989196777e-1\t1.2503051757812500e-1\t5.5826926231384277e-1\t4.4650639949963384e+0\t3.0517578125000000e-5\n\t[3\]\t9.0373212099075317e-1\t1.8695068359375000e-1\t7.1678143739700317e-1\t3.8340669508039502e+0\t3.0517578125000000e-5\n\t[4\]\t9.9780619144439697e-1\t2.4810791015625000e-1\t7.4969828128814697e-1\t3.0216621502152523e+0\t3.0517578125000000e-5\n\t[5\]\t9.5236867666244507e-1\t3.0831909179687500e-1\t6.4404958486557007e-1\t2.0889059484187866e+0\t3.0517578125000000e-5\n\t...and 44054 more errors.\n\tMax AbsError of 1.9961981773376465e+0 at index of 18538.\n\t[18538\]\t-9.9879217147827148e-1\t9.9740600585937500e-1\t1.9961981773376465e+0\t2.0013897706758867e+0\t3.0517578125000000e-5\n\tMax RelError of Infinity at index of 12348.\n\t[12348\]\t9.5105654001235962e-1\t0.0000000000000000e+0\t9.5105654001235962e-1\tInfinity\t3.0517578125000000e-5\n] expected: FAIL + [X Rendered audio for channel 5 does not equal [0,0.0626220703125,0.125030517578125,0.18695068359375,0.24810791015625,0.308319091796875,0.3673095703125,0.42486572265625,0.480743408203125,0.53472900390625,0.58660888671875,0.636199951171875,0.68328857421875,0.727691650390625,0.76922607421875,0.8077392578125...\] with an element-wise tolerance of {"absoluteThreshold":0.000030517578125,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[1\]\t3.6732959747314453e-1\t6.2622070312500000e-2\t3.0470752716064453e-1\t4.8658168859649127e+0\t3.0517578125000000e-5\n\t[2\]\t6.8329977989196777e-1\t1.2503051757812500e-1\t5.5826926231384277e-1\t4.4650639949963384e+0\t3.0517578125000000e-5\n\t[3\]\t9.0373212099075317e-1\t1.8695068359375000e-1\t7.1678143739700317e-1\t3.8340669508039502e+0\t3.0517578125000000e-5\n\t[4\]\t9.9780619144439697e-1\t2.4810791015625000e-1\t7.4969828128814697e-1\t3.0216621502152523e+0\t3.0517578125000000e-5\n\t[5\]\t9.5236867666244507e-1\t3.0831909179687500e-1\t6.4404958486557007e-1\t2.0889059484187866e+0\t3.0517578125000000e-5\n\t...and 44051 more errors.\n\tMax AbsError of 1.9999794363975525e+0 at index of 19632.\n\t[19632\]\t9.9997943639755249e-1\t-1.0000000000000000e+0\t1.9999794363975525e+0\t1.9999794363975525e+0\t3.0517578125000000e-5\n\tMax RelError of Infinity at index of 12348.\n\t[12348\]\t9.5105654001235962e-1\t0.0000000000000000e+0\t9.5105654001235962e-1\tInfinity\t3.0517578125000000e-5\n] + expected: FAIL + + [X Rendered audio for channel 5 does not equal [0,0.0626220703125,0.125030517578125,0.18695068359375,0.24810791015625,0.308319091796875,0.3673095703125,0.42486572265625,0.480743408203125,0.53472900390625,0.58660888671875,0.636199951171875,0.68328857421875,0.727691650390625,0.76922607421875,0.8077392578125...\] with an element-wise tolerance of {"absoluteThreshold":0.000030517578125,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[1\]\t3.6732959747314453e-1\t6.2622070312500000e-2\t3.0470752716064453e-1\t4.8658168859649127e+0\t3.0517578125000000e-5\n\t[2\]\t6.8329977989196777e-1\t1.2503051757812500e-1\t5.5826926231384277e-1\t4.4650639949963384e+0\t3.0517578125000000e-5\n\t[3\]\t9.0373212099075317e-1\t1.8695068359375000e-1\t7.1678143739700317e-1\t3.8340669508039502e+0\t3.0517578125000000e-5\n\t[4\]\t9.9780619144439697e-1\t2.4810791015625000e-1\t7.4969828128814697e-1\t3.0216621502152523e+0\t3.0517578125000000e-5\n\t[5\]\t9.5236867666244507e-1\t3.0831909179687500e-1\t6.4404958486557007e-1\t2.0889059484187866e+0\t3.0517578125000000e-5\n\t...and 44047 more errors.\n\tMax AbsError of 1.9999794363975525e+0 at index of 37272.\n\t[37272\]\t9.9997943639755249e-1\t-1.0000000000000000e+0\t1.9999794363975525e+0\t1.9999794363975525e+0\t3.0517578125000000e-5\n\tMax RelError of Infinity at index of 12348.\n\t[12348\]\t9.5105654001235962e-1\t0.0000000000000000e+0\t9.5105654001235962e-1\tInfinity\t3.0517578125000000e-5\n] + expected: FAIL + diff --git a/tests/wpt/metadata/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini b/tests/wpt/metadata/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini index c8d7e71fc52..e3036148555 100644 --- a/tests/wpt/metadata/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini +++ b/tests/wpt/metadata/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini @@ -365,3 +365,9 @@ [X Stitched sine-wave buffers at sample rate 44100 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.000090957,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[31080\]\t-1.1377083450655894e+22\t5.6332010030746460e-1\t1.1377083450655894e+22\t2.0196480552435802e+22\t9.0957000000000003e-5\n\t[31081\]\t4.5654303967702540e-41\t6.1397600173950195e-1\t6.1397600173950195e-1\t1.0000000000000000e+0\t9.0957000000000003e-5\n\tMax AbsError of 1.1377083450655894e+22 at index of 31080.\n\tMax RelError of 2.0196480552435802e+22 at index of 31080.\n] expected: FAIL + [X Stitched sine-wave buffers at sample rate 44100 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.000090957,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[31080\]\t-1.7359996676420403e+17\t5.6332010030746460e-1\t1.7359996676420403e+17\t3.0817286063368198e+17\t9.0957000000000003e-5\n\t[31081\]\t4.5750993561740953e-41\t6.1397600173950195e-1\t6.1397600173950195e-1\t1.0000000000000000e+0\t9.0957000000000003e-5\n\tMax AbsError of 1.7359996676420403e+17 at index of 31080.\n\tMax RelError of 3.0817286063368198e+17 at index of 31080.\n] + expected: FAIL + + [X SNR (-301.35690681171843 dB) is not greater than or equal to 85.58. Got -301.35690681171843.] + expected: FAIL + diff --git a/tests/wpt/metadata/workers/semantics/multiple-workers/005.html.ini b/tests/wpt/metadata/workers/semantics/multiple-workers/005.html.ini index 268949ced5c..f584fce5df1 100644 --- a/tests/wpt/metadata/workers/semantics/multiple-workers/005.html.ini +++ b/tests/wpt/metadata/workers/semantics/multiple-workers/005.html.ini @@ -1,4 +1,5 @@ [005.html] + expected: ERROR [dedicated worker in shared worker in dedicated worker] expected: FAIL diff --git a/tests/wpt/web-platform-tests/.taskcluster.yml b/tests/wpt/web-platform-tests/.taskcluster.yml index 815648df512..556b9914d5b 100644 --- a/tests/wpt/web-platform-tests/.taskcluster.yml +++ b/tests/wpt/web-platform-tests/.taskcluster.yml @@ -56,7 +56,7 @@ tasks: owner: ${owner} source: ${event.repository.clone_url} payload: - image: harjgam/web-platform-tests:0.33 + image: hexcles/web-platform-tests:0.35 maxRunTime: 7200 artifacts: public/results: diff --git a/tests/wpt/web-platform-tests/2dcontext/path-objects/2d.path.isPointInStroke.scaleddashes.html b/tests/wpt/web-platform-tests/2dcontext/path-objects/2d.path.isPointInStroke.scaleddashes.html new file mode 100644 index 00000000000..55a80bc8211 --- /dev/null +++ b/tests/wpt/web-platform-tests/2dcontext/path-objects/2d.path.isPointInStroke.scaleddashes.html @@ -0,0 +1,40 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT! This test has been generated by /2dcontext/tools/gentest.py. --> +<title>Canvas test: 2d.path.isPointInStroke.scaleddashes</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/2dcontext/resources/canvas-tests.js"></script> +<link rel="stylesheet" href="/2dcontext/resources/canvas-tests.css"> +<body class="show_output"> + +<h1>2d.path.isPointInStroke.scaleddashes</h1> +<p class="desc">isPointInStroke() should return correct results on dashed paths at high scale factors</p> + + +<p class="output">Actual output:</p> +<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas> + +<ul id="d"></ul> +<script> +var t = async_test("isPointInStroke() should return correct results on dashed paths at high scale factors"); +_addTest(function(canvas, ctx) { + +var scale = 20; +ctx.setLineDash([10, 21.4159]); // dash from t=0 to t=10 along the circle +ctx.scale(scale, scale); +ctx.ellipse(6, 10, 5, 5, 0, 2*Math.PI, false); +ctx.stroke(); + +// hit-test the beginning of the dash (t=0) +_assertSame(ctx.isPointInStroke(11*scale, 10*scale), true, "ctx.isPointInStroke(11*scale, 10*scale)", "true"); +// hit-test the middle of the dash (t=5) +_assertSame(ctx.isPointInStroke(8.70*scale, 14.21*scale), true, "ctx.isPointInStroke(8.70*scale, 14.21*scale)", "true"); +// hit-test the end of the dash (t=9.8) +_assertSame(ctx.isPointInStroke(4.10*scale, 14.63*scale), true, "ctx.isPointInStroke(4.10*scale, 14.63*scale)", "true"); +// hit-test past the end of the dash (t=10.2) +_assertSame(ctx.isPointInStroke(3.74*scale, 14.46*scale), false, "ctx.isPointInStroke(3.74*scale, 14.46*scale)", "false"); + + +}); +</script> + diff --git a/tests/wpt/web-platform-tests/2dcontext/tools/tests2d.yaml b/tests/wpt/web-platform-tests/2dcontext/tools/tests2d.yaml index 42a572995a6..d8ccbe13f6d 100644 --- a/tests/wpt/web-platform-tests/2dcontext/tools/tests2d.yaml +++ b/tests/wpt/web-platform-tests/2dcontext/tools/tests2d.yaml @@ -8646,6 +8646,27 @@ @assert ctx.isPointInPath(NaN, NaN) === false; +- name: 2d.path.isPointInStroke.scaleddashes + desc: isPointInStroke() should return correct results on dashed paths at high scale factors + testing: + - 2d.path.isPointInStroke + code: | + var scale = 20; + ctx.setLineDash([10, 21.4159]); // dash from t=0 to t=10 along the circle + ctx.scale(scale, scale); + ctx.ellipse(6, 10, 5, 5, 0, 2*Math.PI, false); + ctx.stroke(); + + // hit-test the beginning of the dash (t=0) + @assert ctx.isPointInStroke(11*scale, 10*scale) === true; + // hit-test the middle of the dash (t=5) + @assert ctx.isPointInStroke(8.70*scale, 14.21*scale) === true; + // hit-test the end of the dash (t=9.8) + @assert ctx.isPointInStroke(4.10*scale, 14.63*scale) === true; + // hit-test past the end of the dash (t=10.2) + @assert ctx.isPointInStroke(3.74*scale, 14.46*scale) === false; + + - name: 2d.drawImage.3arg testing: - 2d.drawImage.defaultsource diff --git a/tests/wpt/web-platform-tests/cookie-store/change_eventhandler_for_no_name_equals_in_value.tentative.https.window.js b/tests/wpt/web-platform-tests/cookie-store/change_eventhandler_for_no_name_equals_in_value.tentative.https.window.js index fe6a34b3d69..13d721786c9 100644 --- a/tests/wpt/web-platform-tests/cookie-store/change_eventhandler_for_no_name_equals_in_value.tentative.https.window.js +++ b/tests/wpt/web-platform-tests/cookie-store/change_eventhandler_for_no_name_equals_in_value.tentative.https.window.js @@ -6,10 +6,11 @@ cookie_test(async t => { let eventPromise = observeNextCookieChangeEvent(); await cookieStore.set('', 'first-value'); - assert_equals( - (await cookieStore.getAll('')).map(({ value }) => value).join(';'), - 'first-value', - 'Cookie with no name and normal value should have been set'); + const initialCookies = await cookieStore.getAll(''); + assert_equals(initialCookies.length, 1); + assert_equals(initialCookies[0].name, ''); + assert_equals(initialCookies[0].value, 'first-value'); + await verifyCookieChangeEvent( eventPromise, {changed: [{name: '', value: 'first-value'}]}, 'Observed no-name change'); @@ -29,10 +30,11 @@ cookie_test(async t => { 'Expected promise rejection when setting a cookie with' + ' no name and "=" in value (via options)'); - assert_equals( - (await cookieStore.getAll('')).map(({ value }) => value).join(';'), - 'first-value', - 'Cookie with no name should still have previous value'); + const cookies = await cookieStore.getAll(''); + assert_equals(cookies.length, 1); + assert_equals(cookies[0].name, ''); + assert_equals(cookies[0].value, 'first-value', + 'Cookie with no name should still have previous value.'); eventPromise = observeNextCookieChangeEvent(); await cookieStore.delete(''); diff --git a/tests/wpt/web-platform-tests/cookie-store/cookieStore_event_delete.tenative.https.window.js b/tests/wpt/web-platform-tests/cookie-store/cookieStore_event_delete.tentative.https.window.js index e8c6fc036a7..e8c6fc036a7 100644 --- a/tests/wpt/web-platform-tests/cookie-store/cookieStore_event_delete.tenative.https.window.js +++ b/tests/wpt/web-platform-tests/cookie-store/cookieStore_event_delete.tentative.https.window.js diff --git a/tests/wpt/web-platform-tests/cookie-store/cookieStore_get_arguments.tentative.https.any.js b/tests/wpt/web-platform-tests/cookie-store/cookieStore_get_arguments.tentative.https.any.js index 34f7dbcd948..b0bef77fd89 100644 --- a/tests/wpt/web-platform-tests/cookie-store/cookieStore_get_arguments.tentative.https.any.js +++ b/tests/wpt/web-platform-tests/cookie-store/cookieStore_get_arguments.tentative.https.any.js @@ -15,6 +15,21 @@ promise_test(async testCase => { }, 'cookieStore.get with no arguments'); promise_test(async testCase => { + await cookieStore.set('cookie-name-1', 'cookie-value-1'); + testCase.add_cleanup(async () => { + await cookieStore.delete('cookie-name-1'); + }); + await cookieStore.set('cookie-name-2', 'cookie-value-2'); + testCase.add_cleanup(async () => { + await cookieStore.delete('cookie-name-2'); + }); + + const cookie = await cookieStore.get(); + assert_equals(cookie.name, 'cookie-name-1'); + assert_equals(cookie.value, 'cookie-value-1'); +},'cookieStore.get with no args and multiple matches'); + +promise_test(async testCase => { await cookieStore.set('cookie-name', 'cookie-value'); testCase.add_cleanup(async () => { await cookieStore.delete('cookie-name'); @@ -44,6 +59,8 @@ promise_test(async testCase => { const cookie = await cookieStore.get('cookie-name', { name: 'wrong-cookie-name' }); + assert_equals(cookie.name, 'cookie-name'); + assert_equals(cookie.value, 'cookie-value'); }, 'cookieStore.get with name in both positional arguments and options'); promise_test(async testCase => { diff --git a/tests/wpt/web-platform-tests/cookie-store/cookieStore_set_arguments.tentative.https.any.js b/tests/wpt/web-platform-tests/cookie-store/cookieStore_set_arguments.tentative.https.any.js index b9074c827d2..6685f5fd3b7 100644 --- a/tests/wpt/web-platform-tests/cookie-store/cookieStore_set_arguments.tentative.https.any.js +++ b/tests/wpt/web-platform-tests/cookie-store/cookieStore_set_arguments.tentative.https.any.js @@ -41,6 +41,22 @@ promise_test(async testCase => { }, 'cookieStore.set with name in both positional arguments and options'); promise_test(async testCase => { + await promise_rejects_js(testCase, TypeError, + cookieStore.set('', 'suspicious-value=resembles-name-and-value')); +}, "cookieStore.set with empty name and an '=' in value"); + +promise_test(async testCase => { + await cookieStore.delete('cookie-name'); + cookieStore.set('cookie-name', 'suspicious-value=resembles-name-and-value'); + testCase.add_cleanup(async () => { + await cookieStore.delete('cookie-name'); + }); + const cookie = await cookieStore.get('cookie-name'); + assert_equals(cookie.name, 'cookie-name'); + assert_equals(cookie.value, 'suspicious-value=resembles-name-and-value'); +}, "cookieStore.set with normal name and an '=' in value"); + +promise_test(async testCase => { await cookieStore.delete('cookie-name'); cookieStore.set('cookie-name', 'cookie-value', diff --git a/tests/wpt/web-platform-tests/css/compositing/root-element-opacity-change-ref.html b/tests/wpt/web-platform-tests/css/compositing/root-element-opacity-change-ref.html new file mode 100644 index 00000000000..be3d3713694 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/compositing/root-element-opacity-change-ref.html @@ -0,0 +1,4 @@ +<!doctype HTML> +<html style="font-size: 200px"> +TEST +</html> diff --git a/tests/wpt/web-platform-tests/css/compositing/root-element-opacity-change.html b/tests/wpt/web-platform-tests/css/compositing/root-element-opacity-change.html new file mode 100644 index 00000000000..de2599de491 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/compositing/root-element-opacity-change.html @@ -0,0 +1,14 @@ +<!doctype HTML> +<html class="test-wait" style="font-size: 200px; opacity: 0.5"> +<link rel="help" href="https://drafts.fxtf.org/compositing/#pagebackdrop"> +<link rel="match" href="root-element-opacity-change-ref.html"> +<meta name="assert" content="View background should be white after opacity changes from 0.5 to 1"> +<script src="/common/rendering-utils.js"></script> +TEST +<script> +waitForAtLeastOneFrame().then(() => { + document.documentElement.style.opacity=1; + document.documentElement.classList.remove('test-wait'); +}); +</script> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-animations/animation-base-response-004.html b/tests/wpt/web-platform-tests/css/css-animations/animation-base-response-004.html new file mode 100644 index 00000000000..5638a572e90 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-animations/animation-base-response-004.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<title>Tests that base responds to font-affecting properties appearing via setKeyframes</title> +<link rel="help" href="https://drafts.csswg.org/css-animations/"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> + #target1 { + font-size: 10px; + height: 1em; + } +</style> +<div id=target1></div> +<script> + test(function() { + getComputedStyle(target1).height; + + let animation = target1.animate([ + { height: '50px' }, + { height: '100px' }, + ], { + duration: 1000000, + delay: -500000, + easing: 'steps(2, end)' + }); + + assert_equals(getComputedStyle(target1).height, '75px'); + + animation.effect.setKeyframes([ + { fontSize: '10px' }, + { fontSize: '20px' }, + ]); + + assert_equals(getComputedStyle(target1).height, '15px'); + }, 'Base is responsive to font-affecting appearing via setKeyframes'); +</script> diff --git a/tests/wpt/web-platform-tests/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-change-checkbox-notref.html b/tests/wpt/web-platform-tests/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-change-checkbox-notref.html new file mode 100644 index 00000000000..921482afcdf --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-change-checkbox-notref.html @@ -0,0 +1,2 @@ +<!doctype html> +<input type="checkbox"> diff --git a/tests/wpt/web-platform-tests/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-change-checkbox.html b/tests/wpt/web-platform-tests/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-change-checkbox.html new file mode 100644 index 00000000000..ae0dc62b7c8 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-change-checkbox.html @@ -0,0 +1,21 @@ +<!doctype html> +<html class="reftest-wait"> +<head> + <title>CSS Color Adjustment Test: Checkbox rendering should change between dark and light schemes</title> + <link rel="help" href="https://drafts.csswg.org/css-color-adjust/#color-scheme-processing"> + <link rel="mismatch" href="color-scheme-change-checkbox-notref.html"> + <link rel="stylesheet" href="support/assert-preferred-dark.css"> + <script src="/common/reftest-wait.js"></script> +</head> +<body> + <input type="checkbox"> +</body> +<script> + requestAnimationFrame(() => { + requestAnimationFrame(() => { + document.querySelector("input").style.colorScheme = "dark"; + takeScreenshot(); + }); + }); +</script> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-contain/contain-size-grid-003.html b/tests/wpt/web-platform-tests/css/css-contain/contain-size-grid-003.html index fd07602b568..44b736b1d6b 100644 --- a/tests/wpt/web-platform-tests/css/css-contain/contain-size-grid-003.html +++ b/tests/wpt/web-platform-tests/css/css-contain/contain-size-grid-003.html @@ -73,7 +73,7 @@ </div> <div class="grid" style="grid: calc(50px - 10%) / calc(100px + 20%);" - data-expected-width="100" data-expected-height="50"> + data-expected-width="0" data-expected-height="0"> </div> <div class="grid" style="grid: fit-content(50px) / fit-content(100px);" diff --git a/tests/wpt/web-platform-tests/css/css-contain/contain-size-grid-004.html b/tests/wpt/web-platform-tests/css/css-contain/contain-size-grid-004.html new file mode 100644 index 00000000000..c333c03298c --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-contain/contain-size-grid-004.html @@ -0,0 +1,210 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Containment Test: Size containment on grid containers with percentages</title> +<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size"> +<meta name="assert" content="Checks that grid containers with size containment and their grid items are sized correctly when the track sizing functions contain percentages."> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<style> +.grid { + display: grid; + contain: size; + font: 75px/1 Ahem; +} +.min-content { + height: min-content; + width: min-content; +} +.max-content { + height: max-content; + width: max-content; +} +.fixed { + height: 100px; + width: 100px; +} +.percent { + grid: 50% / 200%; +} +.calc { + grid: calc(100px + 50%) / calc(100px + 200%); +} +.minmax-percent-fixed { + grid: minmax(50%, 100px) / minmax(200%, 100px); +} +.minmax-fixed-percent { + grid: minmax(100px, 50%) / minmax(100px, 200%); +} +.minmax-percent-flex { + grid: minmax(50%, 1fr) / minmax(200%, 1fr); +} +.minmax-percent-intrinsic { + grid: minmax(50%, min-content) / minmax(200%, min-content); +} +.minmax-intrinsic-percent { + grid: minmax(min-content, 50%) / minmax(min-content, 200%); +} +.fit-content { + grid: fit-content(50%) / fit-content(200%); +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<body onload="checkLayout('.grid')"> + +<div id="log"></div> + +<div class="grid percent min-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="0" data-expected-width="0"></div> +</div> +<div class="grid percent min-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="0" data-expected-width="0">XXXX</div> +</div> +<div class="grid percent max-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="0" data-expected-width="0"></div> +</div> +<div class="grid percent max-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="0" data-expected-width="0">XXXX</div> +</div> +<div class="grid percent fixed" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="50" data-expected-width="200"></div> +</div> +<div class="grid percent fixed" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="50" data-expected-width="200">XXXX</div> +</div> + +<div class="grid calc min-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="100" data-expected-width="100"></div> +</div> +<div class="grid calc min-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="100" data-expected-width="100">XXXX</div> +</div> +<div class="grid calc max-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="100" data-expected-width="100"></div> +</div> +<div class="grid calc max-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="100" data-expected-width="100">XXXX</div> +</div> +<div class="grid calc fixed" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="150" data-expected-width="300"></div> +</div> +<div class="grid calc fixed" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="150" data-expected-width="300">XXXX</div> +</div> + +<div class="grid minmax-percent-fixed min-content" data-expected-height="100" data-expected-width="0"> + <div data-expected-height="100" data-expected-width="0"></div> +</div> +<div class="grid minmax-percent-fixed min-content" data-expected-height="100" data-expected-width="0"> + <div data-expected-height="100" data-expected-width="0">XXXX</div> +</div> +<div class="grid minmax-percent-fixed max-content" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="100" data-expected-width="200"></div> +</div> +<div class="grid minmax-percent-fixed max-content" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="100" data-expected-width="200">XXXX</div> +</div> +<div class="grid minmax-percent-fixed fixed" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="100" data-expected-width="200"></div> +</div> +<div class="grid minmax-percent-fixed fixed" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="100" data-expected-width="200">XXXX</div> +</div> + +<div class="grid minmax-fixed-percent min-content" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="100" data-expected-width="100"></div> +</div> +<div class="grid minmax-fixed-percent min-content" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="100" data-expected-width="100">XXXX</div> +</div> +<div class="grid minmax-fixed-percent max-content" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="100" data-expected-width="100"></div> +</div> +<div class="grid minmax-fixed-percent max-content" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="100" data-expected-width="100">XXXX</div> +</div> +<div class="grid minmax-fixed-percent fixed" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="100" data-expected-width="100"></div> +</div> +<div class="grid minmax-fixed-percent fixed" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="100" data-expected-width="100">XXXX</div> +</div> + +<div class="grid minmax-percent-flex min-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="0" data-expected-width="0"></div> +</div> +<div class="grid minmax-percent-flex min-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="0" data-expected-width="0">XXXX</div> +</div> +<div class="grid minmax-percent-flex max-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="0" data-expected-width="0"></div> +</div> +<div class="grid minmax-percent-flex max-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="0" data-expected-width="0">XXXX</div> +</div> +<div class="grid minmax-percent-flex fixed" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="100" data-expected-width="200"></div> +</div> +<div class="grid minmax-percent-flex fixed" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="100" data-expected-width="200">XXXX</div> +</div> + +<div class="grid minmax-intrinsic-percent min-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="0" data-expected-width="0"></div> +</div> +<div class="grid minmax-intrinsic-percent min-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="75" data-expected-width="300">XXXX</div> +</div> +<div class="grid minmax-intrinsic-percent max-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="0" data-expected-width="0"></div> +</div> +<div class="grid minmax-intrinsic-percent max-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="75" data-expected-width="300">XXXX</div> +</div> +<div class="grid minmax-intrinsic-percent fixed" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="50" data-expected-width="100"></div> +</div> +<div class="grid minmax-intrinsic-percent fixed" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="75" data-expected-width="300">XXXX</div> +</div> + +<div class="grid minmax-percent-intrinsic min-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="0" data-expected-width="0"></div> +</div> +<div class="grid minmax-percent-intrinsic min-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="0" data-expected-width="0">XXXX</div> +</div> +<div class="grid minmax-percent-intrinsic max-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="0" data-expected-width="0"></div> +</div> +<div class="grid minmax-percent-intrinsic max-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="0" data-expected-width="0">XXXX</div> +</div> +<div class="grid minmax-percent-intrinsic fixed" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="50" data-expected-width="200"></div> +</div> +<div class="grid minmax-percent-intrinsic fixed" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="75" data-expected-width="200">XXXX</div> +</div> + +<div class="grid fit-content min-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="0" data-expected-width="0"></div> +</div> +<div class="grid fit-content min-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="75" data-expected-width="300">XXXX</div> +</div> +<div class="grid fit-content max-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="0" data-expected-width="0"></div> +</div> +<div class="grid fit-content max-content" data-expected-height="0" data-expected-width="0"> + <div data-expected-height="75" data-expected-width="300">XXXX</div> +</div> +<div class="grid fit-content fixed" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="0" data-expected-width="0"></div> +</div> +<div class="grid fit-content fixed" data-expected-height="100" data-expected-width="100"> + <div data-expected-height="75" data-expected-width="300">XXXX</div> +</div> + +</body> diff --git a/tests/wpt/web-platform-tests/css/css-flexbox/flex-shrink-large-value-crash.html b/tests/wpt/web-platform-tests/css/css-flexbox/flex-shrink-large-value-crash.html new file mode 100644 index 00000000000..a48bec65581 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-flexbox/flex-shrink-large-value-crash.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<title>CSS Flexbox: large flex-shrink value</title> +<link rel="help" href="https://drafts.csswg.org/css-flexbox/#scaled-flex-shrink-factor"> +<link rel="help" href="https://crbug.com/543614"> +<meta name="assert" content="This test ensures that large flex-shrink value does crash due to the lost of precision."> +<style> +.flex { + display: inline-flex; + width: 40px; + height: 40px; +} + +.fractional { + height: 50px; + width: 50.5px; + min-width: 50.5px; +} + +.high-shrink { + flex-shrink: 130000000000000; + height: 40px; + width: 40px; + min-width: 40px; +} +</style> + +<div class="flex"> + <div class="fractional"></div> + <div class="high-shrink"></div> +</div> + +<p>The high flex shrink factor can lead to loss of precision as we calculate the +<a href="https://drafts.csswg.org/css-flexbox/#scaled-flex-shrink-factor">sum of +scaled flex shrink factors</a> as required by the spec, and as we later subtract +the scaled flex factors for frozen violations, we can get to a negative value +due to that lost precision.</p> diff --git a/tests/wpt/web-platform-tests/css/css-flexbox/inline-flex-editing-crash.html b/tests/wpt/web-platform-tests/css/css-flexbox/inline-flex-editing-crash.html new file mode 100644 index 00000000000..01917e3726c --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-flexbox/inline-flex-editing-crash.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>CSS Flexbox: inline-flex layout with editing operations</title> +<link rel="help" href="https://drafts.csswg.org/css-flexbox/#flex-containers"> +<link rel="help" href="https://bugs.webkit.org/show_bug.cgi?id=77772"> +<link rel="help" href="https://crbug.com/118662"> +<meta name="assert" content="This test ensures that inline-flex layout does not crash with editing operations."> +<style>#el0::first-letter, #el0:first-child { height: 100px; }</style> +<div id='container' contentEditable> + <a> + <img> + <div id="el0" style="display: inline-flex"> + <pre>AAAAA</pre> + </div> + </a> +</div> +<script> +window.getSelection().selectAllChildren(document.getElementById('container')); +document.execCommand('FormatBlock', false, '<h5>'); +</script> diff --git a/tests/wpt/web-platform-tests/css/css-flexbox/inline-flex-editing-with-updating-text-crash.html b/tests/wpt/web-platform-tests/css/css-flexbox/inline-flex-editing-with-updating-text-crash.html new file mode 100644 index 00000000000..bdf7df85d7b --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-flexbox/inline-flex-editing-with-updating-text-crash.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<title>CSS Flexbox: inline-flex layout with updating text and editing operations</title> +<link rel="help" href="https://drafts.csswg.org/css-flexbox/#flex-containers"> +<link rel="help" href="https://bugs.webkit.org/show_bug.cgi?id=77772"> +<link rel="help" href="https://crbug.com/118662"> +<meta name="assert" content="This test ensures that inline-flex layout does not crash with updating text and editing operations."> +<style>#el0::first-letter, #el0:first-child { height: 10px; }</style> +<div id='container' contentEditable> + <a> + <img> + <div id="el0" style="display: inline-flex"> + <pre></pre> + </div> + </a> +</div> +<script> +document.querySelector('pre').textContent = 'AA\u0605'; +window.getSelection().selectAllChildren(document.getElementById('container')); +document.execCommand('FormatBlock', false, '<h1>'); +</script> diff --git a/tests/wpt/web-platform-tests/css/css-flexbox/inline-flex-frameset-main-axis-crash.html b/tests/wpt/web-platform-tests/css/css-flexbox/inline-flex-frameset-main-axis-crash.html new file mode 100644 index 00000000000..434897cc7ac --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-flexbox/inline-flex-frameset-main-axis-crash.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<html style="display: inline-flex;"> +<title>CSS Flexbox: the main axis calculation with frameset</title> +<link rel="help" href="https://drafts.csswg.org/css-flexbox/#main-axis"> +<link rel="help" href="https://crbug.com/335121"> +<meta name="assert" content="This test ensures that frameset does not crash on computing the main axis."> +<frameset></frameset> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-baseline-001.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-baseline-001.html new file mode 100644 index 00000000000..ef8c0e4d340 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-baseline-001.html @@ -0,0 +1,218 @@ +<!DOCTYPE html> +<html> +<title>CSS Grid: Grid container baseline</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid/#grid-baselines"> +<link rel="help" href="https://crbug.com/234191"> +<link rel="match" href="references/grid-baseline-001-ref.html"> +<meta name="assert" content="Check the first baselines of a grid container."/> + +<style> +body { + margin: 0; +} +.inline-grid { + display: inline-grid; + background-color: lightgrey; + margin-top: 5px; + grid-auto-flow: column; +} +.grid { + display: grid; + background-color: grey; + margin-top: 10px; + grid-auto-flow: column; +} +.empty { + border-style: solid; + border-width: 5px 0px 10px; + padding: 2px 0px 4px; + margin: 10px 0px 20px; +} +.column { + grid-auto-flow: row; +} +.firstRowFirstColumn { + grid-column: 1; + grid-row: 1; +} +.secondRowFirstColumn { + grid-column: 1; + grid-row: 2; +} +</style> + +<body style="position: relative"> + +<!-- If any of the grid items whose areas intersect the grid container's first +row/column participate in baseline alignment, the grid container's baseline is +the baseline of those grid items. --> +<div> +before text +<div class="inline-grid" style="grid-auto-rows: 50px;"> + <div style="align-self: end">below</div> + <div style="align-self: baseline; margin-top: 15px">baseline</div> + <div style="align-self: start">above</div> +</div> +after text +</div> + +<!-- This grid has a baseline item, it's orthogonal but it still participates +in baseline alignment. --> +<div> +before text +<div class="inline-grid" style="grid-auto-rows: 40px"> + <div style="align-self: end">below</div> + <div style="align-self: baseline; margin-top: 20px; writing-mode: vertical-rl"></div> + <div style="align-self: start">above</div> +</div> +after text +</div> + +<div> +before text +<div class="inline-grid"> + <h2>h2 baseline</h2> + <div>above</div> +</div> +after text +</div> + +<div> +before text +<div class="inline-grid"> + <div>baseline</div> + <h2>h2 below</h2> +</div> +after text +</div> + +<!-- If the first grid item has an orthogonal baseline, use the synthesized +baseline (bottom of the content box of the first item). --> +<div> +should align with the middle +<div class="inline-grid" style="width: 40px; height: 40px"> + <div style="writing-mode: vertical-rl; height: 20px; width: 40px; border-bottom: 1px solid black"></div> +</div> +of the grey box +</div> + +<!-- If there are no griditems, align to the bottom of the margin box. --> +<div> +should align below the bottom +<div class="empty inline-grid" style="width: 30px; height: 30px"> +</div> +of the black line +</div> + +<div> +should align with the bottom +<div class="inline-grid" style="width: 40px; height: 40px;"> + <div style="width: 20px; height: 20px; border: 5px solid black; background: red;"></div> +</div> +of the red box +</div> + +<!-- column-axis test cases. --> +<div> +before text +<div class="inline-grid column"> + <div>baseline</div> + <div>below</div> +</div> +after text +</div> + +<!-- If the first grid item has an orthogonal baseline, use the synthesized +baseline (bottom of the border box of the first item). --> +<div> +should align with the middle +<div class="inline-grid column" style="width: 40px; height: 40px;"> + <div style="writing-mode: vertical-rl; width: 40px; height: 20px; border-bottom: 1px solid black"></div> + <div style="writing-mode: vertical-rl; width: 40px; height: 19px"></div> +</div> +of the grey box +</div> + +<!-- More tests on the right side of the page. --> +<div style="position: absolute; top: 0; left: 400px; width: 360px"> + +<!-- Ignore absolutely positioned grid items. --> +<div> +before text +<div class="inline-grid"> + <div style="position: absolute">absolute</div> + <div style="margin-top: 30px">baseline</div> +</div> +after text +</div> + +<!-- We don't participate in baseline alignment if there's an auto margin. --> +<div> +before text +<div class="inline-grid" style="grid-auto-rows: 40px;"> + <div>baseline</div> + <div style="align-self: baseline; margin-top: auto">below</div> +</div> +after text +</div> + +<div> +before text +<div style="display: inline-block"> +<div class="inline-grid" style="height: 40px;"> + <div>above</div> + <div style="align-self: baseline; margin-top: 10px">baseline</div> + <div>above</div> +</div> +after +</div> +text +</div> + +<!-- The spec is a little unclear what should happen here. For now, +align to the last line box. --> +<div> + before text + <div style="display: inline-block"> + <div class="grid" style="height: 30px;"> + baseline + </div> + </div> + after text +</div> + +<table style="background-color: lightgrey; margin-top: 5px"> +<tr style="height: 50px"> + <td style="vertical-align: bottom">bottom</td> + <td style="vertical-align: baseline">baseline</td> + <td style="vertical-align: top">top</td> + <td style="vertical-align: baseline"><div class="grid"> + <h2>h2 baseline</h2> + <div>above</div> + </div></td> +</table> + +<!-- If a box contributing a baseline has a scrollbar, the box must be treated +as being in its initial scroll position when computing the baseline. --> +<div> +before text +<div id="grid-with-scrollbar" class="inline-grid" style="height: 65px; width: 150px"> + <div id="griditem-with-scrollbar" style="align-self: baseline; padding-top: 15px; height: 50px; overflow-y: scroll;"> + The baseline is based on<br> + the non-scrolled position;<br> + this won't line up. + </div> +</div> +after text +</div> + +</div> + +<script> +document.getElementById("griditem-with-scrollbar").scrollTop = 999; +document.getElementById("grid-with-scrollbar").style.width = "auto"; +</script> + +</body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-baseline-002.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-baseline-002.html new file mode 100644 index 00000000000..b52eeff27e5 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-baseline-002.html @@ -0,0 +1,68 @@ +<!DOCTYPE html> +<title>CSS Grid: Grid container baseline</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid/#grid-baselines"> +<link rel="help" href="https://crbug.com/234191"> +<link rel="match" href="references/grid-baseline-002-ref.html"> +<meta name="assert" content="Check that Baseline Alignment works for 1-dimensional Grid like in Flexible Box, even using margins, paddings and borders."/> + +<link href="/css/support/grid.css" rel="stylesheet"> +<style> +.inline-block { display: inline-block; } +.grid, .inline-grid { + background-color: lightgrey; + grid-auto-flow: column; +} +.border { border: 11px solid pink; } +.padding { padding: 13px; } +.margin { margin: 8px 0; } +</style> +<div> +before text +<div class="border" style="display: inline-block; background-color: lightgrey"> +<div class="grid" style="height: 30px; margin-top: 7px; padding-top: 10px;"> + baseline +</div> +</div> +after text +</div> + +<div> +Should align +<div class="inline-block border"> + <div class="grid padding" style="grid-template-columns: 50px; grid-template-rows: 50px; background-color: pink"> + <div style="background-color: lightgrey"></div> + </div> +</div> +with the +<div class="inline-block margin"> + <div class="grid border" style="grid-template-columns: 50px; grid-template-rows: 50px; background-color: pink"> + <div style="background-color: lightgrey"></div> + </div> +</div> +bottom of +<div class="inline-block padding" style="padding-left: 0; padding-right: 0"> + <div class="grid margin border" style="grid-template-columns: 50px; grid-template-rows: 50px; background-color: pink"> + <div style="background-color: lightgrey;"></div> + </div> +</div> +the grey box. +</div> + +<div> +Should align with the +<div class="inline-block"> + <div class="grid" style="background-color: white"> + <div class="border padding margin" style="background-color: lightgrey;"></div> + </div> +</div> +bottom of the pink box. +</div> + +<div> +Should align 8px +<div class="inline-grid margin border" style="grid-template-columns: 30px; grid-template-rows: 30px;"></div> +below the bottom +<div class="inline-grid margin border padding"></div> +of the pink box. +</div> diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-baseline-003.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-baseline-003.html new file mode 100644 index 00000000000..bd411abed91 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-baseline-003.html @@ -0,0 +1,40 @@ +<!DOCTYPE html> +<title>CSS Grid: Grid container baseline</title> +<link rel="author" title="Manuel Rego" href="mailto:rego@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid/#grid-baselines"> +<link rel="help" href="https://drafts.csswg.org/css-align-3/#synthesize-baseline"> +<link rel="help" href="https://crbug.com/234191"> +<link rel="match" href="references/grid-baseline-003-ref.html"> +<meta name="assert" content="Check that grid container baseline should be synthesized from the border edges when it has no baseline."/> + +<link href="/css/support/grid.css" rel="stylesheet"> +<style> +.inline-block { display: inline-block; } +.grid, .inline-grid { + background-color: lightgrey; + grid-auto-flow: column; +} +.border { border: 11px solid pink; } +.padding { padding: 13px; } +.margin { margin: 8px 0; } +</style> + +<div> +Should align with the bottom +<div class="inline-block border margin padding" style="background-color: pink"> + <div class="grid border margin padding" style="grid-template-columns: 100px; grid-template-rows: 100px; background-color: pink"> + <div style="overflow: scroll; background-color: lightgrey; margin: 10px 0px; border-top: 10px solid pink;"></div> + </div> +</div> +of the horizontal scrollbar. +</div> + +<div> +Should align 10px below the +<div class="inline-block" style="background-color: pink"> + <div class="grid" style="grid-template-columns: 100px; grid-template-rows: 100px; background-color: pink"> + <div style="overflow: scroll; padding-bottom: 10px; background-color: lightgrey; margin: 10px 0px; border-top: 10px solid pink; border-bottom: 10px solid pink;"></div> + </div> +</div> +horizontal scrollbar, if one is visible. +</div> diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-baseline-004.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-baseline-004.html new file mode 100644 index 00000000000..baabc70a3f4 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-baseline-004.html @@ -0,0 +1,204 @@ +<!DOCTYPE html> +<title>CSS Grid: Grid container baseline</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid/#grid-baselines"> +<link rel="help" href="https://drafts.csswg.org/css-grid/#grid-order"> +<link rel="help" href="https://crbug.com/234191"> +<meta name="assert" content="Check that grid container must use its first item in grid-modified document order (grid order) to compute its baseline."/> + +<link href="/css/support/grid.css" rel="stylesheet"> +<link href="/css/support/alignment.css" rel="stylesheet"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<style> +body { margin: 0; } +.container { + position: relative; + font: 10px/1 Ahem; + border: 5px solid; + width: 470px; +} +.grid { + display: inline-grid; + grid-template-columns: 50px 50px; + width: 150px; + background-color: transparent; + position: relative; +} +.twoRows { grid-template-rows: 50px 50px; } +.threeRows { grid-template-rows: 50px 50px 50px; } +.empty { + border-color: black; + border-style: solid; + margin: 15px 0px 30px; + border-width: 5px 0px 10px; + padding: 10px 0px 20px; +} +.item { + height: 25px; + border-color: black; + border-style: solid; +} +.style1 { + border-width: 5px 0px 10px; + padding: 10px 0px 20px; +} +.style2 { + border-width: 10px 0px 5px; + padding: 20px 0px 10px; + margin-top: 10px; +} +.style3 { + border-width: 10px 0px 20px; + padding: 5px 0px 10px; + margin-top: 20px; +} + +.bothRowFirstColumn, .secondRowSecondColumn { + margin-right: 10px; + margin-top: 10px; + margin-bottom: 10px; + background-color: pink; +} +.firstRowBothColumn, .secondRowBothColumn { + margin-top: 15px; + margin-bottom: 15px; + background-color: green; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<script type="text/javascript"> + setup({ explicit_done: true }); +</script> +<body onload="document.fonts.ready.then(() => { checkLayout('.grid, container'); })"> +<div id="log"></div> +<p> + The test shows 3 grids each of them with 3 items sorted differently in the DOM.<br> + Each grid container must use its first (grid order) item to compute its baseline, and using document-oder in case of element with same grid-order. Hence they might be baseline aligned each other accordingly. +</p> + +<p> + This case shows 3 items located along the first row and in different columns, so grid baseline is computed using the one located at first column (blue item). +</p> +<div class="container" data-expected-width="480" data-expected-height="120"> + <div class="grid" data-offset-x="0" data-offset-y="20"> + <div class="item style1 firstRowFirstColumn" data-offset-x="0" data-offset-y="0"></div> + <div class="item style2 firstRowSecondColumn" data-offset-x="50" data-offset-y="10"></div> + <div class="item style3 firstRowThirdColumn" data-offset-x="100" data-offset-y="20"></div> + </div> + <div class="grid" data-offset-x="160" data-offset-y="10"> + <div class="item style1 firstRowThirdColumn" data-offset-x="100" data-offset-y="0"></div> + <div class="item style2 firstRowFirstColumn" data-offset-x="0" data-offset-y="10"></div> + <div class="item style3 firstRowSecondColumn" data-offset-x="50" data-offset-y="20"></div> + </div> + <div class="grid" data-offset-x="320" data-offset-y="0"> + <div class="item style1 firstRowSecondColumn" data-offset-x="50" data-offset-y="0"></div> + <div class="item style2 firstRowThirdColumn" data-offset-x="100" data-offset-y="10"></div> + <div class="item style3 firstRowFirstColumn" data-offset-x="0" data-offset-y="20"></div> + </div> +</div> + +<p> + This case shows 3 items located along the first row and in different columns, so such item is used to determine the grid's baseline instead of using the grid order. +</p> +<div class="container" data-expected-width="480" data-expected-height="120"> + <div class="grid" data-offset-x="0" data-offset-y="0"> + <div class="item style1 firstRowFirstColumn" data-offset-x="0" data-offset-y="0"></div> + <div class="item style2 firstRowSecondColumn" data-offset-x="50" data-offset-y="10"></div> + <div class="item style3 firstRowThirdColumn alignSelfBaseline" data-offset-x="100" data-offset-y="20"></div> + </div> + <div class="grid" data-offset-x="160" data-offset-y="0"> + <div class="item style1 firstRowThirdColumn" data-offset-x="100" data-offset-y="0"></div> + <div class="item style2 firstRowFirstColumn" data-offset-x="0" data-offset-y="10"></div> + <div class="item style3 firstRowSecondColumn alignSelfBaseline" data-offset-x="50" data-offset-y="20"></div> + </div> + <div class="grid" data-offset-x="320" data-offset-y="20"> + <div class="item style1 firstRowSecondColumn alignSelfBaseline" data-offset-x="50" data-offset-y="0"></div> + <div class="item style2 firstRowThirdColumn" data-offset-x="100" data-offset-y="10"></div> + <div class="item style3 firstRowFirstColumn" data-offset-x="0" data-offset-y="20"></div> + </div> +</div> + +<p> + This case shows 3 items' areas intersecting the first row and first column, so the dom order must be used to determine each grid's baseline. +</p> +<div class="container" data-expected-width="480" data-expected-height="165"> + <div class="grid twoRows" data-offset-x="0" data-offset-y="40"> + <div class="firstRowFirstColumn" data-offset-x="0" data-offset-y="0"></div> + <div class="firstRowBothColumn" data-offset-x="0" data-offset-y="15"></div> + <div class="bothRowFirstColumn" data-offset-x="0" data-offset-y="10"></div> + </div> + <div class="grid twoRows" data-offset-x="160" data-offset-y="0"> + <div class="bothRowFirstColumn" data-offset-x="0" data-offset-y="10"></div> + <div class="firstRowFirstColumn" data-offset-x="0" data-offset-y="0"></div> + <div class="firstRowBothColumn" data-offset-x="0" data-offset-y="15"></div> + </div> + <div class="grid twoRows" data-offset-x="320" data-offset-y="55"> + <div class="firstRowBothColumn" data-offset-x="0" data-offset-y="15"></div> + <div class="firstRowFirstColumn" data-offset-x="0" data-offset-y="0"></div> + <div class="bothRowFirstColumn" data-offset-x="0" data-offset-y="10"></div> + </div> +</div> + +<p> + This case shows 3 items' areas intersecting the first row and first column, but one of the items participates in baseline alignment, so such item is used to determine the grid's baseline instead of using the dom order. +</p> +<div class="container" data-expected-width="480" data-expected-height="165"> + <div class="grid twoRows" data-offset-x="0" data-offset-y="55"> + <div class="firstRowFirstColumn" data-offset-x="0" data-offset-y="0"></div> + <div class="firstRowBothColumn alignSelfBaseline" style="width: 100px; height: 20px;" data-offset-x="0" data-offset-y="15"></div> + <div class="bothRowFirstColumn" data-offset-x="0" data-offset-y="10"></div> + </div> + <div class="grid twoRows" data-offset-x="160" data-offset-y="40"> + <div class="bothRowFirstColumn" data-offset-x="0" data-offset-y="10"></div> + <div class="firstRowFirstColumn alignSelfBaseline" style="width: 50px; height: 50px;" data-offset-x="0" data-offset-y="0"></div> + <div class="firstRowBothColumn" data-offset-x="0" data-offset-y="15"></div> + </div> + <div class="grid twoRows" data-offset-x="320" data-offset-y="0"> + <div class="firstRowBothColumn" data-offset-x="0" data-offset-y="15"></div> + <div class="firstRowFirstColumn" data-offset-x="0" data-offset-y="0"></div> + <div class="bothRowFirstColumn alignSelfBaseline" style="width: 40px; height: 80px;" data-offset-x="0" data-offset-y="10"></div> + </div> +</div> + +<p> + This case shows one of the grids with no items, hence its baseline must be synthesized. +</p> +<div class="container" data-expected-width="480" data-expected-height="250"> + <div class="grid twoRows" data-offset-x="0" data-offset-y="140"> + <div class="firstRowFirstColumn" data-offset-x="0" data-offset-y="0"></div> + <div class="firstRowBothColumn" data-offset-x="0" data-offset-y="15"></div> + <div class="bothRowFirstColumn" data-offset-x="0" data-offset-y="10"></div> + </div> + <div class="grid twoRows" data-offset-x="160" data-offset-y="100"> + <div class="bothRowFirstColumn" data-offset-x="0" data-offset-y="10"></div> + <div class="firstRowFirstColumn" data-offset-x="0" data-offset-y="0"></div> + <div class="firstRowBothColumn" data-offset-x="0" data-offset-y="15"></div> + </div> + <div class="grid empty twoRows" data-offset-x="320" data-offset-y="15"> + </div> +</div> + +<p> + This case shows one of the grids with no items in the first row, hence its baseline must be synthesized. +</p> +<div class="container" data-expected-width="480" data-expected-height="300"> + <div class="grid twoRows" data-offset-x="0" data-offset-y="190"> + <div class="firstRowFirstColumn" data-offset-x="0" data-offset-y="0"></div> + <div class="firstRowBothColumn" data-offset-x="0" data-offset-y="15"></div> + <div class="bothRowFirstColumn" data-offset-x="0" data-offset-y="10"></div> + </div> + <div class="grid twoRows" data-offset-x="160" data-offset-y="150"> + <div class="bothRowFirstColumn" data-offset-x="0" data-offset-y="10"></div> + <div class="firstRowFirstColumn" data-offset-x="0" data-offset-y="0"></div> + <div class="firstRowBothColumn" data-offset-x="0" data-offset-y="15"></div> + </div> + <div class="grid empty threeRows" data-offset-x="320" data-offset-y="15"> + <div class="secondRowFirstColumn" data-offset-x="0" data-offset-y="60"></div> + <div class="thirdRowSecondColumn" data-offset-x="50" data-offset-y="110"></div> + <div class="secondRowBothColumn" data-offset-x="0" data-offset-y="75"></div> + </div> +</div> + +</body> diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/references/grid-baseline-001-ref.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/references/grid-baseline-001-ref.html new file mode 100644 index 00000000000..6a02ae4796a --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/references/grid-baseline-001-ref.html @@ -0,0 +1,205 @@ +<!DOCTYPE html> +<html> +<style> +body { + margin: 0; +} +.inline-flexbox { + display: inline-flex; + background-color: lightgrey; + margin-top: 5px; +} +.flexbox { + display: flex; + background-color: grey; + margin-top: 10px; +} +.empty { + border-style: solid; + border-width: 5px 0px 10px; + padding: 2px 0px 4px; + margin: 10px 0px 20px; +} +.column { + flex-flow: column; +} +.column-reverse { + flex-flow: column-reverse; +} +</style> + +<body style="position: relative"> + +<!-- If any of the flex items on the flex container's first line participate +in baseline alignment, the flex container's main-axis baseline is the baseline +of those flex items. --> +<div> +before text +<div class="inline-flexbox" style="height: 50px;"> + <div style="align-self: flex-end">below</div> + <div style="align-self: baseline; margin-top: 15px">baseline</div> + <div style="align-self: flex-start">above</div> +</div> +after text +</div> + +<!-- This grid has a baseline item, it's orthogonal but it still participates +in baseline alignment. --> +<div> +before text +<div class="inline-flexbox" style="height: 40px"> + <div style="align-self: flex-end">below</div> + <div style="align-self: baseline; margin-top: 20px"></div> + <div style="align-self: flex-start">above</div> +</div> +after text +</div> + +<div> +before text +<div class="inline-flexbox"> + <h2>h2 baseline</h2> + <div>above</div> +</div> +after text +</div> + +<div> +before text +<div class="inline-flexbox"> + <div>baseline</div> + <h2>h2 below</h2> +</div> +after text +</div> + +<!-- If the first flex item has an orthogonal baseline, use the synthesized +baseline (bottom of the content box of the first item). --> +<div> +should align with the middle +<div class="inline-flexbox" style="width: 40px; height: 40px"> + <div style="writing-mode: vertical-rl; height: 20px; width: 40px; border-bottom: 1px solid black"></div> +</div> +of the grey box +</div> + +<!-- If there are no flexitems, align to the bottom of the margin box. --> +<div> +should align below the bottom +<div class="empty inline-flexbox" style="width: 30px; height: 30px"> +</div> +of the black line +</div> + +<!-- If the griditem has not a natural baseline, align to the bottom of the box. --> +<div> +should align with the bottom +<div class="inline-flexbox" style="width: 40px; height: 40px;"> + <div style="width: 20px; height: 20px; border: 5px solid; background: red; "></div> +</div> +of the red box +</div> + +<!-- cross-axis (column) test cases. --> +<div> +before text +<div class="inline-flexbox column"> + <div>baseline</div> + <div>below</div> +</div> +after text +</div> + +<!-- If the first flex item has an orthogonal baseline, use the synthesized +baseline (bottom of the content box of the first item). --> +<div> +should align with the middle +<div class="inline-flexbox column" style="width: 40px; height: 40px;"> + <div style="writing-mode: vertical-rl; width: 40px; height: 20px; border-bottom: 1px solid black"></div> + <div style="writing-mode: vertical-rl; width: 40px; height: 19px"></div> +</div> +of the grey box +</div> + +<!-- More tests on the right side of the page. --> +<div style="position: absolute; top: 0; left: 400px; width: 360px"> + +<!-- Ignore absolutely positioned flex items. --> +<div> +before text +<div class="inline-flexbox"> + <div style="position: absolute">absolute</div> + <div style="margin-top: 30px">baseline</div> +</div> +after text +</div> + +<!-- We don't participate in baseline alignment if there's an auto margin. --> +<div> +before text +<div class="inline-flexbox" style="height: 40px;"> + <div>baseline</div> + <div style="align-self: baseline; margin-top: auto">below</div> +</div> +after text +</div> + +<div> +before text +<div style="display: inline-block"> +<div class="inline-flexbox" style="height: 40px;"> + <div>above</div> + <div style="align-self: baseline; margin-top: 10px">baseline</div> + <div>above</div> +</div> +after +</div> +text +</div> + +<!-- The spec is a little unclear what should happen here. For now, align to +the last line box. --> +<div> +before text +<div style="display: inline-block"> +<div class="flexbox" style="height: 30px;"> + baseline +</div> +</div> +after text +</div> + +<table style="background-color: lightgrey; margin-top: 5px"> +<tr style="height: 50px"> + <td style="vertical-align: bottom">bottom</td> + <td style="vertical-align: baseline">baseline</td> + <td style="vertical-align: top">top</td> + <td style="vertical-align: baseline"><div class="flexbox"> + <h2>h2 baseline</h2> + <div>above</div> + </div></td> +</table> + +<!-- If a box contributing a baseline has a scrollbar, the box must be treated +as being in its initial scroll position when computing the baseline. --> +<div> +before text +<div id="flexbox-with-scrollbar" class="inline-flexbox" style="height: 65px; width: 150px"> + <div id="flexitem-with-scrollbar" style="align-self: baseline; padding-top: 15px; height: 50px; overflow-y: scroll;"> + The baseline is based on<br> + the non-scrolled position;<br> + this won't line up. + </div> +</div> +after text +</div> + +</div> + +<script> +document.getElementById("flexitem-with-scrollbar").scrollTop = 999; +document.getElementById("flexbox-with-scrollbar").style.width = "auto"; +</script> + +</body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/references/grid-baseline-002-ref.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/references/grid-baseline-002-ref.html new file mode 100644 index 00000000000..43634e58c38 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/references/grid-baseline-002-ref.html @@ -0,0 +1,70 @@ +<!DOCTYPE html> +<style> +.flexbox { + display: flex; +} +.inline-flexbox { + display: inline-flex; +} +.flex-one { + flex: 1; +} +.inline-block { display: inline-block; } +.flexbox, .inline-flexbox { background-color: lightgrey; } +.border { border: 11px solid pink; } +.padding { padding: 13px; } +.margin { margin: 8px 0; } +.flexbox > div { + min-width: 0; + min-height: 0; +} +</style> +<div> +before text +<div class="border" style="display: inline-block; background-color: lightgrey"> +<div class="flexbox" style="height: 30px; margin-top: 7px; padding-top: 10px;"> + baseline +</div> +</div> +after text +</div> + +<div> +Should align +<div class="inline-block border"> + <div class="flexbox padding" style="width: 50px; height: 50px; background-color: pink"> + <div class="flex-one" style="background-color: lightgrey"></div> + </div> +</div> +with the +<div class="inline-block margin"> + <div class="flexbox border" style="width: 50px; height: 50px; background-color: pink"> + <div class="flex-one" style="background-color: lightgrey"></div> + </div> +</div> +bottom of +<div class="inline-block padding" style="padding-left: 0; padding-right: 0"> + <div class="flexbox margin border" style="width: 50px; height: 50px; background-color: pink"> + <div class="flex-one" style="background-color: lightgrey;"></div> + </div> +</div> +the grey box. +</div> + +<div> +Should align with the +<div class="inline-block"> + <div class="flexbox" style="background-color: white"> + <div class="flex-one border padding margin" style="background-color: lightgrey;"></div> + </div> +</div> +bottom of the pink box. +</div> + +<div> +Should align 8px +<div class="inline-flexbox margin border" style="width: 30px; height: 30px;"></div> +below the bottom +<div class="inline-flexbox margin border padding"></div> +of the pink box. +</div> diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/references/grid-baseline-003-ref.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/references/grid-baseline-003-ref.html new file mode 100644 index 00000000000..446c42f1a29 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/references/grid-baseline-003-ref.html @@ -0,0 +1,41 @@ +<!DOCTYPE html> +<style> +.flexbox { + display: flex; +} +.inline-flexbox { + display: inline-flex; +} +.flex-one { + flex: 1; +} +.inline-block { display: inline-block; } +.flexbox, .inline-flexbox { background-color: lightgrey; } +.border { border: 11px solid pink; } +.padding { padding: 13px; } +.margin { margin: 8px 0; } +.flexbox > div { + min-width: 0; + min-height: 0; +} +</style> + +<div> +Should align with the bottom +<div class="inline-block border margin padding" style="background-color: pink"> + <div class="flexbox border margin padding" style="width: 100px; height: 100px; background-color: pink"> + <div style="width: 200px; overflow: scroll; background-color: lightgrey; margin: 10px 0px; border-top: 10px solid pink;"></div> + </div> +</div> +of the horizontal scrollbar. +</div> + +<div> +Should align 10px below the +<div class="inline-block" style="background-color: pink"> + <div class="flexbox" style="width: 100px; height: 100px; background-color: pink"> + <div style="width: 200px; overflow: scroll; background-color: lightgrey; padding-bottom: 10px; margin: 10px 0px; border-top: 10px solid pink; border-bottom: 10px solid pink;"></div> + </div> +</div> +horizontal scrollbar, if one is visible. +</div> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-content-distribution-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-content-distribution-001.html new file mode 100644 index 00000000000..62fb46deebc --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-content-distribution-001.html @@ -0,0 +1,87 @@ +<!DOCTYPE html> +<title>CSS Grid Layout Test: free space computation with flex lengths.</title> +<link rel="author" title="Sergio Villar Senin" href="mailto:svillar@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#algo-flex-tracks"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#fr-unit"> +<link rel="help" href="https://bugs.webkit.org/show_bug.cgi?id=150359"> +<link rel="stylesheet" href="/css/support/grid.css"> +<link rel="stylesheet" href="/css/support/alignment.css"> +<meta name="assert" content="Test that free space is properly computed after computing fr tracks so that we could use it for content distribution." /> + +<style> +.freeSpaceForColumnsGrid { + grid-template: 100% / minmax(20px, 0.7fr); + width: 50px; + height: 100px; +} + +.freeSpaceForRowsGrid { + grid-template: minmax(20px, 0.7fr) / 100%; + width: 50px; + height: 100px; +} + +.container { position: relative; } + +.item { + width: 100%; + height: 50px; + background-color: red; +} + +.item2 { + width: 50px; + height: 100%; + background-color: red; +} + +</style> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> + +<body onload="checkLayout('.grid');"> + +<p>Grid with justify-content: start.</p> +<div class="container"> + <div class="grid freeSpaceForColumnsGrid justifyContentStart"> + <div class="item" data-offset-x="0" data-offset-y="0" data-expected-width="35" data-expected-height="50"></div> + </div> +</div> + +<p>Grid with justify-content: center.</p> +<div class="container"> + <div class="grid freeSpaceForColumnsGrid justifyContentCenter"> + <div class="item" data-offset-x="8" data-offset-y="0" data-expected-width="35" data-expected-height="50"></div> + </div> +</div> + +<p>Grid with justify-content: end.</p> +<div class="container"> + <div class="grid freeSpaceForColumnsGrid justifyContentEnd"> + <div class="item" data-offset-x="15" data-offset-y="0" data-expected-width="35" data-expected-height="50"></div> + </div> +</div> + +<p>Grid with align-content: start.</p> +<div class="container"> + <div class="grid freeSpaceForRowsGrid alignContentStart"> + <div class="item2" data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="70"></div> + </div> +</div> + +<p>Grid with align-content: center.</p> +<div class="container"> + <div class="grid freeSpaceForRowsGrid alignContentCenter"> + <div class="item2" data-offset-x="0" data-offset-y="15" data-expected-width="50" data-expected-height="70"></div> + </div> +</div> + +<p>Grid with align-content: end.</p> +<div class="container"> + <div class="grid freeSpaceForRowsGrid alignContentEnd"> + <div class="item2" data-offset-x="0" data-offset-y="30" data-expected-width="50" data-expected-height="70"></div> + </div> +</div> +</body> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-content-resolution-columns-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-content-resolution-columns-001.html new file mode 100644 index 00000000000..ce70aa31de5 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-content-resolution-columns-001.html @@ -0,0 +1,182 @@ +<!DOCTYPE html> +<html> +<title>CSS Grid Layout Test: Auto repeat tracks, grid-template-columns and flexible lengths.</title> +<link rel="author" title="Julien Chaffraix" href="mailto:jchaffraix@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#track-sizes"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#fr-unit"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=235258"> +<link rel="stylesheet" href="/fonts/ahem.css"> +<link rel="stylesheet" href="/css/support/grid.css"> +<meta name="assert" content="Test that resolving auto tracks on grid items using <flex> values with grid-template-columns works properly." /> + +<style> +.gridFlexContent { + grid-template-columns: 1fr 1fr; + grid-template-rows: 50px; +} +.gridMaxFlexContent { + grid-template-columns: minmax(30px, 2fr); + grid-template-rows: 50px; +} +.gridTwoMaxFlexContent { + grid-template-columns: minmax(10px, 1fr) minmax(10px, 2fr); + grid-template-rows: 50px; +} +.gridTwoDoubleMaxFlexContent { + grid-template-columns: minmax(10px, 0.5fr) minmax(10px, 2fr); + grid-template-rows: 50px; +} +.gridIgnoreSecondGridItem { + grid-template-columns: minmax(300px, 3fr) minmax(150px, 1fr); + grid-template-rows: 50px; +} +.gridRespectBaseSize { + grid-template-columns: minmax(75px, 1fr) minmax(0px, 2fr); + grid-template-rows: 50px; +} +.gridRespectProportions { + grid-template-columns: minmax(0px, .25fr) minmax(0px, .5fr) minmax(0px, 2fr); + grid-template-rows: 50px; +} +.gridRespectBaseSizeProportions { + grid-template-columns: minmax(50px, .25fr) minmax(0px, .5fr) minmax(0px, 1fr); + grid-template-rows: 50px; +} +.gridRespectBaseSizeBeforeProportions { + grid-template-columns: minmax(50px, .25fr) minmax(0px, .5fr) minmax(0px, 1fr); + grid-template-rows: 50px; +} +.firstRowThirdColumn { + background-color: yellow; + grid-column: 3; + grid-row: 1; +} +</style> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<script type="text/javascript"> + setup({ explicit_done: true }); +</script> + +<body onload="document.fonts.ready.then(() => { checkLayout('.grid'); })"> + +<div class="constrainedContainer" style="position: relative"> + <div class="grid gridFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-offset-x="0" data-offset-y="0" data-expected-width="30" data-expected-height="50">XXX</div> + <div class="sizedToGridArea firstRowSecondColumn" data-offset-x="30" data-offset-y="0" data-expected-width="50" data-expected-height="50">XXXXX</div> + </div> +</div> + +<div class="constrainedContainer"> + <div class="grid gridMaxFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="30" data-expected-height="50"></div> + </div> +</div> + +<!-- Allow the extra logical space distribution to occur. --> +<div style="width: 40px; height: 10px"> + <div class="grid gridMaxFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="40" data-expected-height="50"></div> + </div> +</div> + +<div style="width: 100px; height: 10px;"> + <div class="grid gridMaxFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="100" data-expected-height="50"></div> + </div> +</div> + + +<div class="constrainedContainer"> + <div class="grid gridTwoMaxFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="10" data-expected-height="50"></div> + <div class="sizedToGridArea firstRowSecondColumn" data-expected-width="10" data-expected-height="50"></div> + </div> +</div> + +<!-- Allow the extra logical space distribution to occur. --> +<div style="width: 60px; height: 10px"> + <div class="grid gridTwoMaxFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="20" data-expected-height="50"></div> + <div class="sizedToGridArea firstRowSecondColumn" data-expected-width="40" data-expected-height="50"></div> + </div> +</div> + +<div style="width: 120px; height: 10px;"> + <div class="grid gridTwoMaxFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="40" data-expected-height="50"></div> + <div class="sizedToGridArea firstRowSecondColumn" data-expected-width="80" data-expected-height="50"></div> + </div> +</div> + + +<div class="constrainedContainer"> + <div class="grid gridTwoDoubleMaxFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="10" data-expected-height="50"></div> + <div class="sizedToGridArea firstRowSecondColumn" data-expected-width="10" data-expected-height="50"></div> + </div> +</div> + +<!-- Allow the extra logical space distribution to occur. --> +<div style="width: 60px; height: 10px"> + <div class="grid gridTwoDoubleMaxFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="12" data-expected-height="50"></div> + <div class="sizedToGridArea firstRowSecondColumn" data-expected-width="48" data-expected-height="50"></div> + </div> +</div> + +<div style="width: 120px; height: 10px;"> + <div class="grid gridTwoDoubleMaxFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="24" data-expected-height="50"></div> + <div class="sizedToGridArea firstRowSecondColumn" data-expected-width="96" data-expected-height="50"></div> + </div> +</div> + + +<!-- Custom test for a corner case. --> +<div style="width: 570px; height: 10px;"> + <div class="grid gridIgnoreSecondGridItem"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="420" data-expected-height="50"></div> + <div class="sizedToGridArea firstRowSecondColumn" data-expected-width="150" data-expected-height="50"></div> + </div> +</div> + +<!-- Flex track length must be at least its baseSize. --> +<div style="width: 100px; height: 10px;"> + <div class="grid gridRespectBaseSize"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="75" data-expected-height="50"></div> + <div class="sizedToGridArea firstRowSecondColumn" data-expected-width="25" data-expected-height="50"></div> + </div> +</div> + +<!-- Flex track lengths must be proportional to their flex factors.. --> +<div style="width: 275px; height: 10px;"> + <div class="grid gridRespectProportions"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="25" data-expected-height="50"></div> + <div class="sizedToGridArea firstRowSecondColumn" data-expected-width="50" data-expected-height="50"></div> + <div class="sizedToGridArea firstRowThirdColumn" data-expected-width="200" data-expected-height="50"></div> + </div> +</div> + +<!-- Flex track lengths must be proportional but still respecting their base sizes. --> +<div style="width: 350px; height: 10px;"> + <div class="grid gridRespectBaseSizeProportions"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="50"></div> + <div class="sizedToGridArea firstRowSecondColumn" data-expected-width="100" data-expected-height="50"></div> + <div class="sizedToGridArea firstRowThirdColumn" data-expected-width="200" data-expected-height="50"></div> + </div> +</div> + +<!-- Not enough space to respect proportions, because minTrackBreadh it's a harder requirement --> +<div style="width: 275px; height: 10px;"> + <div class="grid gridRespectBaseSizeBeforeProportions"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="50"></div> + <div class="sizedToGridArea firstRowSecondColumn" data-expected-width="75" data-expected-height="50"></div> + <div class="sizedToGridArea firstRowThirdColumn" data-expected-width="150" data-expected-height="50"></div> + </div> +</div> + +</body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-and-minmax-content-resolution-columns-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-content-resolution-columns-002.html index b92eb9f0ddd..b92eb9f0ddd 100644 --- a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-and-minmax-content-resolution-columns-001.html +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-content-resolution-columns-002.html diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-content-resolution-rows-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-content-resolution-rows-001.html new file mode 100644 index 00000000000..d10b84014de --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-content-resolution-rows-001.html @@ -0,0 +1,253 @@ +<!DOCTYPE html> +<html> +<title>CSS Grid Layout Test: Auto repeat tracks, grid-template-rows and flexible lengths.</title> +<link rel="author" title="Julien Chaffraix" href="mailto:jchaffraix@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#track-sizes"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#fr-unit"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=235258"> +<link rel="stylesheet" href="/fonts/ahem.css"> +<link rel="stylesheet" href="/css/support/grid.css"> +<meta name="assert" content="Test that resolving auto tracks on grid items using <flex> values with grid-template-rows works properly." /> + +<style> +.gridFlexContent { + grid-template-columns: 50px; + grid-template-rows: 1fr 1fr; +} +.gridMaxFlexContent { + grid-template-columns: 50px; + grid-template-rows: minmax(30px, 2fr); +} +.gridTwoMaxFlexContent { + grid-template-columns: 50px; + grid-template-rows: minmax(10px, 1fr) minmax(10px, 2fr); +} +.gridTwoDoubleMaxFlexContent { + grid-template-columns: 50px; + grid-template-rows: minmax(10px, 0.5fr) minmax(10px, 2fr); +} +.gridRespectBaseSize { + grid-template-columns: 50px; + grid-template-rows: minmax(75px, 1fr) minmax(0px, 2fr); +} +.gridRespectProportions { + grid-template-columns: 50px; + grid-template-rows: minmax(25px, .25fr) minmax(0px, .5fr) minmax(0px, 2fr); +} +.gridRespectBaseSizeProportions { + grid-template-columns: 50px; + grid-template-rows: minmax(50px, .25fr) minmax(0px, .5fr) minmax(0px, 1fr); +} +.gridRespectBaseSizeBeforeProportions { + grid-template-columns: 50px; + grid-template-rows: minmax(50px, .25fr) minmax(0px, .5fr) minmax(0px, 1fr); +} +.thirdRowFirstColumn { + background-color: yellow; + grid-column: 1; + grid-row: 3; +} +</style> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<script type="text/javascript"> + setup({ explicit_done: true }); +</script> + +<body onload="document.fonts.ready.then(() => { checkLayout('.grid'); })"> + +<div class="grid gridFlexContent constrainedContainer" style="position: relative;"> + <div class="sizedToGridArea firstRowFirstColumn" data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="30">X<br>X<br>X</div> + <div class="sizedToGridArea secondRowFirstColumn" data-offset-x="0" data-offset-y="30" data-expected-width="50" data-expected-height="50">X<br>X<br>X<br>X<br>X</div> +</div> + +<div class="constrainedContainer"> + <div class="grid gridMaxFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="30"></div> + </div> +</div> + +<!-- Allow the extra logical space distribution to occur. --> +<div style="width: 10px; height: 40px"> + <div class="grid gridMaxFlexContent" style="height: 100%;"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="40"></div> + </div> +</div> + +<div style="width: 10px; height: 40px"> + <div class="grid gridMaxFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="30"></div> + </div> +</div> + +<div style="width: 10px; height: 100px;"> + <div class="grid gridMaxFlexContent" style="height: 100%;"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="100"></div> + </div> +</div> + +<div style="width: 10px; height: 100px;"> + <div class="grid gridMaxFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="30"></div> + </div> +</div> + +<div class="constrainedContainer"> + <div class="grid gridTwoMaxFlexContent" style="height: 100%"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="10"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="10"></div> + </div> +</div> + +<div class="constrainedContainer"> + <div class="grid gridTwoMaxFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="10"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="20"></div> + </div> +</div> + +<!-- Allow the extra logical space distribution to occur. --> +<div style="width: 10px; height: 60px"> + <div class="grid gridTwoMaxFlexContent" style="height: 100%"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="20"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="40"></div> + </div> +</div> + +<div style="width: 10px; height: 60px"> + <div class="grid gridTwoMaxFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="10"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="20"></div> + </div> +</div> + +<div style="width: 10px; height: 120px;"> + <div class="grid gridTwoMaxFlexContent" style="height: 100%"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="40"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="80"></div> + </div> +</div> + +<div style="width: 10px; height: 120px;"> + <div class="grid gridTwoMaxFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="10"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="20"></div> + </div> +</div> + +<div class="constrainedContainer"> + <div class="grid gridTwoDoubleMaxFlexContent" style="height: 100%"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="10"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="10"></div> + </div> +</div> + +<!-- We normalize fraction flex factors to 1, so we don't keep exact proportions with >1 factors. --> +<div class="constrainedContainer"> + <div class="grid gridTwoDoubleMaxFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="10"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="20"></div> + </div> +</div> + +<!-- Allow the extra logical space distribution to occur. --> +<div style="width: 10px; height: 60px"> + <div class="grid gridTwoDoubleMaxFlexContent" style="height: 100%"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="12"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="48"></div> + </div> +</div> + +<!-- We normalize fraction flex factors to 1, so we don't keep exact proportions with >1 factors. --> +<div style="width: 10px; height: 60px"> + <div class="grid gridTwoDoubleMaxFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="10"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="20"></div> + </div> +</div> + +<div style="width: 10px; height: 120px;"> + <div class="grid gridTwoDoubleMaxFlexContent" style="height: 100%"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="24"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="96"></div> + </div> +</div> + +<!-- We normalize fraction flex factors to 1, so we don't keep exact proportions with >1 factors. --> +<div style="width: 10px; height: 120px;"> + <div class="grid gridTwoDoubleMaxFlexContent"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="10"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="20"></div> + </div> +</div> + +<!-- Flex track length must be at least its baseSize. --> +<div style="width: 10px; height: 100px;"> + <div class="grid gridRespectBaseSize" style="height: 100%;"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="75"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="25"></div> + </div> +</div> + +<div style="width: 10px; height: 100px;"> + <div class="grid gridRespectBaseSize"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="75"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="150"></div> + </div> +</div> + +<!-- Flex track lengths must be proportional to their flex factors.. --> +<div style="width: 10px; height: 275px;"> + <div class="grid gridRespectProportions" style="height: 100%;"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="25"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="50"></div> + <div class="sizedToGridArea thirdRowFirstColumn" data-expected-width="50" data-expected-height="200"></div> + </div> +</div> + +<div style="width: 10px; height: 275px;"> + <div class="grid gridRespectProportions"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="25"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="13"></div> + <div class="sizedToGridArea thirdRowFirstColumn" data-expected-width="50" data-expected-height="50"></div> + </div> +</div> + +<!-- Flex track lengths must be proportional but still respecting their base sizes. --> +<div style="width: 10px; height: 350px;"> + <div class="grid gridRespectBaseSizeProportions" style="height: 100%;"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="50"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="100"></div> + <div class="sizedToGridArea thirdRowFirstColumn" data-expected-width="50" data-expected-height="200"></div> + </div> +</div> + +<div style="width: 10px; height: 350px;"> + <div class="grid gridRespectBaseSizeProportions"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="50"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="25"></div> + <div class="sizedToGridArea thirdRowFirstColumn" data-expected-width="50" data-expected-height="50"></div> + </div> +</div> + +<!-- Not enough space to respect proportions, because minTrackBreadh it's a harder requirement --> +<div style="width: 10px; height: 275px;"> + <div class="grid gridRespectBaseSizeBeforeProportions" style="height: 100%;"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="50"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="75"></div> + <div class="sizedToGridArea thirdRowFirstColumn" data-expected-width="50" data-expected-height="150"></div> + </div> +</div> + +<div style="width: 10px; height: 275px;"> + <div class="grid gridRespectBaseSizeBeforeProportions"> + <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="50"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="25"></div> + <div class="sizedToGridArea thirdRowFirstColumn" data-expected-width="50" data-expected-height="50"></div> + </div> +</div> + +</body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-and-minmax-content-resolution-rows-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-content-resolution-rows-002.html index ebaa2c08e4b..d668a93a324 100644 --- a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-and-minmax-content-resolution-rows-001.html +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-content-resolution-rows-002.html @@ -54,8 +54,6 @@ <body onload="document.fonts.ready.then(() => { checkLayout('.grid'); })"> -<p>Test that resolving auto tracks on grid items works properly.</p> - <div class="constrainedContainer"> <div class="grid gridMaxMaxContent"> <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="10">XXXXX</div> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-factor-sum-less-than-1-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-factor-sum-less-than-1-001.html new file mode 100644 index 00000000000..ad7af2d8464 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-factor-sum-less-than-1-001.html @@ -0,0 +1,101 @@ +<!DOCTYPE html> +<html> +<title>CSS Grid Layout Test: flex factor sum smaller than 1.</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid/#algo-find-fr-size"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#fr-unit"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=520477"> +<link rel="stylesheet" href="/css/support/grid.css"> +<meta name="assert" content="Test that resolving auto tracks on grid items works properly even when the flex factor sum is less than 1." /> + +<style> +.onlyColumnFractionFlexFactors { + grid-template-columns: minmax(0, 0.1fr) minmax(0, 0.2fr) minmax(0, 0.3fr); + grid-template-rows: 50px; + width: 100px; +} +.onlyRowFractionFlexFactors { + grid-template-columns: 50px; + grid-template-rows: minmax(0, 0.1fr) minmax(0, 0.2fr) minmax(0, 0.3fr); + width: 50px; + height: 100px; +} +.fixedAndfractionFlexFactors { + grid-template-columns: 50px minmax(0, 0.2fr) 30px; + grid-template-rows: minmax(0, 0.1fr) 50px minmax(0, 0.3fr); + width: 100px; + height: 100px; +} +.zeroValueFlexFactor { + grid-template-columns: .0fr .2fr .3fr; + grid-template-rows: 50px; + width: 100px; +} +.firstRowThirdColumn { + background-color: yellow; + grid-column: 3; + grid-row: 1; +} +.secondRowThirdColumn { + background-color: yellow; + grid-column: 3; + grid-row: 2; +} +.thirdRowFirstColumn { + background-color: brown; + grid-column: 1; + grid-row: 3; +} +.thirdRowThirdColumn { + background-color: magenta; + grid-column: 3; + grid-row: 3; +} +</style> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> + +<body onload="checkLayout('.grid');"> + +<div style="position: relative;"> + <div class="grid onlyColumnFractionFlexFactors"> + <div class="firstRowFirstColumn" data-expected-width="10" data-expected-height="50"></div> + <div class="firstRowSecondColumn" data-expected-width="20" data-expected-height="50"></div> + <div class="firstRowThirdColumn" data-expected-width="30" data-expected-height="50"></div> + </div> +</div> + +<div style="position: relative;"> + <div class="grid onlyRowFractionFlexFactors"> + <div class="firstRowFirstColumn" data-expected-width="50" data-expected-height="10"></div> + <div class="secondRowFirstColumn" data-expected-width="50" data-expected-height="20"></div> + <div class="thirdRowFirstColumn" data-expected-width="50" data-expected-height="30"></div> + </div> +</div> + +<div style="position: relative;"> + <div class="grid zeroValueFlexFactor"> + <div class="firstRowFirstColumn" data-expected-width="0" data-expected-height="50"></div> + <div class="firstRowSecondColumn" data-expected-width="20" data-expected-height="50"></div> + <div class="firstRowThirdColumn" data-expected-width="30" data-expected-height="50"></div> + </div> +</div> + +<div style="position: relative;"> + <div class="grid fixedAndfractionFlexFactors"> + <div class="firstRowFirstColumn" data-expected-width="50" data-expected-height="5"></div> + <div class="firstRowSecondColumn" data-expected-width="4" data-expected-height="5"></div> + <div class="firstRowThirdColumn" data-expected-width="30" data-expected-height="5"></div> + <div class="secondRowFirstColumn" data-expected-width="50" data-expected-height="50"></div> + <div class="secondRowSecondColumn" data-expected-width="4" data-expected-height="50"></div> + <div class="secondRowThirdColumn" data-expected-width="30" data-expected-height="50"></div> + <div class="thirdRowFirstColumn" data-expected-width="50" data-expected-height="15"></div> + <div class="thirdRowSecondColumn" data-expected-width="4" data-expected-height="15"></div> + <div class="thirdRowThirdColumn" data-expected-width="30" data-expected-height="15"></div> + </div> +</div> + +</body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-item-grid-container-percentage-rows-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-item-grid-container-percentage-rows-001.html new file mode 100644 index 00000000000..ba655ce8a17 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/flex-item-grid-container-percentage-rows-001.html @@ -0,0 +1,40 @@ +<!DOCTYPE html> +<title>CSS Grid Layout Test: Percentage rows resolution in a flex item grid container</title> +<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#grid-item"> +<link rel="help" href="https://drafts.csswg.org/css-flexbox/#definite-sizes"> +<link rel="issue" href="https://bugs.chromium.org/p/chromium/issues/detail?id=617876"> +<link rel="match" href="../reference/flex-item-grid-container-percentage-rows-001-ref.html"> +<meta name="assert" content="This test ensures that percentage rows are properly resolved for a grid container that is a flex item with a definite height."> +<link rel="stylesheet" href="/css/support/grid.css"> +<style> +.flex { + display: flex; + flex-direction: column; + width: 200px; + height: 200px; + border: 5px solid; +} + +.flexitem { + flex: 1; + background: magenta; +} + +.grid { + display: grid; + grid: 50% / 1fr; +} + +.griditem { + background: cyan; +} +</style> + +<p>Test passes if you see a 200x200 box with top half cyan and bottom half magenta.</p> + +<div class="flex"> + <div class="flexitem grid"> + <div class="griditem"></div> + </div> +</div> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-add-item-with-positioned-items-crash.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-add-item-with-positioned-items-crash.html new file mode 100644 index 00000000000..7b2ed99f223 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-add-item-with-positioned-items-crash.html @@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html> +<head> +<title>CSS Grid Layout Test: no crash with adding positioned grid items</title> +<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid/#grid-definition"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=273898"> +<meta name="assert" content="Test that adding grid items when some of them are positioned does not crash." /> + +<style> +#grid { + display: grid; + grid-auto-flow: dense; +} + +.absolute { + position: absolute; +} +</style> +</head> + +<body> +<div id="grid"> + <div></div> + <div class="absolute"></div> +</div> + +<script> + var grid = document.getElementById("grid"); + grid.offsetTop; + var newItem1 = document.createElement("div"); + grid.appendChild(newItem1); + var newItem2 = document.createElement("div"); + newItem2.className = "absolute"; + grid.appendChild(newItem2); +</script> +</body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-add-positioned-block-item-after-inline-item-crash.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-add-positioned-block-item-after-inline-item-crash.html new file mode 100644 index 00000000000..4b7aa9913a7 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-add-positioned-block-item-after-inline-item-crash.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html> +<head> +<title>CSS Grid Layout Test: no crash with positioned block grid items</title> +<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid/#grid-definition"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=273898"> +<meta name="assert" content="Test that adding a positioned block grid item after an inline grid item does not crash." /> + +<style> +#grid { + display: grid; + grid-auto-flow: dense; +} + +embed { + position: absolute; +} +</style> +</head> + +<body> +<div id="grid"> + test +</div> + +<script> + var grid = document.getElementById("grid"); + grid.offsetTop; + var embed = document.createElement("embed"); + embed.setAttribute("type", "image/png"); + grid.appendChild(embed); +</script> +</body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-fill-columns-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-fill-columns-001.html new file mode 100644 index 00000000000..ed32ee55d5b --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-fill-columns-001.html @@ -0,0 +1,165 @@ +<!DOCTYPE html> +<title>CSS Grid: auto-fill columns</title> +<link rel="author" title="Sergio Villar" href="mailto: svillar@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#valdef-repeat-auto-fill"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-auto-columns"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-auto-rows"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-template-columns"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-column"> +<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-grid-column-gap"> +<link rel="help" href="https://crbug.com/619930"> +<link rel="help" href="https://crbug.com/589460"> +<meta name="assert" content="Check that auto-fill columns are properly computed in a grid container"/> +<link href="/css/support/grid.css" rel="stylesheet"> +<style> + +.grid { + border: 2px solid magenta; + width: 200px; + position: relative; + justify-content: start; + grid-auto-columns: 157px; + grid-auto-rows: 25px; +} + +.gridOnlyAutoRepeat { grid-template-columns: repeat(auto-fill, 30px [autobar]); } +.gridAutoRepeatAndFixedBefore { grid-template-columns: 10px [foo] 20% [bar] repeat(auto-fill, [autofoo] 35px); } +.gridAutoRepeatAndFixedAfter { grid-template-columns: repeat(auto-fill, [first] 30px [last]) [foo] minmax(60px, 80px) [bar] minmax(45px, max-content); } +.gridAutoRepeatAndFixed { grid-template-columns: [start] repeat(2, 50px [a]) [middle] repeat(auto-fill, [autofoo] 15px [autobar]) minmax(5%, 10%) [end]; } +.gridMultipleNames { grid-template-columns: [start] 20px [foo] 50% repeat(auto-fill, [bar] 20px [start foo]) [foo] 10% [end bar]; } +.gridMultipleTracks { grid-template-columns: [start] 20px repeat(auto-fill, [a] 2em [b c] 10% [d]) [e] minmax(75px, 1fr) [last]; } + +.item { background-color: cyan; } + +.gap { grid-column-gap: 20px; } + +</style> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> + +<body onload="checkLayout('.grid')"> +<div id="log"></div> + +<p>This test checks that repeat(auto-fill, ) syntax works as expected.</p> + +<div class="grid gridOnlyAutoRepeat"> + <div class="item" style="grid-column: 1 / span 6" data-offset-x="0" data-offset-y="0" data-expected-width="180" data-expected-height="25"></div> +</div> + +<div class="grid gridOnlyAutoRepeat"> + <div class="item" style="grid-column: 1 / span 6 autobar" data-offset-x="0" data-offset-y="0" data-expected-width="180" data-expected-height="25"></div> +</div> + +<div class="grid gridOnlyAutoRepeat gap"> + <div class="item" style="grid-column: 1 / span 5" data-offset-x="0" data-offset-y="0" data-expected-width="357" data-expected-height="25"></div> +</div> + +<div class="grid gridOnlyAutoRepeat gap"> + <div class="item" style="grid-column: autobar 2 / span 3" data-offset-x="100" data-offset-y="0" data-expected-width="257" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore"> + <div class="item" style="grid-column: 1 / span 6" data-offset-x="0" data-offset-y="0" data-expected-width="190" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore"> + <div class="item" style="grid-column: foo / autofoo" data-offset-x="10" data-offset-y="0" data-expected-width="40" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore"> + <div class="item" style="grid-column: bar / 5 autofoo" data-offset-x="50" data-offset-y="0" data-expected-width="297" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore gap"> + <div class="item" style="grid-column: 1 / span 4" data-offset-x="0" data-offset-y="0" data-expected-width="180" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore gap"> + <div class="item" style="grid-column: span 3 / 2 autofoo" data-offset-x="0" data-offset-y="0" data-expected-width="125" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore gap"> + <div class="item" style="grid-column: notPresent / 3 autofoo" data-offset-x="377" data-offset-y="0" data-expected-width="157" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter"> + <div class="item" style="grid-column: 1 / span 4" data-offset-x="0" data-offset-y="0" data-expected-width="185" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter"> + <div class="item" style="grid-column: first / last 2" data-offset-x="0" data-offset-y="0" data-expected-width="60" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter"> + <div class="item" style="grid-column: last 2 / foo" data-offset-x="60" data-offset-y="0" data-expected-width="80" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter gap"> + <div class="item" style="grid-column: 1 / span 3" data-offset-x="0" data-offset-y="0" data-expected-width="195" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter gap"> + <div class="item" style="grid-column: 3 / span 1 bar" data-offset-x="130" data-offset-y="0" data-expected-width="222" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter gap"> + <div class="item" style="grid-column: first / foo" data-offset-x="0" data-offset-y="0" data-expected-width="30" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed"> + <div class="item" style="grid-column: 1 / span 8" data-offset-x="0" data-offset-y="0" data-expected-width="195" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed"> + <div class="item" style="grid-column: a / autobar 2" data-offset-x="50" data-offset-y="0" data-expected-width="80" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed"> + <div class="item" style="grid-column: autofoo / end" data-offset-x="100" data-offset-y="0" data-expected-width="95" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed gap"> + <div class="item" style="grid-column: 1 / span 4" data-offset-x="0" data-offset-y="0" data-expected-width="195" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed gap"> + <div class="item" style="grid-column: autobar / -1" data-offset-x="175" data-offset-y="0" data-expected-width="20" data-expected-height="25"></div> +</div> + +<div class="grid gridMultipleNames"> + <div class="item" style="grid-column: 1 / -1" data-offset-x="0" data-offset-y="0" data-expected-width="200" data-expected-height="25"></div> +</div> + +<div class="grid gridMultipleNames"> + <div class="item" style="grid-column: foo 3 / 4 bar" data-offset-x="160" data-offset-y="0" data-expected-width="40" data-expected-height="25"></div> +</div> + +<div class="grid gridMultipleNames"> + <div class="item" style="grid-column: -6 / span 2 start" data-offset-x="20" data-offset-y="0" data-expected-width="140" data-expected-height="25"></div> +</div> + +<div class="grid gridMultipleNames gap"> + <div class="item" style="grid-column: -4 / -2" data-offset-x="40" data-offset-y="0" data-expected-width="140" data-expected-height="25"></div> +</div> + +<div class="grid gridMultipleNames gap"> + <div class="item" style="grid-column: bar / foo 2" data-offset-x="160" data-offset-y="0" data-expected-width="20" data-expected-height="25"></div> +</div> + +<div class="grid gridMultipleNames gap"> + <div class="item" style="grid-column: foo / bar 2" data-offset-x="40" data-offset-y="0" data-expected-width="180" data-expected-height="25"></div> +</div> + +<div class="grid gridMultipleTracks"> + <div class="item" style="grid-column: a / 2 c" data-offset-x="20" data-offset-y="0" data-expected-width="84" data-expected-height="25"></div> + <div class="item" style="grid-column: 3 / e; grid-row: 2;" data-offset-x="52" data-offset-y="25" data-expected-width="72" data-expected-height="25"></div> +</div> + +<div class="grid gridMultipleTracks gap"> + <div class="item" style="grid-column: a / c" data-offset-x="40" data-offset-y="0" data-expected-width="32" data-expected-height="25"></div> + <div class="item" style="grid-column: 3 / last; grid-row: 2;" data-offset-x="92" data-offset-y="25" data-expected-width="115" data-expected-height="25"></div> +</div> + +</body> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-fill-rows-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-fill-rows-001.html new file mode 100644 index 00000000000..afce3f5fa91 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-fill-rows-001.html @@ -0,0 +1,184 @@ +<!DOCTYPE html> +<title>CSS Grid: auto-fill rows</title> +<link rel="author" title="Sergio Villar" href="mailto: svillar@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#valdef-repeat-auto-fill"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-auto-columns"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-auto-rows"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-template-rows"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-row"> +<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-grid-row-gap"> +<link rel="help" href="https://crbug.com/619930"> +<link rel="help" href="https://crbug.com/589460"> +<link rel="help" href="https://crbug.com/648814"> +<meta name="assert" content="Check that auto-fill rows are properly computed in a grid container"/> +<link href="/css/support/grid.css" rel="stylesheet"> +<style> + +.grid { + border: 2px solid magenta; + height: 200px; + width: 25px; + align-content: start; + grid-auto-rows: 157px; + grid-auto-columns: 25px; + + float: left; + position: relative; + margin-right: 2px; +} + +.gridOnlyAutoRepeat { grid-template-rows: repeat(auto-fill, 30px [autobar]); } +.gridAutoRepeatAndFixedBefore { grid-template-rows: 10px [foo] 20% [bar] repeat(auto-fill, [autofoo] 35px); } +.gridAutoRepeatAndFixedAfter { grid-template-rows: repeat(auto-fill, [first] 30px [last]) [foo] minmax(60px, 80px) [bar] minmax(45px, max-content); } +.gridAutoRepeatAndFixed { grid-template-rows: [start] repeat(2, 50px [a]) [middle] repeat(auto-fill, [autofoo] 15px [autobar]) minmax(5%, 10%) [end]; } +.gridMultipleNames { grid-template-rows: [start] 20px [foo] 50% repeat(auto-fill, [bar] 20px [start foo]) [foo] 10% [end bar]; } +.gridMultipleTracks { grid-template-rows: [start] 20px repeat(auto-fill, [a] 2em [b c] 10% [d]) [e] minmax(75px, 1fr) [last]; } + +.item { background-color: blue; } +.item:nth-child(2) { background: green; } +.item:nth-child(3) { background: orange; } + +.gap { grid-row-gap: 20px; } + +</style> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> + +<body onload="checkLayout('.grid')"> +<div id="log"></div> + +<p>This test checks that repeat(auto-fill, ) syntax works as expected.</p> + +<div class="grid gridOnlyAutoRepeat"> + <div class="item" style="grid-row: 1 / span 6" data-offset-y="0" data-offset-x="0" data-expected-height="180" data-expected-width="25"></div> +</div> + +<div class="grid gridOnlyAutoRepeat"> + <div class="item" style="grid-row: 1 / span 6 autobar" data-offset-y="0" data-offset-x="0" data-expected-height="180" data-expected-width="25"></div> +</div> + +<div class="grid gridOnlyAutoRepeat gap"> + <div class="item" style="grid-row: 1 / span 5" data-offset-y="0" data-offset-x="0" data-expected-height="357" data-expected-width="25"></div> +</div> + +<div class="grid gridOnlyAutoRepeat gap"> + <div class="item" style="grid-row: autobar 2 / span 3" data-offset-y="100" data-offset-x="0" data-expected-height="257" data-expected-width="25"></div> +</div> + +<div class="grid gridOnlyAutoRepeat gap" style="height: auto; max-height: 90px;" data-expected-height="94" data-expected-width="29"> + <div class="item" data-offset-y="0" data-offset-x="0" data-expected-height="30" data-expected-width="25"></div> + <div class="item" data-offset-y="50" data-offset-x="0" data-expected-height="30" data-expected-width="25"></div> + <div class="item" data-offset-y="100" data-offset-x="0" data-expected-height="157" data-expected-width="25"></div> +</div> + +<div class="grid gridOnlyAutoRepeat gap" style="height: auto; max-height: 90px; min-height: 130px;" data-expected-height="134" data-expected-width="29"> + <div class="item" data-offset-y="0" data-offset-x="0" data-expected-height="30" data-expected-width="25"></div> + <div class="item" data-offset-y="50" data-offset-x="0" data-expected-height="30" data-expected-width="25"></div> + <div class="item" data-offset-y="100" data-offset-x="0" data-expected-height="30" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore"> + <div class="item" style="grid-row: 1 / span 6" data-offset-y="0" data-offset-x="0" data-expected-height="190" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore"> + <div class="item" style="grid-row: foo / autofoo" data-offset-y="10" data-offset-x="0" data-expected-height="40" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore"> + <div class="item" style="grid-row: bar / 5 autofoo" data-offset-y="50" data-offset-x="0" data-expected-height="297" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore gap"> + <div class="item" style="grid-row: 1 / span 4" data-offset-y="0" data-offset-x="0" data-expected-height="180" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore gap"> + <div class="item" style="grid-row: span 3 / 2 autofoo" data-offset-y="0" data-offset-x="0" data-expected-height="125" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore gap"> + <div class="item" style="grid-row: notPresent / 3 autofoo" data-offset-y="377" data-offset-x="0" data-expected-height="157" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter"> + <div class="item" style="grid-row: 1 / span 4" data-offset-y="0" data-offset-x="0" data-expected-height="185" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter"> + <div class="item" style="grid-row: first / last 2" data-offset-y="0" data-offset-x="0" data-expected-height="60" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter"> + <div class="item" style="grid-row: last 2 / foo" data-offset-y="60" data-offset-x="0" data-expected-height="80" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter gap"> + <div class="item" style="grid-row: 1 / span 3" data-offset-y="0" data-offset-x="0" data-expected-height="195" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter gap"> + <div class="item" style="grid-row: 3 / span 1 bar" data-offset-y="130" data-offset-x="0" data-expected-height="222" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter gap"> + <div class="item" style="grid-row: first / foo" data-offset-y="0" data-offset-x="0" data-expected-height="30" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed"> + <div class="item" style="grid-row: 1 / span 8" data-offset-y="0" data-offset-x="0" data-expected-height="195" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed"> + <div class="item" style="grid-row: a / autobar 2" data-offset-y="50" data-offset-x="0" data-expected-height="80" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed"> + <div class="item" style="grid-row: autofoo / end" data-offset-y="100" data-offset-x="0" data-expected-height="95" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed gap"> + <div class="item" style="grid-row: 1 / span 4" data-offset-y="0" data-offset-x="0" data-expected-height="195" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed gap"> + <div class="item" style="grid-row: autobar / -1" data-offset-y="175" data-offset-x="0" data-expected-height="20" data-expected-width="25"></div> +</div> + +<div class="grid gridMultipleNames"> + <div class="item" style="grid-row: 1 / -1" data-offset-y="0" data-offset-x="0" data-expected-height="200" data-expected-width="25"></div> +</div> + +<div class="grid gridMultipleNames"> + <div class="item" style="grid-row: foo 3 / 4 bar" data-offset-y="160" data-offset-x="0" data-expected-height="40" data-expected-width="25"></div> +</div> + +<div class="grid gridMultipleNames"> + <div class="item" style="grid-row: -6 / span 2 start" data-offset-y="20" data-offset-x="0" data-expected-height="140" data-expected-width="25"></div> +</div> + +<div class="grid gridMultipleNames gap"> + <div class="item" style="grid-row: -4 / -2" data-offset-y="40" data-offset-x="0" data-expected-height="140" data-expected-width="25"></div> +</div> + +<div class="grid gridMultipleNames gap"> + <div class="item" style="grid-row: bar / foo 2" data-offset-y="160" data-offset-x="0" data-expected-height="20" data-expected-width="25"></div> +</div> + +<div class="grid gridMultipleNames gap"> + <div class="item" style="grid-row: foo / bar 2" data-offset-y="40" data-offset-x="0" data-expected-height="180" data-expected-width="25"></div> +</div> + +<div class="grid gridMultipleTracks"> + <div class="item" style="grid-row: a / 2 c" data-offset-y="20" data-offset-x="0" data-expected-height="84" data-expected-width="25"></div> + <div class="item" style="grid-row: 3 / e; grid-column: 2;" data-offset-y="52" data-offset-x="25" data-expected-height="72" data-expected-width="25"></div> +</div> + +<div class="grid gridMultipleTracks gap"> + <div class="item" style="grid-row: a / c" data-offset-y="40" data-offset-x="0" data-expected-height="32" data-expected-width="25"></div> + <div class="item" style="grid-row: 3 / last; grid-column: 2;" data-offset-y="92" data-offset-x="25" data-expected-height="115" data-expected-width="25"></div> +</div> + +</body> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-fit-columns-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-fit-columns-001.html new file mode 100644 index 00000000000..b1dab7e32f9 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-fit-columns-001.html @@ -0,0 +1,176 @@ +<!DOCTYPE html> +<title>CSS Grid: auto-fit columns</title> +<link rel="author" title="Sergio Villar" href="mailto: svillar@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#valdef-repeat-auto-fit"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-auto-columns"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-auto-rows"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-template-columns"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-column"> +<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-grid-column-gap"> +<link rel="help" href="https://crbug.com/619930"> +<link rel="help" href="https://crbug.com/589460"> +<link rel="help" href="https://crbug.com/645746"> +<meta name="assert" content="Check that auto-fit columns are properly computed in a grid container"/> +<link href="/css/support/grid.css" rel="stylesheet"> +<style> + +.grid { + border: 2px solid magenta; + width: 200px; + position: relative; + justify-content: start; + grid-auto-columns: 157px; + grid-auto-rows: 25px; +} + +.gridOnlyAutoRepeat { grid-template-columns: repeat(auto-fit, 30px [autobar]); } +.gridAutoRepeatAndFixedBefore { grid-template-columns: 10px [foo] 20% [bar] repeat(auto-fit, [autofoo] 35px); } +.gridAutoRepeatAndFixedAfter { grid-template-columns: repeat(auto-fit, [first] 30px [last]) [foo] minmax(60px, 80px) [bar] minmax(45px, max-content); } +.gridAutoRepeatAndFixed { grid-template-columns: [start] repeat(2, 50px [a]) [middle] repeat(auto-fit, [autofoo] 15px [autobar]) minmax(5%, 10%) [end]; } +.gridMultipleNames { grid-template-columns: [start] 20px [foo] 50% repeat(auto-fit, [bar] 20px [start foo]) [foo] 10% [end bar]; } +.gridMultipleTracks { grid-template-columns: [start] 20px repeat(auto-fit, [a] 2em [b c] 10% [d]) [e] minmax(75px, 1fr) [last]; } +.gridMinMaxFixedFlex { grid-template-columns: repeat(auto-fit, minmax(50px, 1fr)); } + +.item { background-color: cyan; } +.item:nth-child(2n) { background-color: green; } + +.gap { grid-column-gap: 20px; } + +</style> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> + +<body onload="checkLayout('.grid')"> +<div id="log"></div> + +<p>This test checks that repeat(auto-fit, ) syntax works as expected.</p> + +<div class="grid gridOnlyAutoRepeat"> + <div class="item" style="grid-column: 1 / span 6" data-offset-x="0" data-offset-y="0" data-expected-width="180" data-expected-height="25"></div> +</div> + +<div class="grid gridOnlyAutoRepeat"> + <div class="item" style="grid-column: 1 / span 6 autobar" data-offset-x="0" data-offset-y="0" data-expected-width="180" data-expected-height="25"></div> +</div> + +<div class="grid gridOnlyAutoRepeat gap"> + <div class="item" style="grid-column: 1 / span 5" data-offset-x="0" data-offset-y="0" data-expected-width="357" data-expected-height="25"></div> +</div> + +<div class="grid gridOnlyAutoRepeat gap"> + <div class="item" style="grid-column: autobar 2 / span 3" data-offset-x="0" data-offset-y="0" data-expected-width="257" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore"> + <div class="item" style="grid-column: 1 / span 6" data-offset-x="0" data-offset-y="0" data-expected-width="190" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore"> + <div class="item" style="grid-column: foo / autofoo" data-offset-x="10" data-offset-y="0" data-expected-width="40" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore"> + <div class="item" style="grid-column: bar / 5 autofoo" data-offset-x="50" data-offset-y="0" data-expected-width="297" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore gap"> + <div class="item" style="grid-column: 1 / span 4" data-offset-x="0" data-offset-y="0" data-expected-width="180" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore gap"> + <div class="item" style="grid-column: span 3 / 2 autofoo" data-offset-x="0" data-offset-y="0" data-expected-width="125" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore gap"> + <div class="item" style="grid-column: notPresent / 3 autofoo" data-offset-x="267" data-offset-y="0" data-expected-width="157" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter"> + <div class="item" style="grid-column: 1 / span 4" data-offset-x="0" data-offset-y="0" data-expected-width="185" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter"> + <div class="item" style="grid-column: first / last 2" data-offset-x="0" data-offset-y="0" data-expected-width="60" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter"> + <div class="item" style="grid-column: last 2 / foo" data-offset-x="0" data-offset-y="0" data-expected-width="80" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter gap"> + <div class="item" style="grid-column: 1 / span 3" data-offset-x="0" data-offset-y="0" data-expected-width="195" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter gap"> + <div class="item" style="grid-column: 3 / span 1 bar" data-offset-x="80" data-offset-y="0" data-expected-width="222" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter gap"> + <div class="item" style="grid-column: first / foo" data-offset-x="0" data-offset-y="0" data-expected-width="30" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed"> + <div class="item" style="grid-column: 1 / span 8" data-offset-x="0" data-offset-y="0" data-expected-width="195" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed"> + <div class="item" style="grid-column: a / autobar 2" data-offset-x="50" data-offset-y="0" data-expected-width="80" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed"> + <div class="item" style="grid-column: autofoo / end" data-offset-x="100" data-offset-y="0" data-expected-width="95" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed gap"> + <div class="item" style="grid-column: 1 / span 4" data-offset-x="0" data-offset-y="0" data-expected-width="195" data-expected-height="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed gap"> + <div class="item" style="grid-column: autobar / -1" data-offset-x="140" data-offset-y="0" data-expected-width="20" data-expected-height="25"></div> +</div> + +<div class="grid gridMultipleNames"> + <div class="item" style="grid-column: 1 / -1" data-offset-x="0" data-offset-y="0" data-expected-width="200" data-expected-height="25"></div> +</div> + +<div class="grid gridMultipleNames"> + <div class="item" style="grid-column: foo 3 / 4 bar" data-offset-x="120" data-offset-y="0" data-expected-width="40" data-expected-height="25"></div> +</div> + +<div class="grid gridMultipleNames"> + <div class="item" style="grid-column: -6 / span 2 start" data-offset-x="20" data-offset-y="0" data-expected-width="140" data-expected-height="25"></div> +</div> + +<div class="grid gridMultipleNames gap"> + <div class="item" style="grid-column: -4 / -2" data-offset-x="40" data-offset-y="0" data-expected-width="140" data-expected-height="25"></div> +</div> + +<div class="grid gridMultipleNames gap"> + <div class="item" style="grid-column: bar / foo 2" data-offset-x="160" data-offset-y="0" data-expected-width="20" data-expected-height="25"></div> +</div> + +<div class="grid gridMultipleNames gap"> + <div class="item" style="grid-column: foo / bar 2" data-offset-x="40" data-offset-y="0" data-expected-width="180" data-expected-height="25"></div> +</div> + +<div class="grid gridMultipleTracks"> + <div class="item" style="grid-column: e / last;" data-offset-x="52" data-offset-y="0" data-expected-width="148" data-expected-height="25"></div> + <div class="item" style="grid-column: start / b;" data-offset-x="0" data-offset-y="25" data-expected-width="52" data-expected-height="25"></div> +</div> + +<div class="grid gridMultipleTracks gap"> + <div class="item" style="grid-column: c / -1;" data-offset-x="40" data-offset-y="0" data-expected-width="160" data-expected-height="25"></div> +</div> + +<div class="grid gridMinMaxFixedFlex gap"> + <div class="item" style="grid-column-start: 1" data-offset-x="0" data-offset-y="0" data-expected-width="200" data-expected-height="25"></div> +</div> + +<div class="grid gridMinMaxFixedFlex gap"> + <div class="item" style="grid-column-start: 1" data-offset-x="0" data-offset-y="0" data-expected-width="90" data-expected-height="25"></div> + <div class="item" style="grid-column-start: 2" data-offset-x="110" data-offset-y="0" data-expected-width="90" data-expected-height="25"></div> +</div> + +</body> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-fit-rows-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-fit-rows-001.html new file mode 100644 index 00000000000..7619d9e023e --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-fit-rows-001.html @@ -0,0 +1,169 @@ +<!DOCTYPE html> +<title>CSS Grid: auto-fit rows</title> +<link rel="author" title="Sergio Villar" href="mailto: svillar@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#valdef-repeat-auto-fit"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-auto-columns"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-auto-rows"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-template-rows"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-row"> +<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-grid-row-gap"> +<link rel="help" href="https://crbug.com/619930"> +<link rel="help" href="https://crbug.com/589460"> +<meta name="assert" content="Check that auto-fit rows are properly computed in a grid container"/> +<link href="/css/support/grid.css" rel="stylesheet"> +<style> + +.grid { + border: 2px solid magenta; + height: 200px; + width: 25px; + align-content: start; + grid-auto-rows: 157px; + grid-auto-columns: 25px; + + float: left; + position: relative; + margin-right: 2px; +} + +.gridOnlyAutoRepeat { grid-template-rows: repeat(auto-fit, 30px [autobar]); } +.gridAutoRepeatAndFixedBefore { grid-template-rows: 10px [foo] 20% [bar] repeat(auto-fit, [autofoo] 35px); } +.gridAutoRepeatAndFixedAfter { grid-template-rows: repeat(auto-fit, [first] 30px [last]) [foo] minmax(60px, 80px) [bar] minmax(45px, max-content); } +.gridAutoRepeatAndFixed { grid-template-rows: [start] repeat(2, 50px [a]) [middle] repeat(auto-fit, [autofoo] 15px [autobar]) minmax(5%, 10%) [end]; } +.gridMultipleNames { grid-template-rows: [start] 20px [foo] 50% repeat(auto-fit, [bar] 20px [start foo]) [foo] 10% [end bar]; } +.gridMultipleTracks { grid-template-rows: [start] 20px repeat(auto-fit, [a] 2em [b c] 10% [d]) [e] minmax(75px, 1fr) [last]; } + +.item { background-color: cyan; } +.item:nth-child(2n) { background-color: green; } + +.gap { grid-row-gap: 20px; } + +</style> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> + +<body onload="checkLayout('.grid')"> +<div id="log"></div> + +<p>This test checks that repeat(auto-fit, ) syntax works as expected.</p> + +<div class="grid gridOnlyAutoRepeat"> + <div class="item" style="grid-row: 1 / span 6" data-offset-y="0" data-offset-x="0" data-expected-height="180" data-expected-width="25"></div> +</div> + +<div class="grid gridOnlyAutoRepeat"> + <div class="item" style="grid-row: 1 / span 6 autobar" data-offset-y="0" data-offset-x="0" data-expected-height="180" data-expected-width="25"></div> +</div> + +<div class="grid gridOnlyAutoRepeat gap"> + <div class="item" style="grid-row: 1 / span 5" data-offset-y="0" data-offset-x="0" data-expected-height="357" data-expected-width="25"></div> +</div> + +<div class="grid gridOnlyAutoRepeat gap"> + <div class="item" style="grid-row: autobar 2 / span 3" data-offset-y="0" data-offset-x="0" data-expected-height="257" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore"> + <div class="item" style="grid-row: 1 / span 6" data-offset-y="0" data-offset-x="0" data-expected-height="190" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore"> + <div class="item" style="grid-row: foo / autofoo" data-offset-y="10" data-offset-x="0" data-expected-height="40" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore"> + <div class="item" style="grid-row: bar / 5 autofoo" data-offset-y="50" data-offset-x="0" data-expected-height="297" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore gap"> + <div class="item" style="grid-row: 1 / span 4" data-offset-y="0" data-offset-x="0" data-expected-height="180" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore gap"> + <div class="item" style="grid-row: span 3 / 2 autofoo" data-offset-y="0" data-offset-x="0" data-expected-height="125" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedBefore gap"> + <div class="item" style="grid-row: notPresent / 3 autofoo" data-offset-y="267" data-offset-x="0" data-expected-height="157" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter"> + <div class="item" style="grid-row: 1 / span 4" data-offset-y="0" data-offset-x="0" data-expected-height="185" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter"> + <div class="item" style="grid-row: first / last 2" data-offset-y="0" data-offset-x="0" data-expected-height="60" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter"> + <div class="item" style="grid-row: last 2 / foo" data-offset-y="0" data-offset-x="0" data-expected-height="80" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter gap"> + <div class="item" style="grid-row: 1 / span 3" data-offset-y="0" data-offset-x="0" data-expected-height="195" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter gap"> + <div class="item" style="grid-row: 3 / span 1 bar" data-offset-y="80" data-offset-x="0" data-expected-height="222" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixedAfter gap"> + <div class="item" style="grid-row: first / foo" data-offset-y="0" data-offset-x="0" data-expected-height="30" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed"> + <div class="item" style="grid-row: 1 / span 8" data-offset-y="0" data-offset-x="0" data-expected-height="195" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed"> + <div class="item" style="grid-row: a / autobar 2" data-offset-y="50" data-offset-x="0" data-expected-height="80" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed"> + <div class="item" style="grid-row: autofoo / end" data-offset-y="100" data-offset-x="0" data-expected-height="95" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed gap"> + <div class="item" style="grid-row: 1 / span 4" data-offset-y="0" data-offset-x="0" data-expected-height="195" data-expected-width="25"></div> +</div> + +<div class="grid gridAutoRepeatAndFixed gap"> + <div class="item" style="grid-row: autobar / -1" data-offset-y="140" data-offset-x="0" data-expected-height="20" data-expected-width="25"></div> +</div> + +<div class="grid gridMultipleNames"> + <div class="item" style="grid-row: 1 / -1" data-offset-y="0" data-offset-x="0" data-expected-height="200" data-expected-width="25"></div> +</div> + +<div class="grid gridMultipleNames"> + <div class="item" style="grid-row: foo 3 / 4 bar" data-offset-y="120" data-offset-x="0" data-expected-height="40" data-expected-width="25"></div> +</div> + +<div class="grid gridMultipleNames"> + <div class="item" style="grid-row: -6 / span 2 start" data-offset-y="20" data-offset-x="0" data-expected-height="140" data-expected-width="25"></div> +</div> + +<div class="grid gridMultipleNames gap"> + <div class="item" style="grid-row: -4 / -2" data-offset-y="40" data-offset-x="0" data-expected-height="140" data-expected-width="25"></div> +</div> + +<div class="grid gridMultipleNames gap"> + <div class="item" style="grid-row: bar / foo 2" data-offset-y="160" data-offset-x="0" data-expected-height="20" data-expected-width="25"></div> +</div> + +<div class="grid gridMultipleNames gap"> + <div class="item" style="grid-row: foo / bar 2" data-offset-y="40" data-offset-x="0" data-expected-height="180" data-expected-width="25"></div> +</div> + +<div class="grid gridMultipleTracks"> + <div class="item" style="grid-row: e / last;" data-offset-y="52" data-offset-x="0" data-expected-height="148" data-expected-width="25"></div> + <div class="item" style="grid-row: start / b;" data-offset-y="0" data-offset-x="0" data-expected-height="52" data-expected-width="25"></div> +</div> + +<div class="grid gridMultipleTracks gap"> + <div class="item" style="grid-row: c / -1;" data-offset-y="40" data-offset-x="0" data-expected-height="160" data-expected-width="25"></div> +</div> + +</body> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-repeat-intrinsic-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-repeat-intrinsic-001.html new file mode 100644 index 00000000000..a5f6f16407a --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-repeat-intrinsic-001.html @@ -0,0 +1,109 @@ +<!DOCTYPE html> +<title>CSS Grid: auto repeat computation for intrinsic sizes.</title> +<link rel="author" title="Sergio Villar" href="mailto:svillar@igalia.com"/> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#repeat-notation"/> +<meta name="assert" content="Checks that auto repeat tracks are properly recomputed and items are properly repositioned when grids have intrinsic inline sizes."/> +<link rel="issue" href="https://crbug.com/621517"/> +<link href="/css/support/grid.css" rel="stylesheet"/> +<link href="/css/support/width-keyword-classes.css" rel="stylesheet"/> + +<style> +.grid { + border: 2px solid black; + position: relative; + padding-top: 10px; + justify-items: start; +} + +.item { + background: cyan; + height: 20px; +} + +.gridAutoFillFixed { grid-template-columns: repeat(auto-fill, 20px) minmax(min-content, 40px); } +.gridAutoFillAuto { grid-template-columns: repeat(auto-fill, 10px) minmax(60px, auto); } +.gridAutoFitFixed { grid-template-columns: repeat(auto-fit, 20px) minmax(min-content, 40px); } +.gridAutoFitAuto { grid-template-columns: repeat(auto-fit, 10px) minmax(60px, auto); } + +.paddingTop { padding-top: 10px; } + +.abs { + height: 5px; + position: absolute; + width: 100%; +} +</style> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> + +<body onload="checkLayout('.grid')"> + +<div class="grid gridAutoFillFixed paddingTop max-content" data-expected-width="104" data-expected-height="34"> + <div class="item" style="grid-column: 1 / -1; width: 100px;" data-expected-width="100" data-expected-height="20" data-expected-x="0" data-expected-y="0"></div> + <div class="abs" style="grid-column: 1 / 2; background: purple;" data-expected-width="20" data-expected-height="5" data-expected-x="0" data-expected-y="0"></div> + <div class="abs" style="grid-column: 2 / 3; background: orange;" data-expected-width="20" data-expected-height="5" data-expected-x="20" data-expected-y="0"></div> + <div class="abs" style="grid-column: 3 / 4; background: yellow;" data-expected-width="20" data-expected-height="5" data-expected-x="40" data-expected-y="0"></div> + <div class="abs" style="grid-column: 4 / 5; background: green;" data-expected-width="40" data-expected-height="5" data-expected-x="60" data-expected-y="0"></div> +</div> + +<div class="grid gridAutoFillFixed paddingTop min-content" data-expected-width="104" data-expected-height="34"> + <div class="item" style="grid-column: 1 / -1; width: 100px;" data-expected-width="100" data-expected-height="20" data-expected-x="0" data-expected-y="0"></div> + <div class="abs" style="grid-column: 1 / 2; background: purple;" data-expected-width="20" data-expected-height="5" data-expected-x="0" data-expected-y="0"></div> + <div class="abs" style="grid-column: 2 / 3; background: orange;" data-expected-width="20" data-expected-height="5" data-expected-x="20" data-expected-y="0"></div> + <div class="abs" style="grid-column: 3 / 4; background: yellow;" data-expected-width="20" data-expected-height="5" data-expected-x="40" data-expected-y="0"></div> + <div class="abs" style="grid-column: 4 / 5; background: green;" data-expected-width="40" data-expected-height="5" data-expected-x="60" data-expected-y="0"></div> +</div> + +<div class="grid gridAutoFillAuto paddingTop max-content" data-expected-width="104" data-expected-height="34"> + <div class="item" style="grid-column: 1 / -1; width: 100px;" data-expected-width="100" data-expected-height="20" data-expected-x="0" data-expected-y="0"></div> + <div class="abs" style="grid-column: 1 / 2; background: purple;" data-expected-width="10" data-expected-height="5" data-expected-x="0" data-expected-y="0"></div> + <div class="abs" style="grid-column: 2 / 3; background: orange;" data-expected-width="10" data-expected-height="5" data-expected-x="20" data-expected-y="0"></div> + <div class="abs" style="grid-column: 3 / 4; background: yellow;" data-expected-width="10" data-expected-height="5" data-expected-x="40" data-expected-y="0"></div> + <div class="abs" style="grid-column: 4 / 5; background: green;" data-expected-width="10" data-expected-height="5" data-expected-x="60" data-expected-y="0"></div> +</div> + +<div class="grid gridAutoFillAuto paddingTop min-content" data-expected-width="74" data-expected-height="34"> + <div class="item" style="grid-column: 1 / -1; width: 100px;" data-expected-width="100" data-expected-height="20" data-expected-x="0" data-expected-y="0"></div> + <div class="abs" style="grid-column: 1 / 2; background: purple;" data-expected-width="10" data-expected-height="5" data-expected-x="0" data-expected-y="0"></div> + <div class="abs" style="grid-column: 2 / 3; background: orange;" data-expected-width="60" data-expected-height="5" data-expected-x="20" data-expected-y="0"></div> + <div class="abs" style="grid-column: 3 / 4; background: yellow;" data-expected-width="0" data-expected-height="5" data-expected-x="40" data-expected-y="0"></div> + <div class="abs" style="grid-column: 4 / 5; background: green;" data-expected-width="70" data-expected-height="5" data-expected-x="60" data-expected-y="0"></div> +</div> + +<!-- auto-fill --> + +<div class="grid gridAutoFitFixed paddingTop max-content" data-expected-width="104" data-expected-height="34"> + <div class="item" style="grid-column: 1 / -1; width: 100px;" data-expected-width="100" data-expected-height="20" data-expected-x="0" data-expected-y="0"></div> + <div class="abs" style="grid-column: 1 / 2; background: purple;" data-expected-width="20" data-expected-height="5" data-expected-x="0" data-expected-y="0"></div> + <div class="abs" style="grid-column: 2 / 3; background: orange;" data-expected-width="20" data-expected-height="5" data-expected-x="20" data-expected-y="0"></div> + <div class="abs" style="grid-column: 3 / 4; background: yellow;" data-expected-width="20" data-expected-height="5" data-expected-x="40" data-expected-y="0"></div> + <div class="abs" style="grid-column: 4 / 5; background: green;" data-expected-width="40" data-expected-height="5" data-expected-x="60" data-expected-y="0"></div> +</div> + +<div class="grid gridAutoFitFixed paddingTop min-content" data-expected-width="104" data-expected-height="34"> + <div class="item" style="grid-column: 1 / -1; width: 100px;" data-expected-width="100" data-expected-height="20" data-expected-x="0" data-expected-y="0"></div> + <div class="abs" style="grid-column: 1 / 2; background: purple;" data-expected-width="20" data-expected-height="5" data-expected-x="0" data-expected-y="0"></div> + <div class="abs" style="grid-column: 2 / 3; background: orange;" data-expected-width="20" data-expected-height="5" data-expected-x="20" data-expected-y="0"></div> + <div class="abs" style="grid-column: 3 / 4; background: yellow;" data-expected-width="20" data-expected-height="5" data-expected-x="40" data-expected-y="0"></div> + <div class="abs" style="grid-column: 4 / 5; background: green;" data-expected-width="40" data-expected-height="5" data-expected-x="60" data-expected-y="0"></div> +</div> + +<div class="grid gridAutoFitAuto paddingTop max-content" data-expected-width="104" data-expected-height="34"> + <div class="item" style="grid-column: 1 / -1; width: 100px;" data-expected-width="100" data-expected-height="20" data-expected-x="0" data-expected-y="0"></div> + <div class="abs" style="grid-column: 1 / 2; background: purple;" data-expected-width="10" data-expected-height="5" data-expected-x="0" data-expected-y="0"></div> + <div class="abs" style="grid-column: 2 / 3; background: orange;" data-expected-width="10" data-expected-height="5" data-expected-x="20" data-expected-y="0"></div> + <div class="abs" style="grid-column: 3 / 4; background: yellow;" data-expected-width="10" data-expected-height="5" data-expected-x="40" data-expected-y="0"></div> + <div class="abs" style="grid-column: 4 / 5; background: green;" data-expected-width="10" data-expected-height="5" data-expected-x="60" data-expected-y="0"></div> +</div> + +<div class="grid gridAutoFitAuto paddingTop min-content" data-expected-width="74" data-expected-height="34"> + <div class="item" style="grid-column: 1 / -1; width: 100px;" data-expected-width="100" data-expected-height="20" data-expected-x="0" data-expected-y="0"></div> + <div class="abs" style="grid-column: 1 / 2; background: purple;" data-expected-width="10" data-expected-height="5" data-expected-x="0" data-expected-y="0"></div> + <div class="abs" style="grid-column: 2 / 3; background: orange;" data-expected-width="60" data-expected-height="5" data-expected-x="20" data-expected-y="0"></div> + <div class="abs" style="grid-column: 3 / 4; background: yellow;" data-expected-width="0" data-expected-height="5" data-expected-x="40" data-expected-y="0"></div> + <div class="abs" style="grid-column: 4 / 5; background: green;" data-expected-width="70" data-expected-height="5" data-expected-x="60" data-expected-y="0"></div> +</div> + +</body> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-repeat-positioned-container-001-ref.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-repeat-positioned-container-001-ref.html new file mode 100644 index 00000000000..a017563aa36 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-repeat-positioned-container-001-ref.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<link href="/css/support/grid.css" rel="stylesheet"/> +<style> + +.grid { + width: 100px; + grid: repeat(5, 20px) / repeat(4, 25px); + justify-content: start; + align-content: start; +} + +.item { + background: green; +} +</style> + +<p>Test passes if you get a grid with 5 rows of 20px and 4 columns of 25px.</p> + +<pre id="log">grid: 20px 20px 20px 20px 20px / 25px 25px 25px 25px;</pre> + +<div class="wrapper"> + <div id="grid" class="grid"> + <div class="item" style="grid-area: 1 / 1;"></div> + <div class="item" style="grid-area: 2 / 2;"></div> + <div class="item" style="grid-area: 3 / 3;"></div> + <div class="item" style="grid-area: 4 / 4;"></div> + <div class="item" style="grid-row: 5; grid-column: 1 / -1;"></div> + </div> +</div> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-repeat-positioned-container-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-repeat-positioned-container-001.html new file mode 100644 index 00000000000..309ad856712 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-auto-repeat-positioned-container-001.html @@ -0,0 +1,50 @@ +<!DOCTYPE html> +<title>CSS Grid: auto-repeat tracks on a positioned grid container.</title> +<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com"/> +<link rel="issue" href="https://crbug.com/624301"/> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#repeat-notation"/> +<link rel="match" href="grid-auto-repeat-positioned-container-001-ref.html"/> +<meta name="assert" content="Checks that auto repeat tracks are properly computed for a positioned grid container with a definite width and height."/> +<link href="/css/support/grid.css" rel="stylesheet"/> +<style> +.wrapper { + position: relative; + width: 100px; + height: 100px; +} + +.grid { + position: absolute; + left: 0; right: 0; top: 0; bottom: 0; + grid: repeat(auto-fill, 20px) / repeat(auto-fill, 25px); + justify-content: start; + align-content: start; +} + +.item { + background: green; +} +</style> + +<p>Test passes if you get a grid with 5 rows of 20px and 4 columns of 25px.</p> + +<pre id="log"></pre> + +<div class="wrapper"> + <div id="grid" class="grid"> + <div class="item" style="grid-area: 1 / 1;"></div> + <div class="item" style="grid-area: 2 / 2;"></div> + <div class="item" style="grid-area: 3 / 3;"></div> + <div class="item" style="grid-area: 4 / 4;"></div> + <div class="item" style="grid-row: 5; grid-column: 1 / -1;"></div> + </div> +</div> + +<script> + var log = document.getElementById("log"); + + var grid = document.getElementById("grid"); + var computedStyle = getComputedStyle(grid); + + log.innerHTML = "grid: " + computedStyle.getPropertyValue("grid-template-rows") + " / " + computedStyle.getPropertyValue("grid-template-columns") + ";"; +</script> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-change-intrinsic-size-with-auto-repeat-tracks-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-change-intrinsic-size-with-auto-repeat-tracks-001.html new file mode 100644 index 00000000000..437ad818799 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-change-intrinsic-size-with-auto-repeat-tracks-001.html @@ -0,0 +1,151 @@ +<!DOCTYPE html> +<title>CSS Grid: auto-repeat tracks and intrinsic sizes.</title> +<link rel="author" title="Sergio Villar" href="mailto:svillar@igalia.com"/> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#repeat-notation"/> +<meta name="assert" content="Test ensure that grids properly recompute the number of auto repeat tracks when the min|max-content contributions of grid items changed."/> +<link rel="issue" href="https://crbug.com/621517"/> +<link rel="issue" href="https://crbug.com/633474"/> +<link href="/css/support/grid.css" rel="stylesheet"/> +<link href="/css/support/width-keyword-classes.css" rel="stylesheet"/> +<style> +.grid { + border: 2px solid black; + position: relative; + min-width: 30px; + + grid-auto-columns: 20px; + + padding-top: 10px; + margin-bottom: 10px; +} + +.abs { height: 5px; position: absolute; width: 100%; } + +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<script> +function setGridTemplate(id, gridTemplateRows, gridTemplateColumns) +{ + var gridElement = document.getElementById(id); + gridElement.style.gridTemplateRows = gridTemplateRows; + gridElement.style.gridTemplateColumns = gridTemplateColumns; +} + +function setItemSize(id, width, height) +{ + var gridElement = document.getElementById(id); + gridElement.style.width = width; + gridElement.style.height = height; +} + +function testGridDefinitions(gridItemsData) +{ + var length = gridItemsData.length; + for (i = 0; i < length; ++i) { + var item = document.getElementById(gridItemsData[i].id); + item.setAttribute("data-expected-width", gridItemsData[i].width); + item.setAttribute("data-expected-height", gridItemsData[i].height); + item.setAttribute("data-offset-x", gridItemsData[i].x); + item.setAttribute("data-offset-y", gridItemsData[i].y); + } + + checkLayout(".grid", false); +} + +function testChangingGridDefinitions() +{ + setGridTemplate('grid1', 'none', 'repeat(auto-fill, 20px) minmax(min-content, 40px)'); + + setItemSize('item', '100px', '30px'); + testGridDefinitions([ + { 'id': 'item', 'width': '100', 'height': '30', 'x': '0', 'y': '10' }, + { 'id': 'a1', 'width': '20', 'height': '5', 'x': '0', 'y': '0' }, + { 'id': 'a2', 'width': '20', 'height': '5', 'x': '20', 'y': '0' }, + { 'id': 'a3', 'width': '20', 'height': '5', 'x': '40', 'y': '0' }, + { 'id': 'a4', 'width': '40', 'height': '5', 'x': '60', 'y': '0' } + ]); + + setItemSize('item', '80px', '30px'); + testGridDefinitions([ + { 'id': 'item', 'width': '80', 'height': '30', 'x': '0', 'y': '10' }, + { 'id': 'a1', 'width': '20', 'height': '5', 'x': '0', 'y': '0' }, + { 'id': 'a2', 'width': '20', 'height': '5', 'x': '20', 'y': '0' }, + { 'id': 'a3', 'width': '40', 'height': '5', 'x': '40', 'y': '0' }, + { 'id': 'a4', 'width': '0', 'height': '5', 'x': '80', 'y': '0' } + ]); + + setItemSize('item', '15px', '30px'); + testGridDefinitions([ + { 'id': 'item', 'width': '15', 'height': '30', 'x': '0', 'y': '10' }, + { 'id': 'a1', 'width': '20', 'height': '5', 'x': '0', 'y': '0' }, + { 'id': 'a2', 'width': '40', 'height': '5', 'x': '20', 'y': '0' }, + { 'id': 'a3', 'width': '0', 'height': '5', 'x': '60', 'y': '0' }, + { 'id': 'a4', 'width': '60', 'height': '5', 'x': '0', 'y': '0' } + ]); + + setItemSize('item', '120px', '30px'); + testGridDefinitions([ + { 'id': 'item', 'width': '120', 'height': '30', 'x': '0', 'y': '10' }, + { 'id': 'a1', 'width': '20', 'height': '5', 'x': '0', 'y': '0' }, + { 'id': 'a2', 'width': '20', 'height': '5', 'x': '20', 'y': '0' }, + { 'id': 'a3', 'width': '20', 'height': '5', 'x': '40', 'y': '0' }, + { 'id': 'a4', 'width': '20', 'height': '5', 'x': '60', 'y': '0' } + ]); + + var grid = document.getElementById('grid1'); + grid.className = grid.className.replace('max-content', 'min-content'); + + setItemSize('item', '100px', '30px'); + testGridDefinitions([ + { 'id': 'item', 'width': '100', 'height': '30', 'x': '0', 'y': '10' }, + { 'id': 'a1', 'width': '20', 'height': '5', 'x': '0', 'y': '0' }, + { 'id': 'a2', 'width': '20', 'height': '5', 'x': '20', 'y': '0' }, + { 'id': 'a3', 'width': '20', 'height': '5', 'x': '40', 'y': '0' }, + { 'id': 'a4', 'width': '40', 'height': '5', 'x': '60', 'y': '0' } + ]); + + setItemSize('item', '80px', '30px'); + testGridDefinitions([ + { 'id': 'item', 'width': '80', 'height': '30', 'x': '0', 'y': '10' }, + { 'id': 'a1', 'width': '20', 'height': '5', 'x': '0', 'y': '0' }, + { 'id': 'a2', 'width': '20', 'height': '5', 'x': '20', 'y': '0' }, + { 'id': 'a3', 'width': '40', 'height': '5', 'x': '40', 'y': '0' }, + { 'id': 'a4', 'width': '0', 'height': '5', 'x': '80', 'y': '0' } + ]); + + setItemSize('item', '15px', '30px'); + testGridDefinitions([ + { 'id': 'item', 'width': '15', 'height': '30', 'x': '0', 'y': '10' }, + { 'id': 'a1', 'width': '20', 'height': '5', 'x': '0', 'y': '0' }, + { 'id': 'a2', 'width': '10', 'height': '5', 'x': '20', 'y': '0' }, + { 'id': 'a3', 'width': '0', 'height': '5', 'x': '30', 'y': '0' }, + { 'id': 'a4', 'width': '30', 'height': '5', 'x': '0', 'y': '0' } + ]); + + setItemSize('item', '120px', '30px'); + testGridDefinitions([ + { 'id': 'item', 'width': '120', 'height': '30', 'x': '0', 'y': '10' }, + { 'id': 'a1', 'width': '20', 'height': '5', 'x': '0', 'y': '0' }, + { 'id': 'a2', 'width': '20', 'height': '5', 'x': '20', 'y': '0' }, + { 'id': 'a3', 'width': '20', 'height': '5', 'x': '40', 'y': '0' }, + { 'id': 'a4', 'width': '20', 'height': '5', 'x': '60', 'y': '0' } + ]); + + done(); +} + +window.addEventListener("load", testChangingGridDefinitions, false); +</script> + +<div>This test checks that changing the min|max-content contributions of grid items properly recomputes both track sizes and grid positions in grids with auto repeat tracks.</div> +<div id="log"></div> + +<div id="grid1" class="grid max-content"> + <div id="item" style="grid-column: 1 / -1; background: cyan;"></div> + <div id="a1" class="abs" style="grid-column: 1 / 2; background: purple;"></div> + <div id="a2" class="abs" style="grid-column: 2 / 3; background: orange;"></div> + <div id="a3" class="abs" style="grid-column: 3 / 4; background: yellow;"></div> + <div id="a4" class="abs" style="grid-column: 4 / 5; background: magenta;"></div> +</div> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-content-alignment-and-self-alignment-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-content-alignment-and-self-alignment-001.html new file mode 100644 index 00000000000..cd79210f10d --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-definition/grid-content-alignment-and-self-alignment-001.html @@ -0,0 +1,378 @@ +<!DOCTYPE html> +<title>CSS Grid Layout Test: content distribution alignment and self alignment.</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-justify-content"> +<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-self-property"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#auto-tracks"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=249451"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=376823"> +<link rel="stylesheet" href="/fonts/ahem.css"> +<link rel="stylesheet" href="/css/support/alignment.css"> +<link rel="stylesheet" href="/css/support/grid.css"> +<meta name="assert" content="Test that content distribution alignment works fine in combination with self alignment and items in just one cell." /> + +<style> +.grid { + grid-template-columns: 200px 100px; + grid-template-rows: 100px 50px; + width: 500px; + height: 350px; + position: relative; + font: 10px/1 Ahem; +} + +.gridGaps { + grid-gap: 10px 20px; +} +</style> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<script type="text/javascript"> + setup({ explicit_done: true }); +</script> + +<body onload="document.fonts.ready.then(() => { checkLayout('.grid'); })"> + +<div id="log"></div> + +<p>direction: LTR | distribution: 'space-between' | self-alignment: center</p> +<div class="grid contentSpaceBetween itemsCenter"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="95" data-offset-y="45" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="445" data-offset-y="45" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="95" data-offset-y="320" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="445" data-offset-y="320" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: LTR | distribution: 'space-between' | self-alignment: end</p> +<div class="grid contentSpaceBetween itemsEnd"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="190" data-offset-y="90" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="490" data-offset-y="90" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="190" data-offset-y="340" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="490" data-offset-y="340" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: LTR | distribution: 'space-around' | self-alignment: center</p> +<div class="grid contentSpaceAround itemsCenter"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="145" data-offset-y="95" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="395" data-offset-y="95" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="145" data-offset-y="270" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="395" data-offset-y="270" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: LTR | distribution: 'space-around' | self-alignment: end</p> +<div class="grid contentSpaceAround itemsEnd"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="240" data-offset-y="140" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="440" data-offset-y="140" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="240" data-offset-y="290" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="440" data-offset-y="290" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: LTR | distribution: 'space-evenly' | self-alignment: center</p> +<div class="grid contentSpaceEvenly itemsCenter"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="162" data-offset-y="112" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="378" data-offset-y="112" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="162" data-offset-y="253" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="378" data-offset-y="253" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: LTR | distribution: 'space-evenly' | self-alignment: end</p> +<div class="grid contentSpaceEvenly itemsEnd"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="257" data-offset-y="157" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="423" data-offset-y="157" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="257" data-offset-y="273" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="423" data-offset-y="273" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: LTR | grid-gap: 10px 20px | distribution: 'space-between' | self-alignment: center</p> +<div class="grid gridGaps contentSpaceBetween itemsCenter"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="95" data-offset-y="45" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="445" data-offset-y="45" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="95" data-offset-y="320" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="445" data-offset-y="320" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: LTR | grid-gap: 10px 20px | distribution: 'space-between' | self-alignment: end</p> +<div class="grid gridGaps contentSpaceBetween itemsEnd"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="190" data-offset-y="90" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="490" data-offset-y="90" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="190" data-offset-y="340" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="490" data-offset-y="340" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: LTR | grid-gap: 10px 20px | distribution: 'space-around' | self-alignment: center</p> +<div class="grid gridGaps contentSpaceAround itemsCenter"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="140" data-offset-y="93" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="400" data-offset-y="93" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="140" data-offset-y="273" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="400" data-offset-y="273" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: LTR | grid-gap: 10px 20px | distribution: 'space-around' | self-alignment: end</p> +<div class="grid gridGaps contentSpaceAround itemsEnd"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="235" data-offset-y="138" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="445" data-offset-y="138" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="235" data-offset-y="293" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="445" data-offset-y="293" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: LTR | grid-gap: 10px 20px | distribution: 'space-evenly' | self-alignment: center</p> +<div class="grid gridGaps contentSpaceEvenly itemsCenter"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="155" data-offset-y="108" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="385" data-offset-y="108" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="155" data-offset-y="257" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="385" data-offset-y="257" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: LTR | grid-gap: 10px 20px | distribution: 'space-evenly' | self-alignment: end</p> +<div class="grid gridGaps contentSpaceEvenly itemsEnd"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="250" data-offset-y="153" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="430" data-offset-y="153" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="250" data-offset-y="277" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="430" data-offset-y="277" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<!-- RTL direction. --> + +<p>direction: RTL | distribution: 'space-between' | self-alignment: center</p> +<div class="grid directionRTL contentSpaceBetween itemsCenter"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="395" data-offset-y="45" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="45" data-offset-y="45" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="395" data-offset-y="320" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="45" data-offset-y="320" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: RTL | distribution: 'space-between' | self-alignment: end</p> +<div class="grid directionRTL contentSpaceBetween itemsEnd"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="300" data-offset-y="90" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="0" data-offset-y="90" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="300" data-offset-y="340" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="0" data-offset-y="340" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: RTL | distribution: 'space-around' | self-alignment: center</p> +<div class="grid directionRTL contentSpaceAround itemsCenter"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="345" data-offset-y="95" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="95" data-offset-y="95" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="345" data-offset-y="270" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="95" data-offset-y="270" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: RTL | distribution: 'space-around' | self-alignment: end</p> +<div class="grid directionRTL contentSpaceAround itemsEnd"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="250" data-offset-y="140" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="50" data-offset-y="140" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="250" data-offset-y="290" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="50" data-offset-y="290" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: RTL | distribution: 'space-evenly' | self-alignment: center</p> +<div class="grid directionRTL contentSpaceEvenly itemsCenter"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="328" data-offset-y="112" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="112" data-offset-y="112" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="328" data-offset-y="253" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="112" data-offset-y="253" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: RTL | distribution: 'space-evenly' | self-alignment: end</p> +<div class="grid directionRTL contentSpaceEvenly itemsEnd"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="233" data-offset-y="157" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="67" data-offset-y="157" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="233" data-offset-y="273" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="67" data-offset-y="273" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: RTL | grid-gap: 10px 20px | distribution: 'space-between' | self-alignment: center</p> +<div class="grid directionRTL gridGaps contentSpaceBetween itemsCenter"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="395" data-offset-y="45" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="45" data-offset-y="45" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="395" data-offset-y="320" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="45" data-offset-y="320" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: RTL | grid-gap: 10px 20px | distribution: 'space-between' | self-alignment: end</p> +<div class="grid directionRTL gridGaps contentSpaceBetween itemsEnd"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="300" data-offset-y="90" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="0" data-offset-y="90" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="300" data-offset-y="340" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="0" data-offset-y="340" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: RTL | grid-gap: 10px 20px | distribution: 'space-around' | self-alignment: center</p> +<div class="grid directionRTL gridGaps contentSpaceAround itemsCenter"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="350" data-offset-y="93" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="90" data-offset-y="93" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="350" data-offset-y="273" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="90" data-offset-y="273" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: RTL | grid-gap: 10px 20px | distribution: 'space-around' | self-alignment: end</p> +<div class="grid directionRTL gridGaps contentSpaceAround itemsEnd"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="255" data-offset-y="138" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="45" data-offset-y="138" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="255" data-offset-y="293" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="45" data-offset-y="293" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: RTL | grid-gap: 10px 20px | distribution: 'space-evenly' | self-alignment: center</p> +<div class="grid directionRTL gridGaps contentSpaceEvenly itemsCenter"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="335" data-offset-y="108" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="105" data-offset-y="108" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="335" data-offset-y="257" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="105" data-offset-y="257" data-expected-width="10" data-expected-height="10">X</div> +</div> + +<p>direction: RTL | grid-gap: 10px 20px | distribution: 'space-evenly' | self-alignment: end</p> +<div class="grid directionRTL gridGaps contentSpaceEvenly itemsEnd"> + <!-- Dummy DIVs to help checking the result visually. --> + <div class="firstRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="firstRowSecondColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowFirstColumn justifySelfStretch alignSelfStretch"></div> + <div class="secondRowSecondColumn justifySelfStretch alignSelfStretch"></div> + + <div class="firstRowFirstColumn" data-offset-x="240" data-offset-y="153" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowSecondColumn" data-offset-x="60" data-offset-y="153" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowFirstColumn" data-offset-x="240" data-offset-y="277" data-expected-width="10" data-expected-height="10">X</div> + <div class="secondRowSecondColumn" data-offset-x="60" data-offset-y="277" data-expected-width="10" data-expected-height="10">X</div> +</div> + +</body> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-items/grid-item-margins-and-writing-modes-001-ref.html b/tests/wpt/web-platform-tests/css/css-grid/grid-items/grid-item-margins-and-writing-modes-001-ref.html new file mode 100644 index 00000000000..86553ef6f40 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-items/grid-item-margins-and-writing-modes-001-ref.html @@ -0,0 +1,46 @@ +<!DOCTYPE html> +<html> +<link href="/css/support/grid.css" rel="stylesheet"> +<link href="/fonts/ahem.css" rel="stylesheet"/> +<style> +.block { + background-color: grey; + width: 80px; + height: 80px; + position: relative; + margin-bottom: 5px; + border: 1px solid; +} + +.item { + font: 15px/1 Ahem; + background-color: green; + width: 40px; + height: 20px; + margin: 4px 8px 12px 16px; +} +</style> + +<body> + <div class="block"> + <div class="item">X</div> + </div> + <div class="block verticalRL"> + <div class="item">X</div> + </div> + <div class="block verticalLR"> + <div class="item">X</div> + </div> + <div class="block directionRTL"> + <div class="item">X</div> + </div> + <div class="block directionRTL verticalRL"> + <div class="item">X</div> + </div> + <div class="block directionRTL verticalLR"> + <div class="item">X</div> + </div> +</body> + +</body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-items/grid-item-margins-and-writing-modes-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-items/grid-item-margins-and-writing-modes-001.html new file mode 100644 index 00000000000..5209940a969 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-items/grid-item-margins-and-writing-modes-001.html @@ -0,0 +1,61 @@ +<!DOCTYPE html> +<html> +<title>CSS Grid: Grid items and logical margins</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-template-columns"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-column"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-row"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#grid-items"> +<link rel="match" href="grid-item-margins-and-writing-modes-001-ref.html"> +<meta name="assert" content="This test ensures that the border, margin, and padding +combining with RTL direction and different writing-modes generate the proper layout."/> +<link href="/css/support/grid.css" rel="stylesheet"> +<link href="/fonts/ahem.css" rel="stylesheet"/> +<style> +.grid { + grid-template-columns: 80px; +} + +.block { + background-color: grey; + width: 80px; + height: 80px; + position: relative; + margin-bottom: 5px; + border: 1px solid; +} + +.item { + font: 15px/1 Ahem; + background-color: green; + grid-column: 1 / 2; + grid-row: 1 / 2; + width: 40px; + height: 20px; + margin: 4px 8px 12px 16px; +} +</style> + +<body> + <div class="grid block"> + <div class="item">X</div> + </div> + <div class="grid block verticalRL"> + <div class="item">X</div> + </div> + <div class="grid block verticalLR"> + <div class="item">X</div> + </div> + <div class="grid block directionRTL"> + <div class="item">X</div> + </div> + <div class="grid block directionRTL verticalRL"> + <div class="item">X</div> + </div> + <div class="grid block directionRTL verticalLR"> + <div class="item">X</div> + </div> +</body> + +</body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-items/remove-svg-grid-item-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-items/remove-svg-grid-item-001.html new file mode 100644 index 00000000000..5e196c82c64 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-items/remove-svg-grid-item-001.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<title>CSS Grid Layout Test: Remove a first child in grid items</title> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#grid-item"> +<link rel="stylesheet" href="/css/support/grid.css"/> +<link rel="match" href="../reference/grid-item-script-001-ref.html"> +<meta name="assert" content="This test ensures that removing a first child element in grid items doesn't crash."> +<link rel="stylesheet" href="/css/support/grid.css"/> +<div class="grid"> + <svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='190'> + <polygon points='100,10 40,180 190,60 10,60 160,180' style='fill:lime;stroke:purple;stroke-width:5;fill-rule:evenodd;'> + </svg> +</div> + +<script> + var grid = document.getElementsByClassName("grid")[0]; + grid.offsetTop; + while (grid.firstChild) + grid.removeChild(grid.firstChild); + grid.offsetTop; + grid.innerHTML = "Test passes if it doesn't crash."; +</script> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-items/whitespace-in-grid-item-001-ref.html b/tests/wpt/web-platform-tests/css/css-grid/grid-items/whitespace-in-grid-item-001-ref.html new file mode 100644 index 00000000000..1531d98a64f --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-items/whitespace-in-grid-item-001-ref.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<link href="/css/support/grid.css" rel="stylesheet"> +<style> + .item { + height: 100%; + width: 30px; + background: salmon; + } +</style> +<body> + <p>This test passes if it has the same output than the reference. As spec states that child text runs containing only white space should not rendered (just as if its text nodes were display:none).</p> + <div class="grid"> + <div class="item"></div> + </div> +</body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-items/whitespace-in-grid-item-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-items/whitespace-in-grid-item-001.html new file mode 100644 index 00000000000..f79baab6f05 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-items/whitespace-in-grid-item-001.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<html> +<title>CSS Grid : Whitespace in grid item</title> +<link rel="author" title="Christian Biesinger" href="mailto:cbiesinger@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/css-grid/#grid-items"> +<link rel="match" href="whitespace-in-grid-item-001-ref.html"> +<link rel="help" href="https://codereview.chromium.org/16888008"> +<meta name="assert" content="Grid items shouldn't be created for white spaces."/> +<link href="/css/support/grid.css" rel="stylesheet"> +<style> + .grid { + white-space: pre; + } + .item { + height: 100%; + width: 30px; + background: salmon; + } +</style> +<body> + <p>This test passes if it has the same output than the reference. As spec states that child text runs containing only white space should not rendered (just as if its text nodes were display:none).</p> + <div class="grid"> + + <div class="item"></div> 	 + </div> +</body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-model/fixed-width-intrinsic-width-should-exclude-scrollbar-001.html b/tests/wpt/web-platform-tests/css/css-grid/grid-model/fixed-width-intrinsic-width-should-exclude-scrollbar-001.html new file mode 100644 index 00000000000..26b8f5e01dd --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-model/fixed-width-intrinsic-width-should-exclude-scrollbar-001.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html> +<title>CSS Grid: intrinsic width of fixed-width grid items.</title> +<link rel="author" title="Sunil Ratnu" href="mailto:sunil.ratnu@samsung.com"/> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#overflow"/> +<meta name="assert" content="This test ensures that scrollbar width is not accounted for fixed-width grid items' intrinsic width."/> +<link href="/css/support/grid.css" rel="stylesheet"/> +<style> +.grid { + grid-template-columns: 400px 500px; + grid-template-rows: 200px 300px; +} + +.gridItemScrollOverflow { + width: 50px; + height: 50px; + overflow: scroll; +} + +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<body onload="checkLayout('.grid')"> + +<div class="grid"> + <div class="firstRowFirstColumn gridItemScrollOverflow" data-expected-width="50" data-expected-height="50"></div> + <div class="firstRowSecondColumn gridItemScrollOverflow" data-expected-width="50" data-expected-height="50"></div> + <div class="secondRowFirstColumn gridItemScrollOverflow" data-expected-width="50" data-expected-height="50"></div> + <!-- Grid item itself being a grid container--> + <div class="grid secondRowSecondColumn gridItemScrollOverflow" data-expected-width="50" data-expected-height="50"></div> +</div> + +</body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-floats-no-intrude-002-ref.html b/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-floats-no-intrude-002-ref.html new file mode 100644 index 00000000000..070980ed27c --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-floats-no-intrude-002-ref.html @@ -0,0 +1,52 @@ +<!DOCTYPE html> +<html> +<head> +<link rel="stylesheet" href="/css/support/grid.css"> +<style> +.cell { + width: 50px; + height: auto; + min-height: 50px +} + +.invisibleFont { + color: lime; +} + +.floatLeft { + float: left; +} + +.clearLeft { + clear: left; +} + +.relative { + position: relative; +} +</style> +</head> + +<body> + +<div>This test checks that grid item sets a new formatting context for its content, preventing any 'float' protruding content on the adjoining grid item ('Float' text shouldn't overflow the first row).</div> + +<div> + <div class="cell relative floatLeft firstRowFirstColumn"> + <div>Float</div> + <div>Float</div> + <div>Float</div> + <div>Float</div> + </div> + <div class="cell floatLeft firstRowSecondColumn"> + <div class="invisibleFont">Float</div> + <div class="invisibleFont">Float</div> + <div class="invisibleFont">Float</div> + <div class="invisibleFont">Float</div> + </div> + <div class="cell floatLeft clearLeft secondRowFirstColumn"></div> + <div class="cell floatLeft secondRowSecondColumn"></div> +</div> + +</body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-floats-no-intrude-002.html b/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-floats-no-intrude-002.html new file mode 100644 index 00000000000..9c26e021050 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-floats-no-intrude-002.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<html> +<head> +<title>CSS Grid Layout Test: floats do not protrude content onto grid items</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#grid-containers"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=430100"> +<link rel="match" href="grid-floats-no-intrude-002-ref.html"> +<link rel="stylesheet" href="/css/support/grid.css"> +<link rel="stylesheet" href="/css/support/width-keyword-classes.css"> +<meta name="assert" content="Test that a grid item sets a new formatting context for its content, preventing any 'float' protruding content on the adjoining grid item." /> + +<style> +.grid { + grid-auto-columns: minmax(50px, max-content); + grid-auto-rows: minmax(50px, max-content); +} + +.floatChild { + float: left; + clear: both; +} +</style> +</head> + +<body> + +<div>This test checks that grid item sets a new formatting context for its content, preventing any 'float' protruding content on the adjoining grid item ('Float' text shouldn't overflow the first row).</div> + +<div class="grid fit-content"> + <div class="firstRowFirstColumn"> + <div class="floatChild">Float</div> + <div class="floatChild">Float</div> + <div class="floatChild">Float</div> + <div class="floatChild">Float</div> + </div> + <div class="firstRowSecondColumn"></div> + <div class="secondRowFirstColumn"></div> + <div class="secondRowSecondColumn"></div> +</div> + +</body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-margins-no-collapse-002-ref.html b/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-margins-no-collapse-002-ref.html new file mode 100644 index 00000000000..ce56a566456 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-margins-no-collapse-002-ref.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<link rel="stylesheet" href="/css/support/grid.css"> + +<div>This test checks that grid item's margins do not collapse with its content's margins (single margin in the first row and double between subsequent).</div> + +<div style="float: left"> + <div><p>XXXXX</p></div> + <div style="float:left; margin:20px 0px;">XXXXX</div> + <div><p style="float:left; clear:both;">XXXXX</p></div> +</div> diff --git a/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-margins-no-collapse-002.html b/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-margins-no-collapse-002.html new file mode 100644 index 00000000000..f644a6fb53c --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/grid-model/grid-margins-no-collapse-002.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<title>CSS Grid Layout Test: grid items not collapsing</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#grid-containers"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=430100"> +<link rel="match" href="grid-margins-no-collapse-002-ref.html"> +<link rel="stylesheet" href="/css/support/grid.css"> +<meta name="assert" content="Test that grid item's margins do not collapse with its content's margins." /> + +<div>This test checks that grid item's margins do not collapse with its content's margins (single margin in the first row and double between subsequent).</div> + +<div style="display: grid;"> + <div><p>XXXXX</p></div> + <div style="margin:20px 0px;">XXXXX</div> + <div><p>XXXXX</p></div> +</div> diff --git a/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/flex-and-intrinsic-sizes-001.html b/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/flex-and-intrinsic-sizes-001.html new file mode 100644 index 00000000000..5144450dd8c --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/flex-and-intrinsic-sizes-001.html @@ -0,0 +1,82 @@ +<!DOCTYPE html> +<title>CSS Grid: track sizing algo with size restrictions and intrinsic sizes.</title> +<link rel="author" title="Sergio Villar" href="mailto:svillar@igalia.com"/> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#layout-algorithm"/> +<meta name="assert" content="This test ensures that fr tracks are properly sized whenever grid has intrinsic sizes."/> +<link rel="issue" href="https://crbug.com/423743"/> +<link href="/css/support/width-keyword-classes.css" rel="stylesheet"/> +<link href="/css/support/height-keyword-classes.css" rel="stylesheet"/> +<link href="/css/support/grid.css" rel="stylesheet"/> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> + +<style> +.container { + width: 100px; + height: 100px; +} + +.grid { + grid-template-columns: 1fr; + grid-template-rows: 1fr; +} + +div { font: 10px/1 Ahem; } +</style> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<script type="text/javascript"> + setup({ explicit_done: true }); +</script> + +<body onload="document.fonts.ready.then(() => { checkLayout('.grid'); })"> + +<div class="container"> + <div class="grid" data-expected-width="100" data-expected-height="10"> + <div>XXX XXX</div> + </div> +</div> + +<div class="container"> + <div class="grid min-content" data-expected-width="30" data-expected-height="20"> + <div>XXX XXX</div> + </div> +</div> + +<div class="container"> + <div class="grid max-content" data-expected-width="70" data-expected-height="10"> + <div>XXX XXX</div> + </div> +</div> + +<div class="container"> + <div class="grid fit-content" data-expected-width="70" data-expected-height="10"> + <div>XXX XXX</div> + </div> +</div> + +<div class="min-content"> + <div class="grid" data-expected-width="40" data-expected-height="50"> + <div>XXX XXXX XX X XX XXX</div> + </div> +</div> + +<div class="grid container" data-expected-width="100" data-expected-height="100"> + <div style="display: grid; grid-template-columns: 3fr; grid-template-rows: 2fr;" data-expected-width="100" data-expected-height="100"> + <div>XXX XXXX XX X XX XXX</div> + </div> +</div> + +<div class="grid" style="grid; grid: 1fr 2fr / 2fr 1fr; width: 300px; height: 300px;" data-expected-width="300" data-expected-height="300"> + <div class="firstRowFirstColumn" style="display: grid; grid: 1fr 3fr / 3fr 1fr;" data-expected-width="200" data-expected-height="100"> + <div style="border: 2px solid magenta;" data-expected-width="150" data-expected-height="25">XXXX</div> + <div class="secondRowSecondColumn" style="border: 2px solid cyan;" data-expected-width="50" data-expected-height="75">XXXX XX XX</div> + </div> + <div class="secondRowSecondColumn" style="display: grid; grid: 3fr 4fr / 4fr 3fr;" data-expected-width="100" data-expected-height="200"> + <div style="border: 2px solid lime;" data-expected-width="56" data-expected-height="86">XXX XX X</div> + <div class="secondRowSecondColumn" style="border: 2px solid navy;" data-expected-width="44" data-expected-height="114">XXXX XXX XXXX XXX XXXX</div> + </div> +</div> + +</body> diff --git a/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/flex-sizing-columns-min-max-width-001.html b/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/flex-sizing-columns-min-max-width-001.html new file mode 100644 index 00000000000..6b269e5258f --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/flex-sizing-columns-min-max-width-001.html @@ -0,0 +1,94 @@ +<!DOCTYPE HTML> +<title>CSS Grid Layout Test: min and max size when computing the flex fraction</title> +<link rel="author" title="Sergio Villar" href="mailto:svillar@igalia.com"/> +<link rel="help" href="https://drafts.csswg.org/css-grid/#algo-flex-tracks"/> +<link rel="issue" href="https://bugs.chromium.org/p/chromium/issues/detail?id=660690"/> +<link href="/css/support/grid.css" rel="stylesheet"/> +<link href="/css/support/width-keyword-classes.css" rel="stylesheet"> +<meta name="assert" content="This test ensures that minimum and maximum sizes are used to compute the flex fraction for indefinite free spaces."/> +<style> +.grid { + margin: 3px; + grid: 50px / minmax(10px, 1fr) minmax(10px, 4fr); + grid-column-gap: 33px; + border: 5px dashed; + padding: 2px; +} + +.float { float: left; } + +.item:nth-child(1) { background-color: purple; } +.item:nth-child(2) { background-color: blue; } +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<body onload="checkLayout('.grid')"> + +<p>This test PASS if all the grids in the same row look the same.</p> + +<div class="grid float" style="max-width: 70px" data-expected-height="64" data-expected-width="84"> + <div class="item" data-expected-height="50" data-expected-width="10"></div> + <div class="item" data-expected-height="50" data-expected-width="27"></div> +</div> +<div class="grid float" style="min-width: 70px; max-width: 60px" data-expected-height="64" data-expected-width="84"> + <div class="item" data-expected-height="50" data-expected-width="10"></div> + <div class="item" data-expected-height="50" data-expected-width="27"></div> +</div> +<div class="grid float" style="width: 70px" data-expected-height="64" data-expected-width="84"> + <div class="item" data-expected-height="50" data-expected-width="10"></div> + <div class="item" data-expected-height="50" data-expected-width="27"></div> +</div> + +<br clear="all"> + +<div class="grid float" style="min-width: 108px" data-expected-height="64" data-expected-width="122"> + <div class="item" data-expected-height="50" data-expected-width="15"></div> + <div class="item" data-expected-height="50" data-expected-width="60"></div> +</div> +<div class="grid float" style="min-width: 108px; max-width: 60px" data-expected-height="64" data-expected-width="122"> + <div class="item" data-expected-height="50" data-expected-width="15"></div> + <div class="item" data-expected-height="50" data-expected-width="60"></div> +</div> +<div class="grid float" style="width: 108px" data-expected-height="64" data-expected-width="122"> + <div class="item" data-expected-height="50" data-expected-width="15"></div> + <div class="item" data-expected-height="50" data-expected-width="60"></div> +</div> + +<br clear="all"> + +<div class="grid float min-width-max-content" data-expected-height="64" data-expected-width="97"> + <div class="item" data-expected-height="50" data-expected-width="10"></div> + <div class="item" data-expected-height="50" data-expected-width="40"></div> +</div> +<div class="grid float min-width-max-content max-width-min-content" data-expected-height="64" data-expected-width="97"> + <div class="item" data-expected-height="50" data-expected-width="10"></div> + <div class="item" data-expected-height="50" data-expected-width="40"></div> +</div> +<div class="grid float max-content" data-expected-height="64" data-expected-width="97"> + <div class="item" data-expected-height="50" data-expected-width="10"></div> + <div class="item" data-expected-height="50" data-expected-width="40"></div> +</div> + +<br clear="all"> + +<div class="float min-content"> + <div class="grid min-width-max-content" data-expected-height="64" data-expected-width="97"> + <div class="item" data-expected-height="50" data-expected-width="10"></div> + <div class="item" data-expected-height="50" data-expected-width="40"></div> + </div> +</div> +<div class="float max-content"> + <div class="grid min-width-max-content max-width-min-content" data-expected-height="64" data-expected-width="97"> + <div class="item" data-expected-height="50" data-expected-width="10"></div> + <div class="item" data-expected-height="50" data-expected-width="40"></div> + </div> +</div> +<div class="float fit-content"> + <div class="grid max-content" data-expected-height="64" data-expected-width="97"> + <div class="item" data-expected-height="50" data-expected-width="10"></div> + <div class="item" data-expected-height="50" data-expected-width="40"></div> + </div> +</div> + +</body> diff --git a/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/flex-sizing-rows-min-max-height-001.html b/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/flex-sizing-rows-min-max-height-001.html new file mode 100644 index 00000000000..0789e405301 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/flex-sizing-rows-min-max-height-001.html @@ -0,0 +1,96 @@ +<!DOCTYPE HTML> +<title>CSS Grid Layout Test: min and max height when computing the flex row</title> +<link rel="author" title="Sergio Villar" href="mailto:svillar@igalia.com"/> +<link rel="help" href="https://drafts.csswg.org/css-grid/#algo-flex-tracks"/> +<link rel="issue" href="https://bugs.chromium.org/p/chromium/issues/detail?id=660690"/> +<link href="/css/support/grid.css" rel="stylesheet"/> +<link href="/css/support/height-keyword-classes.css" rel="stylesheet"> +<meta name="assert" content="This test ensures that minimum and maximum heights are used to compute the flex fraction for grid rows."/> +<style> +.grid { + margin: 3px; + grid: minmax(10px, 1fr) minmax(10px, 4fr) / 50px; + grid-row-gap: 33px; + border: 5px dashed; + padding: 2px; +} + +.float { float: left; } + +.item:nth-child(1) { background-color: purple; } +.item:nth-child(2) { background-color: blue; } +</style> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<body onload="checkLayout('.grid')"> +<div id="log"></div> + +<p>This test PASS if all the grids in the same row look the same.</p> + +<div class="grid float" style="max-height: 70px" data-expected-width="64" data-expected-height="84"> + <div class="item" data-expected-width="50" data-expected-height="10"></div> + <div class="item" data-expected-width="50" data-expected-height="27"></div> +</div> +<div class="grid float" style="min-height: 70px; max-height: 60px" data-expected-width="64" data-expected-height="84"> + <div class="item" data-expected-width="50" data-expected-height="10"></div> + <div class="item" data-expected-width="50" data-expected-height="27"></div> +</div> +<div class="grid float" style="height: 70px" data-expected-width="64" data-expected-height="84"> + <div class="item" data-expected-width="50" data-expected-height="10"></div> + <div class="item" data-expected-width="50" data-expected-height="27"></div> +</div> + +<br clear="all"> + +<div class="grid float" style="min-height: 108px" data-expected-width="64" data-expected-height="122"> + <div class="item" data-expected-width="50" data-expected-height="15"></div> + <div class="item" data-expected-width="50" data-expected-height="60"></div> +</div> +<div class="grid float" style="min-height: 108px; max-height: 60px" data-expected-width="64" data-expected-height="122"> + <div class="item" data-expected-width="50" data-expected-height="15"></div> + <div class="item" data-expected-width="50" data-expected-height="60"></div> +</div> +<div class="grid float" style="height: 108px" data-expected-width="64" data-expected-height="122"> + <div class="item" data-expected-width="50" data-expected-height="15"></div> + <div class="item" data-expected-width="50" data-expected-height="60"></div> +</div> + +<br clear="all"> + +<div class="grid float min-height-max-content" data-expected-width="64" data-expected-height="97"> + <div class="item" data-expected-width="50" data-expected-height="10"></div> + <div class="item" data-expected-width="50" data-expected-height="40"></div> +</div> +<div class="grid float min-height-max-content max-height-min-content" data-expected-width="64" data-expected-height="97"> + <div class="item" data-expected-width="50" data-expected-height="10"></div> + <div class="item" data-expected-width="50" data-expected-height="40"></div> +</div> +<div class="grid float max-content" data-expected-width="64" data-expected-height="97"> + <div class="item" data-expected-width="50" data-expected-height="10"></div> + <div class="item" data-expected-width="50" data-expected-height="40"></div> +</div> + +<br clear="all"> + +<div class="float min-content"> + <div class="grid min-height-max-content" data-expected-width="64" data-expected-height="97"> + <div class="item" data-expected-width="50" data-expected-height="10"></div> + <div class="item" data-expected-width="50" data-expected-height="40"></div> + </div> +</div> +<div class="float max-content"> + <div class="grid min-height-max-content max-height-min-content" data-expected-width="64" data-expected-height="97"> + <div class="item" data-expected-width="50" data-expected-height="10"></div> + <div class="item" data-expected-width="50" data-expected-height="40"></div> + </div> +</div> +<div class="float fit-content"> + <div class="grid max-content" data-expected-width="64" data-expected-height="97"> + <div class="item" data-expected-width="50" data-expected-height="10"></div> + <div class="item" data-expected-width="50" data-expected-height="40"></div> + </div> +</div> + +</body> diff --git a/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/grid-container-percentage-001.html b/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/grid-container-percentage-001.html new file mode 100644 index 00000000000..511e0cd99ea --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/grid-container-percentage-001.html @@ -0,0 +1,262 @@ +<!DOCTYPE html> +<title>CSS Grid: indefinite grid container and percentage columns.</title> +<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com"/> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#valdef-grid-template-columns-length-percentage"/> +<meta name="assert" content="Checks that percentage columns are only indefinite during intrinsic size computation. Aftewards, they are properly resolved against the grid container intrinsic sizes."/> +<link rel="issue" href="https://crbug.com/616716"/> +<link rel="stylesheet" href="/css/support/grid.css"/> +<link rel="stylesheet" href="/css/support/width-keyword-classes.css"/> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css"/> +<style> +.wrapper { + position: relative; + clear: both; +} + +.grid { + font: 10px/1 Ahem; +} + +.float { + float: left; +} + +.abspos { + position: absolute; +} + +.fixedSize { + width: 200px; + height: 200px; +} + +.oneColumn100 { + grid-template-columns: 100%; +} + +.oneColumn50 { + grid-template-columns: 50%; +} + +.twoColumns { + grid-template-columns: 50% 100px; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<script type="text/javascript"> + setup({ explicit_done: true }); +</script> +<body onload="document.fonts.ready.then(() => { checkLayout('.grid'); })"> +<div id="log"></div> +<div class="wrapper"> + <div class="grid float oneColumn100" data-expected-width="40" data-expected-height="10"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="40" data-expected-height="10"> + XX X + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid abspos oneColumn100" data-expected-width="40" data-expected-height="10"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="40" data-expected-height="10"> + XX X + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid max-content oneColumn100" data-expected-width="40" data-expected-height="10"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="40" data-expected-height="10"> + XX X + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid fit-content oneColumn100" data-expected-width="40" data-expected-height="10"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="40" data-expected-height="10"> + XX X + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid min-content oneColumn100" data-expected-width="20" data-expected-height="20"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="20" data-expected-height="20"> + XX X + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid float oneColumn50" data-expected-width="40" data-expected-height="20"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="20" data-expected-height="20"> + XX X + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid abspos oneColumn50" data-expected-width="40" data-expected-height="20"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="20" data-expected-height="20"> + XX X + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid max-content oneColumn50" data-expected-width="40" data-expected-height="20"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="20" data-expected-height="20"> + XX X + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid fit-content oneColumn50" data-expected-width="40" data-expected-height="20"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="20" data-expected-height="20"> + XX X + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid min-content oneColumn50" data-expected-width="20" data-expected-height="20"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="20"> + XX X + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid float twoColumns" data-expected-width="140" data-expected-height="10"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="70" data-expected-height="10"> + XX X + </div> + <div class="firstRowSecondColumn" + data-offset-x="70" data-offset-y="0" data-expected-width="100" data-expected-height="10"> + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid abspos twoColumns" data-expected-width="140" data-expected-height="10"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="70" data-expected-height="10"> + XX X + </div> + <div class="firstRowSecondColumn" + data-offset-x="70" data-offset-y="0" data-expected-width="100" data-expected-height="10"> + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid max-content twoColumns" data-expected-width="140" data-expected-height="10"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="70" data-expected-height="10"> + XX X + </div> + <div class="firstRowSecondColumn" + data-offset-x="70" data-offset-y="0" data-expected-width="100" data-expected-height="10"> + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid fit-content twoColumns" data-expected-width="140" data-expected-height="10"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="70" data-expected-height="10"> + XX X + </div> + <div class="firstRowSecondColumn" + data-offset-x="70" data-offset-y="0" data-expected-width="100" data-expected-height="10"> + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid min-content twoColumns" data-expected-width="120" data-expected-height="10"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="60" data-expected-height="10"> + XX X + </div> + <div class="firstRowSecondColumn" + data-offset-x="60" data-offset-y="0" data-expected-width="100" data-expected-height="10"> + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid float twoColumns" data-expected-width="100" data-expected-height="10"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="10"> + </div> + <div class="firstRowSecondColumn" + data-offset-x="50" data-offset-y="0" data-expected-width="100" data-expected-height="10"> + XX X + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid abspos twoColumns" data-expected-width="100" data-expected-height="10"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="10"> + </div> + <div class="firstRowSecondColumn" + data-offset-x="50" data-offset-y="0" data-expected-width="100" data-expected-height="10"> + XX X + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid max-content twoColumns" data-expected-width="100" data-expected-height="10"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="10"> + </div> + <div class="firstRowSecondColumn" + data-offset-x="50" data-offset-y="0" data-expected-width="100" data-expected-height="10"> + XX X + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid min-content twoColumns" data-expected-width="100" data-expected-height="10"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="10"> + </div> + <div class="firstRowSecondColumn" + data-offset-x="50" data-offset-y="0" data-expected-width="100" data-expected-height="10"> + XX X + </div> + </div> +</div> + +<div class="wrapper"> + <div class="grid fit-content twoColumns" data-expected-width="100" data-expected-height="10"> + <div class="firstRowFirstColumn" + data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="10"> + </div> + <div class="firstRowSecondColumn" + data-offset-x="50" data-offset-y="0" data-expected-width="100" data-expected-height="10"> + XX X + </div> + </div> +</div> +</body> diff --git a/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/grid-item-margin-auto-columns-rows-001.html b/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/grid-item-margin-auto-columns-rows-001.html new file mode 100644 index 00000000000..6ae1c50c220 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/grid-item-margin-auto-columns-rows-001.html @@ -0,0 +1,87 @@ +<!DOCTYPE html> +<title>CSS Grid: 'auto' sizes with item's margins</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid"> +<link rel="help" href="https://drafts.csswg.org/css-grid/#layout-algorithm"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=357419"> +<meta name="assert" content="Check that the grid's rows and columns 'auto' sizes are updated accordingly to its grid-item's before and start margins."/> +<link href="/css/support/grid.css" rel="stylesheet"> +<link href="/css/support/width-keyword-classes.css" rel="stylesheet"> + +<style> +.grid { + grid-template-rows: auto auto; + grid-template-columns: auto auto; +} + +.gridItem { + width: 20px; + height: 40px; +} + +.marginTop { + margin-top: 20px; +} + +.marginBottom { + margin-bottom: 20px; +} + +.borderTop { + border-top: 5px solid; +} + +.borderBottom { + border-bottom: 5px solid; +} + +.paddingTop { + padding-top: 10px; +} + +.paddingBottom { + padding-bottom: 10px; +} +</style> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> + +<body onload="checkLayout('.grid')"> +<div> + <div class="grid fit-content" data-expected-width="40" data-expected-height="120"> + <div class="gridItem marginTop firstRowFirstColumn"></div> + <div class="gridItem firstRowSecondColumn"></div> + <div class="gridItem marginBottom secondRowFirstColumn"></div> + <div class="gridItem secondRowSecondColumn"></div> + </div> +</div> + +<div> + <div class="grid fit-content" data-expected-width="40" data-expected-height="120"> + <div class="gridItem marginTop paddingTop firstRowFirstColumn"></div> + <div class="gridItem firstRowSecondColumn"></div> + <div class="gridItem borderTop borderBottom secondRowFirstColumn"></div> + <div class="gridItem secondRowSecondColumn"></div> + </div> +</div> + +<div> + <div class="grid fit-content" data-expected-width="40" data-expected-height="120"> + <div class="gridItem marginTop paddingTop firstRowFirstColumn"></div> + <div class="gridItem firstRowSecondColumn"></div> + <div class="gridItem borderTop borderBottom secondRowFirstColumn"></div> + <div class="gridItem secondRowSecondColumn"></div> + </div> +</div> + +<div> + <div class="grid fit-content" data-expected-width="40" data-expected-height="120"> + <div class="gridItem marginTop paddingTop firstRowFirstColumn"></div> + <div class="gridItem firstRowSecondColumn"></div> + <div class="gridItem paddingBottom secondRowFirstColumn"></div> + <div class="gridItem secondRowSecondColumn"></div> + </div> +</div> +</body> diff --git a/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/grid-item-margin-auto-columns-rows-vertical-lr-001.html b/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/grid-item-margin-auto-columns-rows-vertical-lr-001.html new file mode 100644 index 00000000000..63bf55f293b --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/grid-item-margin-auto-columns-rows-vertical-lr-001.html @@ -0,0 +1,86 @@ +<!DOCTYPE html> +<title>CSS Grid: 'auto' sizes with item's margins with vertical-lr</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid/#layout-algorithm"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=357419"> +<meta name="assert" content="Check that the grid's rows and columns 'auto' sizes are updated accordingly to its grid-item's before and start margins when using vertical-lr writing mode."/> +<link href="/css/support/grid.css" rel="stylesheet"> +<link href="/css/support/width-keyword-classes.css" rel="stylesheet"> + +<style> +.grid { + grid-template-rows: auto auto; + grid-template-columns: auto auto; +} + +.gridItem { + width: 20px; + height: 40px; +} + +.marginTop { + margin-top: 20px; +} + +.marginBottom { + margin-bottom: 20px; +} + +.borderTop { + border-top: 5px solid; +} + +.borderBottom { + border-bottom: 5px solid; +} + +.paddingTop { + padding-top: 10px; +} + +.paddingBottom { + padding-bottom: 10px; +} +</style> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> + +<body onload="checkLayout('.grid')"> +<div> + <div class="grid fit-content verticalLR" data-expected-width="40" data-expected-height="120"> + <div class="gridItem marginTop firstRowFirstColumn"></div> + <div class="gridItem marginBottom firstRowSecondColumn"></div> + <div class="gridItem secondRowFirstColumn"></div> + <div class="gridItem secondRowSecondColumn"></div> + </div> +</div> + +<div> + <div class="grid fit-content verticalLR" data-expected-width="40" data-expected-height="120"> + <div class="gridItem marginTop paddingTop firstRowFirstColumn"></div> + <div class="gridItem borderTop borderBottom firstRowSecondColumn"></div> + <div class="gridItem secondRowFirstColumn"></div> + <div class="gridItem secondRowSecondColumn"></div> + </div> +</div> + +<div> + <div class="grid fit-content verticalLR" data-expected-width="40" data-expected-height="120"> + <div class="gridItem marginTop paddingTop firstRowFirstColumn"></div> + <div class="gridItem borderTop borderBottom firstRowSecondColumn"></div> + <div class="gridItem secondRowFirstColumn"></div> + <div class="gridItem secondRowSecondColumn"></div> + </div> +</div> + +<div> + <div class="grid fit-content verticalLR" data-expected-width="40" data-expected-height="120"> + <div class="gridItem marginTop paddingTop firstRowFirstColumn"></div> + <div class="gridItem paddingBottom firstRowSecondColumn"></div> + <div class="gridItem secondRowFirstColumn"></div> + <div class="gridItem secondRowSecondColumn"></div> + </div> +</div> +</body> diff --git a/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/grid-item-margin-auto-columns-rows-vertical-rl-001.html b/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/grid-item-margin-auto-columns-rows-vertical-rl-001.html new file mode 100644 index 00000000000..d6767e3f4a6 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/layout-algorithm/grid-item-margin-auto-columns-rows-vertical-rl-001.html @@ -0,0 +1,86 @@ +<!DOCTYPE html> +<title>CSS Grid: 'auto' sizes with item's margins with vertical-rl</title> +<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid/#layout-algorithm"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=357419"> +<meta name="assert" content="Check that the grid's rows and columns 'auto' sizes are updated accordingly to its grid-item's before and start margins when using vertical-rl writing mode."/> +<link href="/css/support/grid.css" rel="stylesheet"> +<link href="/css/support/width-keyword-classes.css" rel="stylesheet"> + +<style> +.grid { + grid-template-rows: auto auto; + grid-template-columns: auto auto; +} + +.gridItem { + width: 20px; + height: 40px; +} + +.marginTop { + margin-top: 20px; +} + +.marginBottom { + margin-bottom: 20px; +} + +.borderTop { + border-top: 5px solid; +} + +.borderBottom { + border-bottom: 5px solid; +} + +.paddingTop { + padding-top: 10px; +} + +.paddingBottom { + padding-bottom: 10px; +} +</style> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> + +<body onload="checkLayout('.grid')"> +<div style="position: relative"> + <div class="grid fit-content verticalRL" data-expected-width="40" data-expected-height="120"> + <div class="gridItem marginTop firstRowFirstColumn"></div> + <div class="gridItem marginBottom firstRowSecondColumn"></div> + <div class="gridItem secondRowFirstColumn"></div> + <div class="gridItem secondRowSecondColumn"></div> + </div> +</div> + +<div style="position: relative"> + <div class="grid fit-content verticalRL" data-expected-width="40" data-expected-height="120"> + <div class="gridItem marginTop paddingTop firstRowFirstColumn"></div> + <div class="gridItem borderTop borderBottom firstRowSecondColumn"></div> + <div class="gridItem secondRowFirstColumn"></div> + <div class="gridItem secondRowSecondColumn"></div> + </div> +</div> + +<div style="position: relative"> + <div class="grid fit-content verticalRL" data-expected-width="40" data-expected-height="120"> + <div class="gridItem marginTop paddingTop firstRowFirstColumn"></div> + <div class="gridItem borderTop borderBottom firstRowSecondColumn"></div> + <div class="gridItem secondRowFirstColumn"></div> + <div class="gridItem secondRowSecondColumn"></div> + </div> +</div> + +<div style="position: relative"> + <div class="grid fit-content verticalRL" data-expected-width="40" data-expected-height="120"> + <div class="gridItem marginTop paddingTop firstRowFirstColumn"></div> + <div class="gridItem paddingBottom firstRowSecondColumn"></div> + <div class="gridItem secondRowFirstColumn"></div> + <div class="gridItem secondRowSecondColumn"></div> + </div> +</div> +</body> diff --git a/tests/wpt/web-platform-tests/css/css-grid/placement/grid-auto-flow-sparse-001.html b/tests/wpt/web-platform-tests/css/css-grid/placement/grid-auto-flow-sparse-001.html new file mode 100644 index 00000000000..373371ac2bf --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/placement/grid-auto-flow-sparse-001.html @@ -0,0 +1,118 @@ +<!DOCTYPE html> +<title>CSS Grid: auto-placement with 'grid-auto-flow: column'</title> +<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-auto-flow"> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#auto-placement-algo"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=384099"> +<meta name="assert" content="Check that the auto-placement algorithm is sparse by default."> +<link rel="stylesheet" href="/css/support/grid.css"> +<link rel="stylesheet" href="/fonts/ahem.css"> + +<style> +.grid { + grid-template-columns: 50px 100px 150px 200px; + grid-template-rows: 50px 100px 150px 200px; +} + +.unconstrainedContainer { + /* For accurate x / y offset. */ + position: relative; +} +</style> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<script type="text/javascript"> + setup({ explicit_done: true }); +</script> + +<body onload="document.fonts.ready.then(() => { checkLayout('.grid'); })"> +<div class="unconstrainedContainer"> + <div class="grid"> + <div class="sizedToGridArea firstRowSecondColumn" data-offset-x="50" data-offset-y="0" data-expected-width="100" data-expected-height="50"></div> + <div class="sizedToGridArea autoRowAutoColumnSpanning2" data-offset-x="150" data-offset-y="0" data-expected-width="350" data-expected-height="50"></div> + <div class="sizedToGridArea autoRowAutoColumn" data-offset-x="0" data-offset-y="50" data-expected-width="50" data-expected-height="100"></div> + <div class="sizedToGridArea autoRowAutoColumnSpanning2" data-offset-x="50" data-offset-y="50" data-expected-width="250" data-expected-height="100"></div> + <div class="sizedToGridArea autoRowAutoColumnSpanning2" data-offset-x="0" data-offset-y="150" data-expected-width="150" data-expected-height="150"></div> + <div class="sizedToGridArea autoRowAutoColumn" data-offset-x="150" data-offset-y="150" data-expected-width="150" data-expected-height="150"></div> + </div> +</div> + +<div class="unconstrainedContainer"> + <div class="grid"> + <div class="sizedToGridArea autoRowSecondColumn" data-offset-x="50" data-offset-y="0" data-expected-width="100" data-expected-height="50"></div> + <div class="sizedToGridArea autoRowAutoColumnSpanning2" data-offset-x="150" data-offset-y="0" data-expected-width="350" data-expected-height="50"></div> + <div class="sizedToGridArea autoRowFirstColumn" data-offset-x="0" data-offset-y="50" data-expected-width="50" data-expected-height="100"></div> + <div class="sizedToGridArea autoRowThirdColumn" data-offset-x="150" data-offset-y="50" data-expected-width="150" data-expected-height="100"></div> + <div class="sizedToGridArea autoRowAutoColumn" data-offset-x="300" data-offset-y="50" data-expected-width="200" data-expected-height="100"></div> + <div class="sizedToGridArea autoRowAutoColumn" data-offset-x="0" data-offset-y="150" data-expected-width="50" data-expected-height="150"></div> + <div class="sizedToGridArea autoRowSpanning2AutoColumnSpanning3" data-offset-x="50" data-offset-y="150" data-expected-width="450" data-expected-height="350"></div> + <div class="sizedToGridArea autoRowAutoColumn" data-offset-x="0" data-offset-y="300" data-expected-width="50" data-expected-height="200"></div> + </div> +</div> + +<div class="unconstrainedContainer"> + <div class="grid"> + <div class="sizedToGridArea firstRowAutoColumn" data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="50"></div> + <div class="sizedToGridArea secondRowAutoColumn" data-offset-x="0" data-offset-y="50" data-expected-width="50" data-expected-height="100"></div> + <div class="sizedToGridArea autoRowSecondColumn" data-offset-x="50" data-offset-y="0" data-expected-width="100" data-expected-height="50"></div> + <div class="sizedToGridArea autoRowFirstColumn" data-offset-x="0" data-offset-y="150" data-expected-width="50" data-expected-height="150"></div> + <div class="sizedToGridArea autoRowAutoColumn" data-offset-x="50" data-offset-y="150" data-expected-width="100" data-expected-height="150"></div> + </div> +</div> + +<div class="unconstrainedContainer"> + <div class="grid"> + <div class="sizedToGridArea autoRowFirstColumn" data-offset-x="0" data-offset-y="150" data-expected-width="50" data-expected-height="150"></div> + <div class="sizedToGridArea firstRowSecondColumn" data-offset-x="50" data-offset-y="0" data-expected-width="100" data-expected-height="50"></div> + <div class="sizedToGridArea secondRowAutoColumn" data-offset-x="0" data-offset-y="50" data-expected-width="50" data-expected-height="100"></div> + <div class="sizedToGridArea firstRowAutoColumn" data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="50"></div> + <div class="sizedToGridArea autoRowAutoColumn" data-offset-x="50" data-offset-y="150" data-expected-width="100" data-expected-height="150"></div> + </div> +</div> + +<div class="unconstrainedContainer"> + <div class="grid gridAutoFlowColumnSparse"> + <div class="sizedToGridArea secondRowFirstColumn" data-offset-x="0" data-offset-y="50" data-expected-width="50" data-expected-height="100"></div> + <div class="sizedToGridArea autoRowSpanning2AutoColumn" data-offset-x="0" data-offset-y="150" data-expected-width="50" data-expected-height="350"></div> + <div class="sizedToGridArea autoRowAutoColumn" data-offset-x="50" data-offset-y="0" data-expected-width="100" data-expected-height="50"></div> + <div class="sizedToGridArea autoRowSpanning2AutoColumn" data-offset-x="50" data-offset-y="50" data-expected-width="100" data-expected-height="250"></div> + <div class="sizedToGridArea autoRowSpanning2AutoColumn" data-offset-x="150" data-offset-y="0" data-expected-width="150" data-expected-height="150"></div> + <div class="sizedToGridArea autoRowAutoColumn" data-offset-x="150" data-offset-y="150" data-expected-width="150" data-expected-height="150"></div> + </div> +</div> + +<div class="unconstrainedContainer"> + <div class="grid gridAutoFlowColumnSparse"> + <div class="sizedToGridArea secondRowAutoColumn" data-offset-x="0" data-offset-y="50" data-expected-width="50" data-expected-height="100"></div> + <div class="sizedToGridArea autoRowSpanning2AutoColumn" data-offset-x="0" data-offset-y="150" data-expected-width="50" data-expected-height="350"></div> + <div class="sizedToGridArea firstRowAutoColumn" data-offset-x="50" data-offset-y="0" data-expected-width="100" data-expected-height="50"></div> + <div class="sizedToGridArea thirdRowAutoColumn" data-offset-x="50" data-offset-y="150" data-expected-width="100" data-expected-height="150"></div> + <div class="sizedToGridArea autoRowAutoColumn" data-offset-x="50" data-offset-y="300" data-expected-width="100" data-expected-height="200"></div> + <div class="sizedToGridArea autoRowAutoColumn" data-offset-x="150" data-offset-y="0" data-expected-width="150" data-expected-height="50"></div> + <div class="sizedToGridArea autoRowSpanning3AutoColumnSpanning2" data-offset-x="150" data-offset-y="50" data-expected-width="350" data-expected-height="450"></div> + <div class="sizedToGridArea autoRowAutoColumn" data-offset-x="300" data-offset-y="0" data-expected-width="200" data-expected-height="50"></div> + </div> +</div> + +<div class="unconstrainedContainer"> + <div class="grid gridAutoFlowColumnSparse"> + <div class="sizedToGridArea autoRowFirstColumn" data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="50"></div> + <div class="sizedToGridArea autoRowSecondColumn" data-offset-x="50" data-offset-y="0" data-expected-width="100" data-expected-height="50"></div> + <div class="sizedToGridArea secondRowAutoColumn" data-offset-x="0" data-offset-y="50" data-expected-width="50" data-expected-height="100"></div> + <div class="sizedToGridArea firstRowAutoColumn" data-offset-x="150" data-offset-y="0" data-expected-width="150" data-expected-height="50"></div> + <div class="sizedToGridArea autoRowAutoColumn" data-offset-x="150" data-offset-y="50" data-expected-width="150" data-expected-height="100"></div> + </div> +</div> + +<div class="unconstrainedContainer"> + <div class="grid gridAutoFlowColumnSparse"> + <div class="sizedToGridArea firstRowAutoColumn" data-offset-x="150" data-offset-y="0" data-expected-width="150" data-expected-height="50"></div> + <div class="sizedToGridArea secondRowFirstColumn" data-offset-x="0" data-offset-y="50" data-expected-width="50" data-expected-height="100"></div> + <div class="sizedToGridArea autoRowSecondColumn" data-offset-x="50" data-offset-y="0" data-expected-width="100" data-expected-height="50"></div> + <div class="sizedToGridArea autoRowFirstColumn" data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="50"></div> + <div class="sizedToGridArea autoRowAutoColumn" data-offset-x="150" data-offset-y="50" data-expected-width="150" data-expected-height="100"></div> + </div> +</div> +</body> diff --git a/tests/wpt/web-platform-tests/css/css-grid/placement/grid-container-change-grid-tracks-recompute-child-positions-001.html b/tests/wpt/web-platform-tests/css/css-grid/placement/grid-container-change-grid-tracks-recompute-child-positions-001.html new file mode 100644 index 00000000000..a2485142e1b --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/placement/grid-container-change-grid-tracks-recompute-child-positions-001.html @@ -0,0 +1,88 @@ +<!DOCTYPE html> +<html> +<title>CSS Grid: Grid tracks changes recomputed child positions.</title> +<link rel="author" title="Julien Chaffraix" href="mailto:jchaffraix@chromium.org"/> +<link rel="help" href="https://drafts.csswg.org/css-grid/#placement"/> +<meta name="assert" content="Checks that grid-template-{rows|columns} dynamic updates recomputes the positions of automatically placed grid items."/> +<link rel="issue" href="https://crbug.com/248151"/> +<link href="/css/support/grid.css" rel="stylesheet"/> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css"/> +<style> +.grid { + grid-auto-flow: row dense; + grid-auto-rows: 5px; + grid-auto-columns: 5px; +} +#firstGridItem { + grid-row: auto; + grid-column: 1; +} + +#secondGridItem { + grid-row: 1; + grid-column: auto; +} + +#thirdGridItem { + grid-row: auto; + grid-column: auto; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<script> +function testGridDefinitions(gridTemplateRows, gridTemplateColumns, gridTemplateAreas, firstGridItemData, secondGridItemData, thirdGridItemData) +{ + var gridElement = document.getElementsByClassName("grid")[0]; + gridElement.style.gridTemplateRows = gridTemplateRows; + gridElement.style.gridTemplateColumns = gridTemplateColumns; + gridElement.style.gridTemplateAreas = gridTemplateAreas; + + var firstGridItem = document.getElementById("firstGridItem"); + firstGridItem.setAttribute("data-expected-width", firstGridItemData.width); + firstGridItem.setAttribute("data-expected-height", firstGridItemData.height); + firstGridItem.setAttribute("data-offset-x", firstGridItemData.x); + firstGridItem.setAttribute("data-offset-y", firstGridItemData.y); + + var secondGridItem = document.getElementById("secondGridItem"); + secondGridItem.setAttribute("data-expected-width", secondGridItemData.width); + secondGridItem.setAttribute("data-expected-height", secondGridItemData.height); + secondGridItem.setAttribute("data-offset-x", secondGridItemData.x); + secondGridItem.setAttribute("data-offset-y", secondGridItemData.y); + + var thirdGridItem = document.getElementById("thirdGridItem"); + thirdGridItem.setAttribute("data-expected-width", thirdGridItemData.width); + thirdGridItem.setAttribute("data-expected-height", thirdGridItemData.height); + thirdGridItem.setAttribute("data-offset-x", thirdGridItemData.x); + thirdGridItem.setAttribute("data-offset-y", thirdGridItemData.y); + + checkLayout(".grid", false); +} + +function testChangingGridDefinitions() +{ + testGridDefinitions('10px 20px', '10px', '', { 'width': '10', 'height': '20', 'x': '0', 'y': '10' }, { 'width': '10', 'height': '10', 'x': '0', 'y': '0' }, { 'width': '10', 'height': '5', 'x': '0', 'y': '30' }); + testGridDefinitions('10px', '10px', '"a"', { 'width': '10', 'height': '5', 'x': '0', 'y': '10' }, { 'width': '10', 'height': '10', 'x': '0', 'y': '0' }, { 'width': '10', 'height': '5', 'x': '0', 'y': '15' }); + testGridDefinitions('10px', '10px', '"a ."', { 'width': '10', 'height': '5', 'x': '0', 'y': '10' }, { 'width': '10', 'height': '10', 'x': '0', 'y': '0' }, { 'width': '5', 'height': '10', 'x': '10', 'y': '0' }); + testGridDefinitions('50px', '30px 40px', '', { 'width': '30', 'height': '5', 'x': '0', 'y': '50' }, { 'width': '30', 'height': '50', 'x': '0', 'y': '0' }, { 'width': '40', 'height': '50', 'x': '30', 'y': '0' }); + testGridDefinitions('50px', '60px', '', { 'width': '60', 'height': '5', 'x': '0', 'y': '50' }, { 'width': '60', 'height': '50', 'x': '0', 'y': '0' }, { 'width': '60', 'height': '5', 'x': '0', 'y': '55' }); + testGridDefinitions('50px 100px 150px', '60px', '', { 'width': '60', 'height': '100', 'x': '0', 'y': '50' }, { 'width': '60', 'height': '50', 'x': '0', 'y': '0' }, { 'width': '60', 'height': '150', 'x': '0', 'y': '150' }); + + done(); +} + +</script> +<script type="text/javascript"> + setup({ explicit_done: true }); +</script> +<body onload="document.fonts.ready.then(() => { testChangingGridDefinitions(); })"> +<div style="position: relative"> + <div class="grid"> + <div class="sizedToGridArea" id="firstGridItem"></div> + <div class="sizedToGridArea" id="secondGridItem"></div> + <div class="sizedToGridArea" id="thirdGridItem"></div> + </div> +</div> +</body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-grid/placement/grid-container-change-named-grid-recompute-child-positions-001.html b/tests/wpt/web-platform-tests/css/css-grid/placement/grid-container-change-named-grid-recompute-child-positions-001.html new file mode 100644 index 00000000000..d702d30b3ba --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/placement/grid-container-change-named-grid-recompute-child-positions-001.html @@ -0,0 +1,84 @@ +<!DOCTYPE html> +<html> +<title>CSS Grid: Change named grid lines.</title> +<link rel="author" title="Julien Chaffraix" href="mailto:jchaffraix@chromium.org"/> +<link rel="help" href="https://drafts.csswg.org/css-grid/#placement"/> +<meta name="assert" content="Checks that updating the named grid lines definitions in grid-template-{rows|columns} recomputes the positions of automatically placed grid items."/> +<link rel="issue" href="https://crbug.com/248151"/> +<link href="/css/support/grid.css" rel="stylesheet"/> +<link href="/css/support/alignment.css" rel="stylesheet"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css"/> +<style> +.grid { + grid-auto-flow: row dense; +} +#firstGridItem { + grid-row: auto; + grid-column: column; +} + +#secondGridItem { + grid-row: row; + grid-column: auto; +} + +#thirdGridItem { + grid-row: auto; + grid-column: auto; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<script> +function testGridDefinitions(gridTemplateRows, gridTemplateColumns, firstGridItemData, secondGridItemData, thirdGridItemData) +{ + var gridElement = document.getElementsByClassName("grid")[0]; + gridElement.style.gridTemplateRows = gridTemplateRows; + gridElement.style.gridTemplateColumns = gridTemplateColumns; + + var firstGridItem = document.getElementById("firstGridItem"); + firstGridItem.setAttribute("data-expected-width", firstGridItemData.width); + firstGridItem.setAttribute("data-expected-height", firstGridItemData.height); + firstGridItem.setAttribute("data-offset-x", firstGridItemData.x); + firstGridItem.setAttribute("data-offset-y", firstGridItemData.y); + + var secondGridItem = document.getElementById("secondGridItem"); + secondGridItem.setAttribute("data-expected-width", secondGridItemData.width); + secondGridItem.setAttribute("data-expected-height", secondGridItemData.height); + secondGridItem.setAttribute("data-offset-x", secondGridItemData.x); + secondGridItem.setAttribute("data-offset-y", secondGridItemData.y); + + var thirdGridItem = document.getElementById("thirdGridItem"); + thirdGridItem.setAttribute("data-expected-width", thirdGridItemData.width); + thirdGridItem.setAttribute("data-expected-height", thirdGridItemData.height); + thirdGridItem.setAttribute("data-offset-x", thirdGridItemData.x); + thirdGridItem.setAttribute("data-offset-y", thirdGridItemData.y); + + checkLayout(".grid", false); +} + +function testChangingGridDefinitions() +{ + testGridDefinitions('10px [row] 20px', '30px [column]', { 'width': '0', 'height': '10', 'x': '30', 'y': '0' }, { 'width': '30', 'height': '20', 'x': '0', 'y': '10' }, { 'width': '30', 'height': '10', 'x': '0', 'y': '0' }); + testGridDefinitions('10px [row] 20px', '30px', { 'width': '0', 'height': '10', 'x': '30', 'y': '0' }, { 'width': '30', 'height': '20', 'x': '0', 'y': '10' }, { 'width': '30', 'height': '10', 'x': '0', 'y': '0' }); + testGridDefinitions('10px 20px [row]', '30px', { 'width': '0', 'height': '10', 'x': '30', 'y': '0' }, { 'width': '30', 'height': '0', 'x': '0', 'y': '30' }, { 'width': '30', 'height': '10', 'x': '0', 'y': '0' }); + testGridDefinitions('10px 20px [row]', '30px [column]', { 'width': '0', 'height': '10', 'x': '30', 'y': '0' }, { 'width': '30', 'height': '0', 'x': '0', 'y': '30' }, { 'width': '30', 'height': '10', 'x': '0', 'y': '0' }); + done(); +} + +</script> +<script type="text/javascript"> + setup({ explicit_done: true }); +</script> +<body onload="document.fonts.ready.then(() => { testChangingGridDefinitions(); })"> +<div style="position: relative"> + <div class="grid justifyContentStart"> + <div class="sizedToGridArea" id="firstGridItem"></div> + <div class="sizedToGridArea" id="secondGridItem"></div> + <div class="sizedToGridArea" id="thirdGridItem"></div> + </div> +</div> + +</body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-grid/reference/flex-item-grid-container-percentage-rows-001-ref.html b/tests/wpt/web-platform-tests/css/css-grid/reference/flex-item-grid-container-percentage-rows-001-ref.html new file mode 100644 index 00000000000..1f4b23952e1 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-grid/reference/flex-item-grid-container-percentage-rows-001-ref.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<style> +.wrapper { + width: 200px; + border: 5px solid; +} + +.wrapper > div { + height: 100px; +} + +.magenta { + background: magenta; +} + +.cyan { + background: cyan; +} +</style> + +<p>Test passes if you see a 200x200 box with top half cyan and bottom half magenta.</p> + +<div class="wrapper"> + <div class="cyan"></div> + <div class="magenta"></div> +</div> diff --git a/tests/wpt/web-platform-tests/css/css-masking/clip-path/clip-path-descendant-text-mutated-001.html b/tests/wpt/web-platform-tests/css/css-masking/clip-path/clip-path-descendant-text-mutated-001.html new file mode 100644 index 00000000000..e41dacc0b54 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-masking/clip-path/clip-path-descendant-text-mutated-001.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<title>CSS Masking: Test ancestors update as text descendants change</title> +<link rel="author" title="Fredrik Söderquist" href="mailto:fs@opera.com"> +<link rel="help" href="https://drafts.fxtf.org/css-masking-1/#the-clip-path"> +<link rel="issue" href="https://bugs.chromium.org/p/chromium/issues/detail?id=901851"> +<link rel="match" href="reference/clip-path-descendant-text-mutated-001-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="assert" content="This test ensures that ancestors are updated properly when a text descendant of clip path property changes."> +<script src="/common/reftest-wait.js"></script> +<script src="/common/rendering-utils.js"></script> +<style> +#target { + width: 100px; + height: 100px; + background-color: green; + border-right: 100px solid red; + clip-path: url(#clip); +} +</style> +<div id="target"></div> +<svg> + <clipPath id="clip"> + <text id="text" y="80" font-family="Ahem" font-size="100">XX</text> + </clipPath> +</svg> +<script> + waitForAtLeastOneFrame().then(function() { + text.firstChild.data = 'X'; + takeScreenshot(); + }); +</script> diff --git a/tests/wpt/web-platform-tests/css/css-masking/clip-path/clip-path-reference-restore.html b/tests/wpt/web-platform-tests/css/css-masking/clip-path/clip-path-reference-restore.html new file mode 100644 index 00000000000..eccebd8fbcc --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-masking/clip-path/clip-path-reference-restore.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<title>CSS Masking: Consecutive clip-paths don't affect each other.</title> +<link rel="author" title="Fredrik Söderquist" href="mailto:fs@opera.com"> +<link rel="help" href="https://drafts.fxtf.org/css-masking-1/#the-clip-path"> +<link rel="issue" href="https://crbug.com/391291"> +<link rel="match" href="reference/clip-path-reference-restore-ref.html"> +<meta name="assert" content="Check that consecutive clip-paths don't affect each other"/> +<style> +.error { + width: 100px; + height: 100px; + background-color: red; + position: absolute; +} +.test { + width: 200px; + height: 50px; + background-color: green; + clip-path: url(#c); +} +</style> +<div class="error"></div> +<div class="test"></div> +<div class="test"></div> +<svg> + <defs> + <clipPath id="c" clipPathUnits="objectBoundingBox"> + <rect width="0.5" height="1"/> + </clipPath> + </defs> +</svg> diff --git a/tests/wpt/web-platform-tests/css/css-masking/clip-path/clip-path-transform-mutated-002.html b/tests/wpt/web-platform-tests/css/css-masking/clip-path/clip-path-transform-mutated-002.html new file mode 100644 index 00000000000..de00a013ad4 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-masking/clip-path/clip-path-transform-mutated-002.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<title>CSS Masking: Mutating a <clipPath>s 'transform' updates the clip path</title> +<link rel="author" title="Fredrik Söderquist" href="mailto:fs@opera.com"> +<link rel="help" href="https://drafts.fxtf.org/css-masking-1/#the-clip-path""> +<link rel="help" href="https://crbug.com/881700"> +<link rel="match" href="reference/clip-path-transform-mutated-002-ref.html"> +<meta name="assert" content="Check that clipPath's clients should be notified when the 'transform' presentation attribute (or CSS property) was mutated on a <clipPath>."/> + +<script src="/common/reftest-wait.js"></script> +<script src="/common/rendering-utils.js"></script> + +<style> +#target { + width: 100px; + height: 100px; + background-color: green; + clip-path: url(#clip); +} +</style> +<div id="target"></div> +<svg> + <clipPath id="clip"> + <rect width="1" height="1"/> + </clipPath> +</svg> +<script> + waitForAtLeastOneFrame().then(function() { + clip.setAttribute('transform', 'scale(100 100)'); + takeScreenshot(); + }); +</script> diff --git a/tests/wpt/web-platform-tests/css/css-masking/clip-path/reference/clip-path-descendant-text-mutated-001-ref.html b/tests/wpt/web-platform-tests/css/css-masking/clip-path/reference/clip-path-descendant-text-mutated-001-ref.html new file mode 100644 index 00000000000..f718ea6abfb --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-masking/clip-path/reference/clip-path-descendant-text-mutated-001-ref.html @@ -0,0 +1,2 @@ +<!DOCTYPE html> +<div style="width: 100px; height: 100px; background-color: green"></div> diff --git a/tests/wpt/web-platform-tests/css/css-masking/clip-path/reference/clip-path-reference-restore-ref.html b/tests/wpt/web-platform-tests/css/css-masking/clip-path/reference/clip-path-reference-restore-ref.html new file mode 100644 index 00000000000..683511fd800 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-masking/clip-path/reference/clip-path-reference-restore-ref.html @@ -0,0 +1,2 @@ +<!DOCTYPE html> +<div style="width: 100px; height: 100px; background-color: green;"></div> diff --git a/tests/wpt/web-platform-tests/css/css-masking/clip-path/reference/clip-path-transform-mutated-002-ref.html b/tests/wpt/web-platform-tests/css/css-masking/clip-path/reference/clip-path-transform-mutated-002-ref.html new file mode 100644 index 00000000000..f718ea6abfb --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-masking/clip-path/reference/clip-path-transform-mutated-002-ref.html @@ -0,0 +1,2 @@ +<!DOCTYPE html> +<div style="width: 100px; height: 100px; background-color: green"></div> diff --git a/tests/wpt/web-platform-tests/css/css-properties-values-api/font-size-animation.html b/tests/wpt/web-platform-tests/css/css-properties-values-api/font-size-animation.html new file mode 100644 index 00000000000..4b8ce1c2551 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-properties-values-api/font-size-animation.html @@ -0,0 +1,44 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1"> +<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3751"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + CSS.registerProperty({ + name: '--length', + syntax: '<length>', + initialValue: '0px', + inherits: false + }); +</script> +<style> + @keyframes font_size_animation { + from { + font-size: 10px; + width: 10em; + --length: 10em; + } + to { + font-size: 20px; + width: 20em; + --length: 20em; + } + } + #target1 { + font-size: 1px; + animation: font_size_animation 10s -5s linear paused; + } +</style> +<div id=target1></div> +<script> + test(function() { + // At the time of writing, the correct (absolute) answer is not + // yet defined. However, whatever the correct answer is, there should + // be no difference in 'width' and a custom property registered with + // "<length>". + // + // See https://github.com/w3c/csswg-drafts/issues/3751 + assert_equals(getComputedStyle(target1).getPropertyValue('width'), + getComputedStyle(target1).getPropertyValue('--length')); + }, 'Animating font-size handled identically for standard and custom properties'); +</script> diff --git a/tests/wpt/web-platform-tests/css/css-scoping/keyframes-003.html b/tests/wpt/web-platform-tests/css/css-scoping/keyframes-003.html new file mode 100644 index 00000000000..2e1d799bd0d --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-scoping/keyframes-003.html @@ -0,0 +1,26 @@ +<!doctype html> +<title>CSS Test: @keyframes applies to :host.</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://drafts.csswg.org/css-scoping/#shadow-names"> +<div id="host"></div> +<script> + test(function() { + host.attachShadow({ mode: "open" }).innerHTML = ` + <style> + @keyframes myanim { + from { background: red; } + to { background: green; } + } + :host { + width: 100px; + height: 100px; + background: blue; + animation: myanim 10s infinite; + } + </style> + `; + + assert_equals(document.getElementById('host').getAnimations().length, 1); + }, "@keyframes applies to the shadow host"); +</script> diff --git a/tests/wpt/web-platform-tests/css/css-scoping/keyframes-004.html b/tests/wpt/web-platform-tests/css/css-scoping/keyframes-004.html new file mode 100644 index 00000000000..67924fb01cd --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-scoping/keyframes-004.html @@ -0,0 +1,27 @@ +<!doctype html> +<title>CSS Test: @keyframes applies to ::slotted.</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://drafts.csswg.org/css-scoping/#shadow-names"> +<div id="host"><div id="in-document"></div></div> +<script> + test(function() { + host.attachShadow({ mode: "open" }).innerHTML = ` + <style> + @keyframes myanim { + from { background: red; } + to { background: green; } + } + ::slotted(#in-document) { + width: 100px; + height: 100px; + background: blue; + animation: myanim 10s infinite; + } + </style> + <slot /> + `; + + assert_equals(document.getElementById('in-document').getAnimations().length, 1); + }, "@keyframes in shadow tree applies to the slotted element"); +</script> diff --git a/tests/wpt/web-platform-tests/css/css-scoping/keyframes-005.html b/tests/wpt/web-platform-tests/css/css-scoping/keyframes-005.html new file mode 100644 index 00000000000..d9026d2f6aa --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-scoping/keyframes-005.html @@ -0,0 +1,28 @@ +<!doctype html> +<title>CSS Test: @keyframes should not leak out of shadow tree.</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://drafts.csswg.org/css-scoping/#shadow-names"> +<style> + #host { + width: 100px; + height: 100px; + background: blue; + animation: myanim 10s infinite; + } +</style> +<div id="host"></div> +<script> + test(function() { + host.attachShadow({ mode: "open" }).innerHTML = ` + <style> + @keyframes myanim { + from { background: red; } + to { background: green; } + } + </style> + `; + + assert_equals(document.getElementById('host').getAnimations().length, 0); + }, "@keyframes should not leak out of the shadow tree."); +</script> diff --git a/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-underline-position-from-font-variable-ref.html b/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-underline-position-from-font-variable-ref.html index e621545772d..e9e5252194b 100644 --- a/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-underline-position-from-font-variable-ref.html +++ b/tests/wpt/web-platform-tests/css/css-text-decor/reference/text-underline-position-from-font-variable-ref.html @@ -18,17 +18,18 @@ src: url(../resources/UnderlineTest-Far.ttf); } .test { -text-decoration: underline; text-underline-position: from-font; font-size: 64px; line-height: 1.8; } .close_underline { +text-decoration: underline; font-family: underline-close; } .far_underline { +text-decoration: underline; font-family: underline-far; } </style> diff --git a/tests/wpt/web-platform-tests/css/css-text-decor/text-underline-position-from-font-variable.html b/tests/wpt/web-platform-tests/css/css-text-decor/text-underline-position-from-font-variable.html index 0459a2ea1d4..dc7ede0cd1f 100644 --- a/tests/wpt/web-platform-tests/css/css-text-decor/text-underline-position-from-font-variable.html +++ b/tests/wpt/web-platform-tests/css/css-text-decor/text-underline-position-from-font-variable.html @@ -14,18 +14,19 @@ src: url(resources/UnderlineTest-VF.ttf); } .test { -text-decoration: underline; text-underline-position: from-font; font-size: 64px; line-height: 1.8; } .close_underline { +text-decoration: underline; font-family: underline-variable, sans-serif; font-variation-settings: 'UNDO' 1; } .far_underline { +text-decoration: underline; font-family: underline-variable, sans-serif; font-variation-settings: 'UNDO' 1000; } diff --git a/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-auto-inline-010.html b/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-auto-inline-010.html index cb6a6222b7b..03776617bf6 100644 --- a/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-auto-inline-010.html +++ b/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-auto-inline-010.html @@ -6,7 +6,18 @@ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> <link rel="help" href="https://www.w3.org/TR/css-text-3/#hyphenation"> - <link rel="match" href="reference/hyphens-auto-inline-010-ref.html"> + <link rel="match" href="reference/hyphens-auto-inline-010M-ref.html"> + <link rel="match" href="reference/hyphens-auto-inline-010H-ref.html"> + + <!-- + User agents may use U+2010 HYPHEN <https://codepoints.net/U+2010> + when the font has the glyph, or + may use U+002D HYPHEN-MINUS <https://codepoints.net/U+002d> + otherwise. Some fonts will display slightly different glyphs for + these code points. Therefore these 2 reference files. + The M-ref.html reference file means the hyphen-Minus character U+002D. + The H-ref.html reference file means the Hyphen character U+2010. + --> <meta content="" name="flags"> <meta content="When 'hyphens' is set to 'auto' and applied to an inline element and when 'lang' attribute is also set to a valid value, then words may be broken at hyphenation opportunities determined automatically by an hyphenation resource appropriate to the language of the text involved."> @@ -17,25 +28,25 @@ border: black solid 2px; font-family: monospace; font-size: 32px; - margin-bottom: 0.25em; width: 6ch; } - span#test + span { hyphens: auto; } - - div#reference - { - hyphens: none; - } </style> <body lang="en"> - <p>Test passes if the characters inside of each black-bordered rectangles are laid out identically. - - <div>There are <span id="test">new guidelines now</span>.</div> - - <div id="reference">There are new guide-lines now.</div> + <div>There are <span>new guidelines now</span>.</div> + + <!-- + Expected result: + There + are + new + guide- + lines + now. + --> diff --git a/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-011.html b/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-011.html index 060dc75619a..862ca80fc64 100644 --- a/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-011.html +++ b/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-011.html @@ -6,7 +6,18 @@ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> <link rel="help" href="https://www.w3.org/TR/css-text-3/#hyphenation"> - <link rel="match" href="reference/hyphens-manual-011-ref.html"> + <link rel="match" href="reference/hyphens-manual-011M-ref.html"> + <link rel="match" href="reference/hyphens-manual-011H-ref.html"> + + <!-- + User agents may use U+2010 HYPHEN <https://codepoints.net/U+2010> + when the font has the glyph, or + may use U+002D HYPHEN-MINUS <https://codepoints.net/U+002d> + otherwise. Some fonts will display slightly different glyphs for + these code points. Therefore these 2 reference files. + The M-ref.html reference file means the hyphen-Minus character U+002D. + The H-ref.html reference file means the Hyphen character U+2010. + --> <meta content="" name="flags"> <meta content="When 'hyphens' is set to 'manual', then words can be hyphenated only if characters inside the words explicitly define hyphenation opportunities. In this test, the characters inside the word 'Deoxyribonucleic' explicitly define 2 hyphenation opportunities, so it can be hyphenated. Since 9 characters can all fit inside the line box of the block box, then the word 'Deoxyribonucleic' is hyphenated only after the 2nd soft hyphen." name="assert"> @@ -17,26 +28,19 @@ border: black solid 2px; font-family: monospace; font-size: 32px; - margin-bottom: 0.25em; - width: 10ch; - } - - div#test - { hyphens: manual; - } - - div#reference - { - hyphens: none; + width: 10ch; } </style> - <p>Test passes if the characters inside of each black-bordered rectangles are laid out identically. + <div>Deoxy­ribo­nucleic acid</div> - <div id="test">Deoxy­ribo­nucleic acid</div> - - <div id="reference">Deoxyribo-nucleic acid</div> + <!-- + Expected result: + Deoxyribo- + nucleic + acid + --> <!-- diff --git a/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-012.html b/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-012.html index 871f7c39b69..7ffece5ff6d 100644 --- a/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-012.html +++ b/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-012.html @@ -6,7 +6,18 @@ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> <link rel="help" href="https://www.w3.org/TR/css-text-3/#hyphenation"> - <link rel="match" href="reference/hyphens-manual-011-ref.html"> + <link rel="match" href="reference/hyphens-manual-011M-ref.html"> + <link rel="match" href="reference/hyphens-manual-011H-ref.html"> + + <!-- + User agents may use U+2010 HYPHEN <https://codepoints.net/U+2010> + when the font has the glyph, or + may use U+002D HYPHEN-MINUS <https://codepoints.net/U+002d> + otherwise. Some fonts will display slightly different glyphs for + these code points. Therefore these 2 reference files. + The M-ref.html reference file means the hyphen-Minus character U+002D. + The H-ref.html reference file means the Hyphen character U+2010. + --> <meta content="" name="flags"> <meta content="When 'hyphens' is set to 'manual', then words can be hyphenated only if characters inside the words explicitly define hyphenation opportunities. In this test, the characters inside the word 'Deoxyribonucleic' explicitly define 4 hyphenation opportunities. Since 9 characters can all fit inside the line box of the block box, then the word 'Deoxyribonucleic' is hyphenated only after the 3rd soft hyphen." name="assert"> @@ -17,26 +28,19 @@ border: black solid 2px; font-family: monospace; font-size: 32px; - margin-bottom: 0.25em; - width: 10ch; - } - - div#test - { hyphens: manual; - } - - div#reference - { - hyphens: none; + width: 10ch; } </style> - <p>Test passes if the characters inside of each black-bordered rectangles are laid out identically. + <div>Deo­xy­ribo­nu­cleic acid</div> - <div id="test">Deo­xy­ribo­nu­cleic acid</div> - - <div id="reference">Deoxyribo-nucleic acid</div> + <!-- + Expected result: + Deoxyribo- + nucleic + acid + --> <!-- diff --git a/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-013.html b/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-013.html index 17e3f6f8157..31c57c5382a 100644 --- a/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-013.html +++ b/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-013.html @@ -6,7 +6,18 @@ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> <link rel="help" href="https://www.w3.org/TR/css-text-3/#hyphenation"> - <link rel="match" href="reference/hyphens-manual-013-ref.html"> + <link rel="match" href="reference/hyphens-manual-013M-ref.html"> + <link rel="match" href="reference/hyphens-manual-013H-ref.html"> + + <!-- + User agents may use U+2010 HYPHEN <https://codepoints.net/U+2010> + when the font has the glyph, or + may use U+002D HYPHEN-MINUS <https://codepoints.net/U+002d> + otherwise. Some fonts will display slightly different glyphs for + these code points. Therefore these 2 reference files. + The M-ref.html reference file means the hyphen-Minus character U+002D. + The H-ref.html reference file means the Hyphen character U+2010. + --> <meta content="" name="flags"> <meta content="When 'hyphens' is set to 'manual', then words can be hyphenated only if characters inside the words explicitly define hyphenation opportunities. In this test, the characters inside the word 'Deoxyribonucleic' explicitly define 1 and only 1 hyphenation opportunity, so it can be hyphenated only at such point." name="assert"> @@ -17,26 +28,19 @@ border: black solid 2px; font-family: monospace; font-size: 32px; - margin-bottom: 0.25em; - width: 10ch; - } - - div#test - { hyphens: manual; - } - - div#reference - { - hyphens: none; + width: 10ch; } </style> - <p>Test passes if the characters inside of each black-bordered rectangles are laid out identically. Only the "c" of "nucleic" should be outside of each black-bordered rectangles. + <div>Deoxy­ribonucleic acid</div> - <div id="test">Deoxy­ribonucleic acid</div> - - <div id="reference">Deoxy-ribonucleic acid</div> + <!-- + Expected result: + Deoxy- + ribonucleic + acid + --> <!-- diff --git a/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-inline-011.html b/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-inline-011.html index ec08f4d3887..9eba15b5291 100644 --- a/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-inline-011.html +++ b/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-inline-011.html @@ -6,7 +6,18 @@ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> <link rel="help" href="https://www.w3.org/TR/css-text-3/#hyphenation"> - <link rel="match" href="reference/hyphens-manual-inline-011-ref.html"> + <link rel="match" href="reference/hyphens-manual-inline-011M-ref.html"> + <link rel="match" href="reference/hyphens-manual-inline-011H-ref.html"> + + <!-- + User agents may use U+2010 HYPHEN <https://codepoints.net/U+2010> + when the font has the glyph, or + may use U+002D HYPHEN-MINUS <https://codepoints.net/U+002d> + otherwise. Some fonts will display slightly different glyphs for + these code points. Therefore these 2 reference files. + The M-ref.html reference file means the hyphen-Minus character U+002D. + The H-ref.html reference file means the Hyphen character U+2010. + --> <meta content="" name="flags"> <meta content="When 'hyphens' is set to 'manual' and applied to an inline element, then words can be hyphenated only if characters inside the words explicitly define hyphenation opportunities. In this test, the characters inside the word 'Deoxyribonucleic' explicitly define 2 hyphenation opportunities, so it can be hyphenated. Since 9 characters can all fit inside the line box of the block box, then the word 'Deoxyribonucleic' is hyphenated only after the 2nd soft hyphen." name="assert"> @@ -17,23 +28,21 @@ border: black solid 2px; font-family: monospace; font-size: 32px; - margin-bottom: 0.25em; width: 10ch; } - span#test + span { hyphens: manual; } - - div#reference - { - hyphens: none; - } </style> - <p>Test passes if the characters inside of each black-bordered rectangles are laid out identically. - - <div>DNA <span id="test">means Deoxy­ribo­nucleic acid</span>.</div> + <div>DNA <span>means Deoxy­ribo­nucleic acid</span>.</div> - <div id="reference">DNA means Deoxyribo-nucleic acid.</div> + <!-- + Expected result: + DNA means + Deoxyribo- + nucleic + acid. + --> diff --git a/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-inline-012.html b/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-inline-012.html index 0267fa7baaa..b2aa04f7a6f 100644 --- a/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-inline-012.html +++ b/tests/wpt/web-platform-tests/css/css-text/hyphens/hyphens-manual-inline-012.html @@ -6,7 +6,18 @@ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> <link rel="help" href="https://www.w3.org/TR/css-text-3/#hyphenation"> - <link rel="match" href="reference/hyphens-manual-inline-012-ref.html"> + <link rel="match" href="reference/hyphens-manual-inline-012M-ref.html"> + <link rel="match" href="reference/hyphens-manual-inline-012H-ref.html"> + + <!-- + User agents may use U+2010 HYPHEN <https://codepoints.net/U+2010> + when the font has the glyph, or + may use U+002D HYPHEN-MINUS <https://codepoints.net/U+002d> + otherwise. Some fonts will display slightly different glyphs for + these code points. Therefore these 2 reference files. + The M-ref.html reference file means the hyphen-Minus character U+002D. + The H-ref.html reference file means the Hyphen character U+2010. + --> <meta content="" name="flags"> <meta content="When 'hyphens' is set to 'manual' and applied to an inline element, then words can be hyphenated only if characters inside the words explicitly define hyphenation opportunities. In this test, the characters inside the word 'Deoxyribonucleic' explicitly define 4 hyphenation opportunities. Since 'Deoxy' has 5 characters and 'Deoxyribo' has 9 characters and since the content width of the block box can take 8 characters, then a soft hyphen will occur after 'Deoxy'. Since 'ribonu' has 6 characters and 'ribonucleic' has 11 characters and since the content width of the block box can take 8 characters, then a soft hyphen will occur after 'ribonu'." name="assert"> @@ -17,23 +28,23 @@ border: black solid 2px; font-family: monospace; font-size: 32px; - margin-bottom: 0.25em; width: 8ch; } - span#test + span { hyphens: manual; } - - div#reference - { - hyphens: none; - } </style> - <p>Test passes if the characters inside of each black-bordered rectangles are laid out identically. - - <div>DNA <span id="test">means Deo­xy­ribo­nu­cleic acid</span>.</div> - - <div id="reference">DNA means Deoxy-ribonu-cleic acid.</div> + <div>DNA <span>means Deo­xy­ribo­nu­cleic acid</span>.</div> + + <!-- + Expected result: + DNA + means + Deoxy- + ribonu- + cleic + acid. + --> diff --git a/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-auto-inline-010-ref.html b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-auto-inline-010H-ref.html index ce1296eb78c..c3e6271c19f 100644 --- a/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-auto-inline-010-ref.html +++ b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-auto-inline-010H-ref.html @@ -12,16 +12,18 @@ border: black solid 2px; font-family: monospace; font-size: 32px; - hyphens: none; - margin-bottom: 0.25em; width: 6ch; } </style> <body lang="en"> - <p>Test passes if the characters inside of each black-bordered rectangles are laid out identically. + <div>There<br>are<br>new<br>guide‐<br>lines<br>now.</div> - <div>There are new guide-lines now.</div> +<!-- - <div>There are new guide-lines now.</div> + Hyphen-minus == - == - + + Hyphen == ‐ == ‐ + +--> diff --git a/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-inline-012-ref.html b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-auto-inline-010M-ref.html index 5dfc2b8e221..ace0c5e7537 100644 --- a/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-inline-012-ref.html +++ b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-auto-inline-010M-ref.html @@ -12,16 +12,18 @@ border: black solid 2px; font-family: monospace; font-size: 32px; - hyphens: none; - margin-bottom: 0.25em; - width: 8ch; + width: 6ch; } </style> <body lang="en"> - <p>Test passes if the characters inside of each black-bordered rectangles are laid out identically. + <div>There<br>are<br>new<br>guide-<br>lines<br>now.</div> - <div>DNA means Deoxy-ribonu-cleic acid.</div> +<!-- - <div>DNA means Deoxy-ribonu-cleic acid.</div> + Hyphen-minus == - == - + + Hyphen == ‐ == ‐ + +--> diff --git a/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-011-ref.html b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-011H-ref.html index 98581bd37c0..99612206f8e 100644 --- a/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-011-ref.html +++ b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-011H-ref.html @@ -12,16 +12,16 @@ border: black solid 2px; font-family: monospace; font-size: 32px; - hyphens: none; - margin-bottom: 0.25em; width: 10ch; } </style> - <body> + <div>Deoxyribo‐<br>nucleic acid</div> - <p>Test passes if the characters inside of each black-bordered rectangles are laid out identically. +<!-- - <div>Deoxyribo-nucleic acid</div> + Hyphen-minus == - == - - <div>Deoxyribo-nucleic acid</div> + Hyphen == ‐ == ‐ + +--> diff --git a/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-inline-011-ref.html b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-011M-ref.html index 17254a09f17..191095a413b 100644 --- a/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-inline-011-ref.html +++ b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-011M-ref.html @@ -12,16 +12,16 @@ border: black solid 2px; font-family: monospace; font-size: 32px; - hyphens: none; - margin-bottom: 0.25em; width: 10ch; } </style> - <body> + <div>Deoxyribo-<br>nucleic acid</div> - <p>Test passes if the characters inside of each black-bordered rectangles are laid out identically. +<!-- - <div>DNA means Deoxyribo-nucleic acid.</div> + Hyphen-minus == - == - - <div>DNA means Deoxyribo-nucleic acid.</div> + Hyphen == ‐ == ‐ + +--> diff --git a/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-013-ref.html b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-013-ref.html deleted file mode 100644 index 9fa6bee4215..00000000000 --- a/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-013-ref.html +++ /dev/null @@ -1,27 +0,0 @@ -<!DOCTYPE html> - - <meta charset="UTF-8"> - - <title>CSS Reference Test</title> - - <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> - - <style> - div - { - border: black solid 2px; - font-family: monospace; - font-size: 32px; - hyphens: none; - margin-bottom: 0.25em; - width: 10ch; - } - </style> - - <body> - - <p>Test passes if the characters inside of each black-bordered rectangles are laid out identically. Only the "c" of "nucleic" should be outside of each black-bordered rectangles. - - <div>Deoxy-ribonucleic acid</div> - - <div>Deoxy-ribonucleic acid</div> diff --git a/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-013H-ref.html b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-013H-ref.html new file mode 100644 index 00000000000..12ad0ed5059 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-013H-ref.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Reference Test</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + + <style> + div + { + border: black solid 2px; + font-family: monospace; + font-size: 32px; + width: 10ch; + } + </style> + + <div>Deoxy‐<br>ribonucleic acid</div> + +<!-- + + Hyphen-minus == - == - + + Hyphen == ‐ == ‐ + +--> diff --git a/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-013M-ref.html b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-013M-ref.html new file mode 100644 index 00000000000..3c7121242b7 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-013M-ref.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Reference Test</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + + <style> + div + { + border: black solid 2px; + font-family: monospace; + font-size: 32px; + width: 10ch; + } + </style> + + <div>Deoxy-<br>ribonucleic acid</div> + +<!-- + + Hyphen-minus == - == - + + Hyphen == ‐ == ‐ + +--> diff --git a/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-inline-011H-ref.html b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-inline-011H-ref.html new file mode 100644 index 00000000000..0cd1ef9f9b3 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-inline-011H-ref.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Reference Test</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + + <style> + div + { + border: black solid 2px; + font-family: monospace; + font-size: 32px; + width: 10ch; + } + </style> + + <div>DNA means<br>Deoxyribo‐<br>nucleic<br>acid.</div> + +<!-- + + Hyphen-minus == - == - + + Hyphen == ‐ == ‐ + +--> diff --git a/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-inline-011M-ref.html b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-inline-011M-ref.html new file mode 100644 index 00000000000..836919648e7 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-inline-011M-ref.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Reference Test</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + + <style> + div + { + border: black solid 2px; + font-family: monospace; + font-size: 32px; + width: 10ch; + } + </style> + + <div>DNA means<br>Deoxyribo-<br>nucleic<br>acid.</div> + +<!-- + + Hyphen-minus == - == - + + Hyphen == ‐ == ‐ + +--> diff --git a/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-inline-012H-ref.html b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-inline-012H-ref.html new file mode 100644 index 00000000000..8b2ff04ade5 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-inline-012H-ref.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Reference Test</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + + <style> + div + { + border: black solid 2px; + font-family: monospace; + font-size: 32px; + width: 8ch; + } + </style> + + <div>DNA<br>means<br>Deoxy‐<br>ribonu‐<br>cleic<br>acid.</div> + +<!-- + + Hyphen-minus == - == - + + Hyphen == ‐ == ‐ + +--> diff --git a/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-inline-012M-ref.html b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-inline-012M-ref.html new file mode 100644 index 00000000000..0c8db033c8b --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text/hyphens/reference/hyphens-manual-inline-012M-ref.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Reference Test</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + + <style> + div + { + border: black solid 2px; + font-family: monospace; + font-size: 32px; + width: 8ch; + } + </style> + + <div>DNA<br>means<br>Deoxy-<br>ribonu-<br>cleic<br>acid.</div> + +<!-- + + Hyphen-minus == - == - + + Hyphen == ‐ == ‐ + +--> diff --git a/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-newline-011.html b/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-newline-011.html new file mode 100644 index 00000000000..068119c2929 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-newline-011.html @@ -0,0 +1,53 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Text: 'white-space: break-spaces' with 4 white spaces and 4 line feeda</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + <link rel="help" href="https://www.w3.org/TR/css-text-3/#white-space-property"> + <link rel="match" href="../../reference/ref-filled-green-100px-square.xht"> + <link rel="stylesheet" type="text/css" href="/fonts/ahem.css"> + + <meta content="" name="flags"> + <meta content="This test checks that when 'white-space' is set to 'break-spaces', then line feeds (&NewLine; in the code) are preserved, just like with 'white-space: pre' or with 'white-space: pre-wrap'."> + + <style> + div + { + font-family: Ahem; + font-size: 25px; + line-height: 1; + width: 4em; + } + + div#overlapped-red-reference + { + background-color: red; + height: 4em; + } + + div#overlapping-green-test + { + background-color: green; + bottom: 4em; + color: red; + position: relative; + white-space: break-spaces; + } + </style> + + <p>Test passes if there is a filled green square and <strong>no red</strong>. + + <div id="overlapped-red-reference"></div> + + <div id="overlapping-green-test">

 

</div> + <!-- ^ ^ + 4 consecutive white spaces: 1234 + --> + +<!-- + + 
 == Line feed == 
 == 
 + +--> diff --git a/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-newline-012.html b/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-newline-012.html new file mode 100644 index 00000000000..766bcc1feee --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-newline-012.html @@ -0,0 +1,53 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Text: 'white-space: break-spaces', 10 white spaces and 1 line feed</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + <link rel="help" href="https://www.w3.org/TR/css-text-3/#white-space-property"> + <link rel="match" href="../../reference/ref-filled-green-100px-square.xht"> + <link rel="stylesheet" type="text/css" href="/fonts/ahem.css"> + + <meta content="" name="flags"> + <meta content="This test checks that when 'white-space' is set to 'break-spaces', then line feeds (&NewLine; in the code) are preserved, just like with 'white-space: pre' or with 'white-space: pre-wrap'."> + + <style> + div + { + font-family: Ahem; + font-size: 25px; + line-height: 1; + width: 4em; + } + + div#overlapped-red-reference + { + background-color: red; + height: 4em; + } + + div#overlapping-green-test + { + background-color: green; + bottom: 4em; + color: red; + position: relative; + white-space: break-spaces; + } + </style> + + <p>Test passes if there is a filled green square and <strong>no red</strong>. + + <div id="overlapped-red-reference"></div> + + <div id="overlapping-green-test"> 
 </div> + <!-- ^ ^ ^ + 10 white spaces: 1 234567890 + --> + +<!-- + + 
 == Line feed == 
 == 
 + +--> diff --git a/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-newline-013.html b/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-newline-013.html new file mode 100644 index 00000000000..5b45e5c1cce --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-newline-013.html @@ -0,0 +1,53 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Text: 'white-space: break-spaces', 7 white spaces and 2 line feeds</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + <link rel="help" href="https://www.w3.org/TR/css-text-3/#white-space-property"> + <link rel="match" href="../../reference/ref-filled-green-100px-square.xht"> + <link rel="stylesheet" type="text/css" href="/fonts/ahem.css"> + + <meta content="" name="flags"> + <meta content="This test checks that when 'white-space' is set to 'break-spaces', then line feeds (&NewLine; in the code) are preserved, just like with 'white-space: pre' or with 'white-space: pre-wrap'."> + + <style> + div + { + font-family: Ahem; + font-size: 25px; + line-height: 1; + width: 4em; + } + + div#overlapped-red-reference + { + background-color: red; + height: 4em; + } + + div#overlapping-green-test + { + background-color: green; + bottom: 4em; + color: red; + position: relative; + white-space: break-spaces; + } + </style> + + <p>Test passes if there is a filled green square and <strong>no red</strong>. + + <div id="overlapped-red-reference"></div> + + <div id="overlapping-green-test"> 
 
 </div> + <!-- ^ ^ ^ ^ + 7 white spaces: 1 2 34567 + --> + +<!-- + + 
 == Line feed == 
 == 
 + +--> diff --git a/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-newline-014.html b/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-newline-014.html new file mode 100644 index 00000000000..56281dee347 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-newline-014.html @@ -0,0 +1,53 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Text: 'white-space: break-spaces', 4 white spaces and 3 line feeds</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + <link rel="help" href="https://www.w3.org/TR/css-text-3/#white-space-property"> + <link rel="match" href="../../reference/ref-filled-green-100px-square.xht"> + <link rel="stylesheet" type="text/css" href="/fonts/ahem.css"> + + <meta content="" name="flags"> + <meta content="This test checks that when 'white-space' is set to 'break-spaces', then line feeds (&NewLine; in the code) are preserved, just like with 'white-space: pre' or with 'white-space: pre-wrap'."> + + <style> + div + { + font-family: Ahem; + font-size: 25px; + line-height: 1; + width: 4em; + } + + div#overlapped-red-reference + { + background-color: red; + height: 4em; + } + + div#overlapping-green-test + { + background-color: green; + bottom: 4em; + color: red; + position: relative; + white-space: break-spaces; + } + </style> + + <p>Test passes if there is a filled green square and <strong>no red</strong>. + + <div id="overlapped-red-reference"></div> + + <div id="overlapping-green-test"> 
 
 
 </div> + <!-- ^ ^ ^ ^ + 4 white spaces: 1 2 3 4 + --> + +<!-- + + 
 == Line feed == 
 == 
 + +--> diff --git a/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-newline-015.html b/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-newline-015.html new file mode 100644 index 00000000000..96a7d836638 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-newline-015.html @@ -0,0 +1,53 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Text: 'white-space: break-spaces', 3 white spaces and 3 line feeds</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + <link rel="help" href="https://www.w3.org/TR/css-text-3/#white-space-property"> + <link rel="match" href="../../reference/ref-filled-green-100px-square.xht"> + <link rel="stylesheet" type="text/css" href="/fonts/ahem.css"> + + <meta content="" name="flags"> + <meta content="This test checks that when 'white-space' is set to 'break-spaces', then line feeds (&NewLine; in the code) are preserved, just like with 'white-space: pre' or with 'white-space: pre-wrap'."> + + <style> + div + { + font-family: Ahem; + font-size: 25px; + line-height: 1; + width: 4em; + } + + div#overlapped-red-reference + { + background-color: red; + height: 4em; + } + + div#overlapping-green-test + { + background-color: green; + bottom: 4em; + color: red; + position: relative; + white-space: break-spaces; + } + </style> + + <p>Test passes if there is a filled green square and <strong>no red</strong>. + + <div id="overlapped-red-reference"></div> + + <div id="overlapping-green-test">
 
 
 </div> + <!-- ^ ^ ^ + 3 white spaces: 1 2 3 + --> + +<!-- + + 
 == Line feed == 
 == 
 + +--> diff --git a/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-newline-016.html b/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-newline-016.html new file mode 100644 index 00000000000..4156e6a7da1 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-newline-016.html @@ -0,0 +1,50 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Text: 'white-space: break-spaces' and 4 consecutive line feeds</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + <link rel="help" href="https://www.w3.org/TR/css-text-3/#white-space-property"> + <link rel="match" href="../../reference/ref-filled-green-100px-square.xht"> + <link rel="stylesheet" type="text/css" href="/fonts/ahem.css"> + + <meta content="" name="flags"> + <meta content="This test checks that when 'white-space' is set to 'break-spaces', then line feeds (&NewLine; in the code) are preserved, just like with 'white-space: pre' or with 'white-space: pre-wrap'."> + + <style> + div + { + font-family: Ahem; + font-size: 25px; + line-height: 1; + width: 4em; + } + + div#overlapped-red-reference + { + background-color: red; + height: 4em; + } + + div#overlapping-green-test + { + background-color: green; + bottom: 4em; + color: red; + position: relative; + white-space: break-spaces; + } + </style> + + <p>Test passes if there is a filled green square and <strong>no red</strong>. + + <div id="overlapped-red-reference"></div> + + <div id="overlapping-green-test">



</div> + +<!-- + + 
 == Line feed == 
 == 
 + +--> diff --git a/tests/wpt/web-platform-tests/css/filter-effects/effect-reference-reset-style-delete-crash.html b/tests/wpt/web-platform-tests/css/filter-effects/effect-reference-reset-style-delete-crash.html new file mode 100644 index 00000000000..e1c0eb9aeca --- /dev/null +++ b/tests/wpt/web-platform-tests/css/filter-effects/effect-reference-reset-style-delete-crash.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<title>CSS Filters: Crash when a SVG filter is deleted</title> +<link rel="author" title="Stephen White" href="mailto:senorblanco@chromium.org"> +<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterElement"> +<link rel="issue" href="https://bugs.webkit.org/show_bug.cgi?id=90405"> +<meta name="assert" content="Check that crash doesn't happen when a SVG filter is deleted that used to be referenced by an HTML element but is no longer."> +<body> + <img id="html" style="filter: url(#MyFilter);" src="support/color-palette.png"> + <svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" version="1.1" id="svg"> + <defs> + <filter id="MyFilter"> + <feColorMatrix type="hueRotate" values="180"/> + </filter> + </defs> + </svg> + <script> + html = document.getElementById('html'); + html.style = ""; + svg = document.getElementById('svg'); + svg.parentNode.removeChild(svg); + </script> +</body> diff --git a/tests/wpt/web-platform-tests/css/support/height-keyword-classes.css b/tests/wpt/web-platform-tests/css/support/height-keyword-classes.css new file mode 100644 index 00000000000..2f847795934 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/support/height-keyword-classes.css @@ -0,0 +1,42 @@ +/* In the current spec for heights, min-content, max-content and fit-content are + * equivalent. + */ + +.min-content { + height: min-content; +} + +.max-content { + height: max-content; +} + +.fit-content { + height: -moz-fit-content; + height: fit-content; +} + +.max-height-min-content { + max-height: min-content; +} + +.max-height-max-content { + max-height: max-content; +} + +.max-height-fit-content { + max-height: -moz-fit-content; + max-height: fit-content; +} + +.min-height-min-content { + min-height: min-content; +} + +.min-height-max-content { + min-height: max-content; +} + +.min-height-fit-content { + min-height: -moz-fit-content; + min-height: fit-content; +} diff --git a/tests/wpt/web-platform-tests/css/support/width-keyword-classes.css b/tests/wpt/web-platform-tests/css/support/width-keyword-classes.css index b5c84a5d5f4..138433c1141 100644 --- a/tests/wpt/web-platform-tests/css/support/width-keyword-classes.css +++ b/tests/wpt/web-platform-tests/css/support/width-keyword-classes.css @@ -3,88 +3,44 @@ unbreakable line box. */ .min-content { - /* Webkit, but not actually implemented outside deprecated flexbox */ - width: min-intrinsic; - width: -webkit-min-content; - width: -moz-min-content; width: min-content; } .max-content { - width: -webkit-max-content; - width: -moz-max-content; width: max-content; } /* - Identical to auto except for elements with an instrinsic width like an - img where this overrides the intrinsic width to get regular block "auto". -*/ -.fill-available { - width: -webkit-fill-available; - /* Firefox is missing the fill- prefix because they followed an older spec */ - width: -moz-available; - width: fill-available; -} - -/* Shrink wrap just like floating. max(min-content, min(max-content, fill-available)) */ .fit-content { - /* Webkit, but only outside a deprecated flexbox. */ - width: intrinsic; - width: -webkit-fit-content; width: -moz-fit-content; width: fit-content; } .max-width-min-content { - max-width: -webkit-min-content; - max-width: -moz-min-content; max-width: min-content; } .max-width-max-content { - max-width: -webkit-max-content; - max-width: -moz-max-content; max-width: max-content; } -.max-width-fill-available { - max-width: -webkit-fill-available; - max-width: -moz-available; - max-width: fill-available; -} - .max-width-fit-content { - max-width: intrinsic; - max-width: -webkit-fit-content; max-width: -moz-fit-content; max-width: fit-content; } .min-width-min-content { - min-width: -webkit-min-content; - min-width: -moz-min-content; min-width: min-content; } .min-width-max-content { - min-width: -webkit-max-content; - min-width: -moz-max-content; min-width: max-content; } -.min-width-fill-available { - min-width: -webkit-fill-available; - min-width: -moz-available; - min-width: fill-available; -} - .min-width-fit-content { - min-width: intrinsic; - min-width: -webkit-fit-content; min-width: -moz-fit-content; min-width: fit-content; } diff --git a/tests/wpt/web-platform-tests/custom-elements/custom-element-reaction-queue.html b/tests/wpt/web-platform-tests/custom-elements/custom-element-reaction-queue.html index 737dab117d3..246b15a0af3 100644 --- a/tests/wpt/web-platform-tests/custom-elements/custom-element-reaction-queue.html +++ b/tests/wpt/web-platform-tests/custom-elements/custom-element-reaction-queue.html @@ -52,6 +52,39 @@ test_with_window(function (contentWindow) { test_with_window(function (contentWindow) { const contentDocument = contentWindow.document; + contentDocument.write('<test-element>'); + + const element = contentDocument.querySelector('test-element'); + assert_equals(Object.getPrototypeOf(element), contentWindow.HTMLElement.prototype); + + let log = []; + class TestElement extends contentWindow.HTMLElement { + constructor() { + super(); + this.id = "foo"; + this.setAttribute('id', 'foo'); + this.removeAttribute('id'); + this.style.fontSize = '10px'; + log.push(create_constructor_log(this)); + } + connectedCallback(...args) { + log.push(create_connected_callback_log(this, ...args)); + } + attributeChangedCallback(...args) { + log.push(create_attribute_changed_callback_log(this, ...args)); + } + static get observedAttributes() { return ['id', 'style']; } + } + contentWindow.customElements.define('test-element', TestElement); + assert_equals(Object.getPrototypeOf(element), TestElement.prototype); + + assert_equals(log.length, 2); + assert_constructor_log_entry(log[0], element); + assert_connected_log_entry(log[1], element); +}, 'Upgrading a custom element must not invoke attributeChangedCallback for the attribute that is changed during upgrading'); + +test_with_window(function (contentWindow) { + const contentDocument = contentWindow.document; contentDocument.write('<test-element id="first-element">'); contentDocument.write('<test-element id="second-element">'); diff --git a/tests/wpt/web-platform-tests/docs/writing-tests/testharness-api.md b/tests/wpt/web-platform-tests/docs/writing-tests/testharness-api.md index 2ee52786add..bb855b17238 100644 --- a/tests/wpt/web-platform-tests/docs/writing-tests/testharness-api.md +++ b/tests/wpt/web-platform-tests/docs/writing-tests/testharness-api.md @@ -313,40 +313,44 @@ NOTE: All asserts must be located in a `test()` or a step of an these places won't be detected correctly by the harness and may cause unexpected exceptions that will lead to an error in the harness. -## Preconditions ## +## Optional Features ## -When a test would be invalid unless certain conditions are met, but yet -doesn't explicitly depend on those preconditions, `assert_precondition` can be -used. For example: +If a test depends on a specification or specification feature that is OPTIONAL +(in the [RFC 2119 sense](https://tools.ietf.org/html/rfc2119)), +`assert_implements_optional` can be used to indicate that failing the test does +not mean violating a web standard. For example: ```js async_test((t) => { const video = document.createElement("video"); - assert_precondition(video.canPlayType("video/webm")); + assert_implements_optional(video.canPlayType("video/webm")); video.src = "multitrack.webm"; // test something specific to multiple audio tracks in a WebM container t.done(); }, "WebM with multiple audio tracks"); ``` -A failing `assert_precondition` call is reported as a status of -`PRECONDITION_FAILED` for the subtest. +A failing `assert_implements_optional` call is reported as a status of +`PRECONDITION_FAILED` for the subtest. This unusual status code is a legacy +leftover from the deprecated `assert_precondition`; see the [RFC that renamed +it](https://github.com/web-platform-tests/rfcs/pull/48). -`assert_precondition` can also be used during test setup. For example: +`assert_implements_optional` can also be used during test setup. For example: ```js setup(() => { - assert_precondition("onfoo" in document.body, "'foo' event supported"); + assert_implements_optional("optionalfeature" in document.body, + "'optionalfeature' event supported"); }); -async_test(() => { /* test #1 waiting for "foo" event */ }); -async_test(() => { /* test #2 waiting for "foo" event */ }); +async_test(() => { /* test #1 waiting for "optionalfeature" event */ }); +async_test(() => { /* test #2 waiting for "optionalfeature" event */ }); ``` -A failing `assert_precondition` during setup is reported as a status of +A failing `assert_implements_optional` during setup is reported as a status of `PRECONDITION_FAILED` for the test, and the subtests will not run. -See also the `.optional` [file name convention](file-names.md), which is -appropriate when the precondition is explicitly optional behavior. +See also the `.optional` [file name convention](file-names.md), which may be +preferable if the entire test is optional. ## Cleanup ## @@ -772,10 +776,6 @@ workers and want to ensure they run in series: ## List of Assertions ## -### `assert_precondition(condition, description)` -asserts that `condition` is truthy. -See [preconditions](#preconditions) for usage. - ### `assert_true(actual, description)` asserts that `actual` is strictly true @@ -885,6 +885,13 @@ that the exception should have as its .constructor. For example, `func` - a function that should throw +### `assert_implements(condition, description)` +asserts that a feature is supported, by checking if `condition` is truthy. + +### `assert_implements_optional(condition, description)` +asserts that an optional feature is supported, by checking if `condition` is truthy. +See [Optional Features](#optional-features) for usage. + ### `assert_unreached(description)` asserts if called. Used to ensure that some codepath is *not* taken e.g. an event does not fire. @@ -897,6 +904,9 @@ asserts that one `assert_func(actual, expected_array_N, extra_arg1, ..., extra_a allows multiple behaviours. Test authors should not use this method simply to hide UA bugs. +### **DEPRECATED** `assert_precondition(condition, description)` +Use `assert_implements` or `assert_implements_optional` instead. + ## Utility functions ## ### **DEPRECATED** `on_event(object, event, callback)` diff --git a/tests/wpt/web-platform-tests/element-timing/background-image-data-uri.html b/tests/wpt/web-platform-tests/element-timing/background-image-data-uri.html index 540668ae3c3..9722463742a 100644 --- a/tests/wpt/web-platform-tests/element-timing/background-image-data-uri.html +++ b/tests/wpt/web-platform-tests/element-timing/background-image-data-uri.html @@ -18,7 +18,7 @@ body { <script> let beforeRender = performance.now(); async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { assert_equals(entryList.getEntries().length, 1); diff --git a/tests/wpt/web-platform-tests/element-timing/background-image-multiple-elements.html b/tests/wpt/web-platform-tests/element-timing/background-image-multiple-elements.html index 61a284a5df3..11f8c05f966 100644 --- a/tests/wpt/web-platform-tests/element-timing/background-image-multiple-elements.html +++ b/tests/wpt/web-platform-tests/element-timing/background-image-multiple-elements.html @@ -23,7 +23,7 @@ body { <script src="resources/element-timing-helpers.js"></script> <script> async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); let beforeRender = performance.now(); let numObservedElements = 0; let observedDiv1 = false; diff --git a/tests/wpt/web-platform-tests/element-timing/background-image-stretched.html b/tests/wpt/web-platform-tests/element-timing/background-image-stretched.html index d5534c3257a..3ad8976ccf1 100644 --- a/tests/wpt/web-platform-tests/element-timing/background-image-stretched.html +++ b/tests/wpt/web-platform-tests/element-timing/background-image-stretched.html @@ -18,7 +18,7 @@ body { <script> let beforeRender = performance.now(); async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { assert_equals(entryList.getEntries().length, 1); diff --git a/tests/wpt/web-platform-tests/element-timing/buffer-before-onload.html b/tests/wpt/web-platform-tests/element-timing/buffer-before-onload.html index 79dd64e2977..17c8238f6e7 100644 --- a/tests/wpt/web-platform-tests/element-timing/buffer-before-onload.html +++ b/tests/wpt/web-platform-tests/element-timing/buffer-before-onload.html @@ -13,7 +13,7 @@ is available from the observer with the buffered flag set to true. */ async_test(function(t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); beforeRender = performance.now(); const img = document.createElement('img'); img.src = 'resources/square20.jpg'; diff --git a/tests/wpt/web-platform-tests/element-timing/buffered-flag.html b/tests/wpt/web-platform-tests/element-timing/buffered-flag.html index 1fca1178792..e7fcf059fb1 100644 --- a/tests/wpt/web-platform-tests/element-timing/buffered-flag.html +++ b/tests/wpt/web-platform-tests/element-timing/buffered-flag.html @@ -12,7 +12,7 @@ body { <script src="resources/element-timing-helpers.js"></script> <script> async_test(t => { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const beforeRender = performance.now(); const img = document.createElement('img'); // Initial observer used to know when entry has been dispatched diff --git a/tests/wpt/web-platform-tests/element-timing/cross-origin-element.sub.html b/tests/wpt/web-platform-tests/element-timing/cross-origin-element.sub.html index b5b06f30469..1052bf246d0 100644 --- a/tests/wpt/web-platform-tests/element-timing/cross-origin-element.sub.html +++ b/tests/wpt/web-platform-tests/element-timing/cross-origin-element.sub.html @@ -12,7 +12,7 @@ body { <script src="resources/element-timing-helpers.js"></script> <script> async_test((t) => { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); let img; const pathname = 'http://{{domains[www]}}:{{ports[http][1]}}' + '/element-timing/resources/square100.png'; diff --git a/tests/wpt/web-platform-tests/element-timing/cross-origin-iframe-element.sub.html b/tests/wpt/web-platform-tests/element-timing/cross-origin-iframe-element.sub.html index b183fe289aa..2f49933ab96 100644 --- a/tests/wpt/web-platform-tests/element-timing/cross-origin-iframe-element.sub.html +++ b/tests/wpt/web-platform-tests/element-timing/cross-origin-iframe-element.sub.html @@ -7,7 +7,7 @@ <script src="resources/element-timing-helpers.js"></script> <script> async_test((t) => { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done((entryList) => { assert_unreached("We should not observe a cross origin element."); diff --git a/tests/wpt/web-platform-tests/element-timing/css-generated-text.html b/tests/wpt/web-platform-tests/element-timing/css-generated-text.html index 4b7dea73ca8..d1bbf5a7eee 100644 --- a/tests/wpt/web-platform-tests/element-timing/css-generated-text.html +++ b/tests/wpt/web-platform-tests/element-timing/css-generated-text.html @@ -17,7 +17,7 @@ body { <script> async_test(function (t) { const beforeRender = performance.now(); - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { assert_equals(entryList.getEntries().length, 1); diff --git a/tests/wpt/web-platform-tests/element-timing/disconnect-image.html b/tests/wpt/web-platform-tests/element-timing/disconnect-image.html index 9c2be0e45ac..6f9f2ce7b9f 100644 --- a/tests/wpt/web-platform-tests/element-timing/disconnect-image.html +++ b/tests/wpt/web-platform-tests/element-timing/disconnect-image.html @@ -9,7 +9,7 @@ let beforeRender; let img; async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { assert_equals(entryList.getEntries().length, 1); diff --git a/tests/wpt/web-platform-tests/element-timing/element-only-when-fully-active.html b/tests/wpt/web-platform-tests/element-timing/element-only-when-fully-active.html index 001430516dc..ff08074d574 100644 --- a/tests/wpt/web-platform-tests/element-timing/element-only-when-fully-active.html +++ b/tests/wpt/web-platform-tests/element-timing/element-only-when-fully-active.html @@ -8,7 +8,7 @@ <script> let t = async_test('Only expose element attribute for fully active documents'); t.step(() => { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); }); window.triggerTest = t.step_func_done(elementEntry => { assert_not_equals(elementEntry.element, null); diff --git a/tests/wpt/web-platform-tests/element-timing/first-letter-background.html b/tests/wpt/web-platform-tests/element-timing/first-letter-background.html index b24ed542c88..f05f2f92234 100644 --- a/tests/wpt/web-platform-tests/element-timing/first-letter-background.html +++ b/tests/wpt/web-platform-tests/element-timing/first-letter-background.html @@ -16,7 +16,7 @@ <script> let beforeRender = performance.now(); async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const div = document.getElementById('target'); let textObserved = false; let imageObserved = false; diff --git a/tests/wpt/web-platform-tests/element-timing/fixed-id-identifier.html b/tests/wpt/web-platform-tests/element-timing/fixed-id-identifier.html index ae8303f021d..749b9ada2f3 100644 --- a/tests/wpt/web-platform-tests/element-timing/fixed-id-identifier.html +++ b/tests/wpt/web-platform-tests/element-timing/fixed-id-identifier.html @@ -8,7 +8,7 @@ <p elementtiming='my_identifier' id='my_id'>Text</p> <script> async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { assert_equals(entryList.getEntries().length, 1); diff --git a/tests/wpt/web-platform-tests/element-timing/image-TAO.sub.html b/tests/wpt/web-platform-tests/element-timing/image-TAO.sub.html index ee2b0617900..7b455dfa4c4 100644 --- a/tests/wpt/web-platform-tests/element-timing/image-TAO.sub.html +++ b/tests/wpt/web-platform-tests/element-timing/image-TAO.sub.html @@ -7,7 +7,7 @@ <script src="resources/element-timing-helpers.js"></script> <script> async_test(t => { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const beforeRender = performance.now(); const remote_img = 'http://{{domains[www]}}:{{ports[http][1]}}/element-timing/resources/TAOImage.py?' + 'origin=' + window.location.origin +'&tao='; diff --git a/tests/wpt/web-platform-tests/element-timing/image-carousel.html b/tests/wpt/web-platform-tests/element-timing/image-carousel.html index ce6ac951e24..2b3b618f8c4 100644 --- a/tests/wpt/web-platform-tests/element-timing/image-carousel.html +++ b/tests/wpt/web-platform-tests/element-timing/image-carousel.html @@ -26,7 +26,7 @@ body { <script> async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const beforeRenderTimes = []; let entry_count = 0; const entry_count_per_element = [0, 0]; diff --git a/tests/wpt/web-platform-tests/element-timing/image-clipped-svg.html b/tests/wpt/web-platform-tests/element-timing/image-clipped-svg.html index c8e4a67cea6..4c2bb360794 100644 --- a/tests/wpt/web-platform-tests/element-timing/image-clipped-svg.html +++ b/tests/wpt/web-platform-tests/element-timing/image-clipped-svg.html @@ -7,7 +7,7 @@ <script> let beforeRender; async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { assert_equals(entryList.getEntries().length, 1); diff --git a/tests/wpt/web-platform-tests/element-timing/image-data-uri.html b/tests/wpt/web-platform-tests/element-timing/image-data-uri.html index afe203ae1bf..02d88fb2448 100644 --- a/tests/wpt/web-platform-tests/element-timing/image-data-uri.html +++ b/tests/wpt/web-platform-tests/element-timing/image-data-uri.html @@ -16,7 +16,7 @@ body { <script> let beforeRender = performance.now(); async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { assert_equals(entryList.getEntries().length, 1); diff --git a/tests/wpt/web-platform-tests/element-timing/image-not-added.html b/tests/wpt/web-platform-tests/element-timing/image-not-added.html index 83a6cc60844..d77049ecd49 100644 --- a/tests/wpt/web-platform-tests/element-timing/image-not-added.html +++ b/tests/wpt/web-platform-tests/element-timing/image-not-added.html @@ -5,7 +5,7 @@ <script src="/resources/testharnessreport.js"></script> <script> async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(() => { // The image should not have caused an entry, so fail test. diff --git a/tests/wpt/web-platform-tests/element-timing/image-not-fully-visible.html b/tests/wpt/web-platform-tests/element-timing/image-not-fully-visible.html index c51c24a965a..504d17592f2 100644 --- a/tests/wpt/web-platform-tests/element-timing/image-not-fully-visible.html +++ b/tests/wpt/web-platform-tests/element-timing/image-not-fully-visible.html @@ -14,7 +14,7 @@ body { let beforeRender; let img; async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { assert_equals(entryList.getEntries().length, 1); diff --git a/tests/wpt/web-platform-tests/element-timing/image-rect-iframe.html b/tests/wpt/web-platform-tests/element-timing/image-rect-iframe.html index a97ed5a8507..00986366e61 100644 --- a/tests/wpt/web-platform-tests/element-timing/image-rect-iframe.html +++ b/tests/wpt/web-platform-tests/element-timing/image-rect-iframe.html @@ -11,7 +11,7 @@ body { <script src="/resources/testharnessreport.js"></script> <script> async_test((t) => { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); on_event(window, 'message', e => { assert_equals(e.data.length, 1); assert_equals(e.data.entryType, 'element'); diff --git a/tests/wpt/web-platform-tests/element-timing/image-src-change.html b/tests/wpt/web-platform-tests/element-timing/image-src-change.html index e9e13742a65..88436123fe9 100644 --- a/tests/wpt/web-platform-tests/element-timing/image-src-change.html +++ b/tests/wpt/web-platform-tests/element-timing/image-src-change.html @@ -13,7 +13,7 @@ body { <img src='resources/square100.png' elementtiming='my_image' id='my_id'/> <script> async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); let beforeRender = performance.now(); const img = document.getElementById('my_id'); let firstCallback = true; diff --git a/tests/wpt/web-platform-tests/element-timing/image-with-css-scale.html b/tests/wpt/web-platform-tests/element-timing/image-with-css-scale.html index 9bd71086a75..a0490f375cc 100644 --- a/tests/wpt/web-platform-tests/element-timing/image-with-css-scale.html +++ b/tests/wpt/web-platform-tests/element-timing/image-with-css-scale.html @@ -21,7 +21,7 @@ body { <script> const beforeRender = performance.now(); async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { assert_equals(entryList.getEntries().length, 1); diff --git a/tests/wpt/web-platform-tests/element-timing/image-with-rotation.html b/tests/wpt/web-platform-tests/element-timing/image-with-rotation.html index 64ff942f0cd..229e9ae96c8 100644 --- a/tests/wpt/web-platform-tests/element-timing/image-with-rotation.html +++ b/tests/wpt/web-platform-tests/element-timing/image-with-rotation.html @@ -21,7 +21,7 @@ body { <script> const beforeRender = performance.now(); async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { assert_equals(entryList.getEntries().length, 1); diff --git a/tests/wpt/web-platform-tests/element-timing/images-repeated-resource.html b/tests/wpt/web-platform-tests/element-timing/images-repeated-resource.html index 6090e75f26e..f7296e05e73 100644 --- a/tests/wpt/web-platform-tests/element-timing/images-repeated-resource.html +++ b/tests/wpt/web-platform-tests/element-timing/images-repeated-resource.html @@ -20,7 +20,7 @@ body { let img; let img2; async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func(function(entryList) { assert_equals(entryList.getEntries().length, 1); diff --git a/tests/wpt/web-platform-tests/element-timing/invisible-images.html b/tests/wpt/web-platform-tests/element-timing/invisible-images.html index 8225996e255..ffde3ce2f6f 100644 --- a/tests/wpt/web-platform-tests/element-timing/invisible-images.html +++ b/tests/wpt/web-platform-tests/element-timing/invisible-images.html @@ -16,7 +16,7 @@ </style> <script> async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done((entries) => { // The image should not have caused an entry, so fail test. diff --git a/tests/wpt/web-platform-tests/element-timing/multiple-background-images.html b/tests/wpt/web-platform-tests/element-timing/multiple-background-images.html index c2a32c3c8e6..380e5e825e1 100644 --- a/tests/wpt/web-platform-tests/element-timing/multiple-background-images.html +++ b/tests/wpt/web-platform-tests/element-timing/multiple-background-images.html @@ -18,7 +18,7 @@ body { <script> let beforeRender = performance.now(); async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); let numObservedElements = 0; let observedCircle = false; let observedSquare = false; diff --git a/tests/wpt/web-platform-tests/element-timing/multiple-redirects-TAO.html b/tests/wpt/web-platform-tests/element-timing/multiple-redirects-TAO.html index 6800f7cf687..3a45b552bea 100644 --- a/tests/wpt/web-platform-tests/element-timing/multiple-redirects-TAO.html +++ b/tests/wpt/web-platform-tests/element-timing/multiple-redirects-TAO.html @@ -11,7 +11,7 @@ <body> <script> async_test(t => { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); let destUrl = get_host_info().HTTP_REMOTE_ORIGIN + '/element-timing/resources/multiple-redirects.py?'; destUrl += 'redirect_count=2'; diff --git a/tests/wpt/web-platform-tests/element-timing/observe-background-image.html b/tests/wpt/web-platform-tests/element-timing/observe-background-image.html index e02714b7021..6a43401cd0f 100644 --- a/tests/wpt/web-platform-tests/element-timing/observe-background-image.html +++ b/tests/wpt/web-platform-tests/element-timing/observe-background-image.html @@ -18,7 +18,7 @@ body { <script> let beforeRender = performance.now(); async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { assert_equals(entryList.getEntries().length, 1); diff --git a/tests/wpt/web-platform-tests/element-timing/observe-child-element.html b/tests/wpt/web-platform-tests/element-timing/observe-child-element.html index 4293e814eb9..c8071998c52 100644 --- a/tests/wpt/web-platform-tests/element-timing/observe-child-element.html +++ b/tests/wpt/web-platform-tests/element-timing/observe-child-element.html @@ -12,7 +12,7 @@ body { <script src="resources/element-timing-helpers.js"></script> <script> async_test((t) => { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done((entryList) => { assert_unreached("Should not have received an entry!"); diff --git a/tests/wpt/web-platform-tests/element-timing/observe-elementtiming.html b/tests/wpt/web-platform-tests/element-timing/observe-elementtiming.html index ee8960bd728..a204f0d6772 100644 --- a/tests/wpt/web-platform-tests/element-timing/observe-elementtiming.html +++ b/tests/wpt/web-platform-tests/element-timing/observe-elementtiming.html @@ -14,7 +14,7 @@ body { let beforeRender; let img; async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { assert_equals(entryList.getEntries().length, 1); diff --git a/tests/wpt/web-platform-tests/element-timing/observe-empty-attribute.html b/tests/wpt/web-platform-tests/element-timing/observe-empty-attribute.html index 25d3492f73b..baec6ee48d7 100644 --- a/tests/wpt/web-platform-tests/element-timing/observe-empty-attribute.html +++ b/tests/wpt/web-platform-tests/element-timing/observe-empty-attribute.html @@ -7,7 +7,7 @@ <script> let beforeRender; async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); let observedImage = false; let observedText = false; const observer = new PerformanceObserver( diff --git a/tests/wpt/web-platform-tests/element-timing/observe-multiple-images.html b/tests/wpt/web-platform-tests/element-timing/observe-multiple-images.html index 9a0657aa60f..c5ea700553b 100644 --- a/tests/wpt/web-platform-tests/element-timing/observe-multiple-images.html +++ b/tests/wpt/web-platform-tests/element-timing/observe-multiple-images.html @@ -22,7 +22,7 @@ body { <script> let beforeRender, image1Observed=0, image2Observed=0, image3Observed=0; async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func(function(entryList) { entryList.getEntries().forEach( entry => { diff --git a/tests/wpt/web-platform-tests/element-timing/observe-shadow-image.html b/tests/wpt/web-platform-tests/element-timing/observe-shadow-image.html index 1c12c5fe031..e2a81d62449 100644 --- a/tests/wpt/web-platform-tests/element-timing/observe-shadow-image.html +++ b/tests/wpt/web-platform-tests/element-timing/observe-shadow-image.html @@ -12,7 +12,7 @@ body { <div id='target'></div> <script> async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { assert_unreached('Should not observe elements in shadow trees!'); diff --git a/tests/wpt/web-platform-tests/element-timing/observe-shadow-text.html b/tests/wpt/web-platform-tests/element-timing/observe-shadow-text.html index 3167a1225c5..6e6347e60d2 100644 --- a/tests/wpt/web-platform-tests/element-timing/observe-shadow-text.html +++ b/tests/wpt/web-platform-tests/element-timing/observe-shadow-text.html @@ -12,7 +12,7 @@ body { <div id='target'></div> <script> async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { assert_unreached('Should not observe text elements in shadow trees!'); diff --git a/tests/wpt/web-platform-tests/element-timing/observe-svg-image.html b/tests/wpt/web-platform-tests/element-timing/observe-svg-image.html index 83ca4f40aae..737f94f92bc 100644 --- a/tests/wpt/web-platform-tests/element-timing/observe-svg-image.html +++ b/tests/wpt/web-platform-tests/element-timing/observe-svg-image.html @@ -7,7 +7,7 @@ <script> let beforeRender; async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { assert_equals(entryList.getEntries().length, 1); diff --git a/tests/wpt/web-platform-tests/element-timing/observe-text.html b/tests/wpt/web-platform-tests/element-timing/observe-text.html index a054b261726..5d8955269f8 100644 --- a/tests/wpt/web-platform-tests/element-timing/observe-text.html +++ b/tests/wpt/web-platform-tests/element-timing/observe-text.html @@ -15,7 +15,7 @@ p { <script src="resources/element-timing-helpers.js"></script> <script> async_test((t) => { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); let paragraph; let beforeRender; const observer = new PerformanceObserver( diff --git a/tests/wpt/web-platform-tests/element-timing/observe-video-poster.html b/tests/wpt/web-platform-tests/element-timing/observe-video-poster.html index f64da173c6f..56077335296 100644 --- a/tests/wpt/web-platform-tests/element-timing/observe-video-poster.html +++ b/tests/wpt/web-platform-tests/element-timing/observe-video-poster.html @@ -7,7 +7,7 @@ <script> let beforeRender; async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { assert_equals(entryList.getEntries().length, 1); diff --git a/tests/wpt/web-platform-tests/element-timing/progressively-loaded-image.html b/tests/wpt/web-platform-tests/element-timing/progressively-loaded-image.html index 0d59052cf3a..6695d8f9c32 100644 --- a/tests/wpt/web-platform-tests/element-timing/progressively-loaded-image.html +++ b/tests/wpt/web-platform-tests/element-timing/progressively-loaded-image.html @@ -14,7 +14,7 @@ let numInitial = 75; let sleep = 500; async_test(function(t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const img_src = 'resources/progressive-image.py?name=square20.jpg&numInitial=' + numInitial + '&sleep=' + sleep; const observer = new PerformanceObserver( diff --git a/tests/wpt/web-platform-tests/element-timing/rectangular-image.html b/tests/wpt/web-platform-tests/element-timing/rectangular-image.html index a97c549a9aa..65f190e7530 100644 --- a/tests/wpt/web-platform-tests/element-timing/rectangular-image.html +++ b/tests/wpt/web-platform-tests/element-timing/rectangular-image.html @@ -14,7 +14,7 @@ body { let beforeRender; let img; async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { assert_equals(entryList.getEntries().length, 1); diff --git a/tests/wpt/web-platform-tests/element-timing/redirects-tao-star.html b/tests/wpt/web-platform-tests/element-timing/redirects-tao-star.html index f8e4d19bd07..e5067d3d6bd 100644 --- a/tests/wpt/web-platform-tests/element-timing/redirects-tao-star.html +++ b/tests/wpt/web-platform-tests/element-timing/redirects-tao-star.html @@ -11,7 +11,7 @@ <body> <script> async_test(t => { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); let destUrl = get_host_info().HTTP_REMOTE_ORIGIN + '/resource-timing/resources/multi_redirect.py?'; destUrl += 'page_origin=' + get_host_info().HTTP_ORIGIN; diff --git a/tests/wpt/web-platform-tests/element-timing/retrievability.html b/tests/wpt/web-platform-tests/element-timing/retrievability.html index 5c6113bdc93..cd2c2a956e1 100644 --- a/tests/wpt/web-platform-tests/element-timing/retrievability.html +++ b/tests/wpt/web-platform-tests/element-timing/retrievability.html @@ -7,7 +7,7 @@ <script> let img; async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const beforeRender = performance.now(); new PerformanceObserver( t.step_func_done(function(entryList) { diff --git a/tests/wpt/web-platform-tests/element-timing/same-origin-redirects.html b/tests/wpt/web-platform-tests/element-timing/same-origin-redirects.html index 3527d805f3e..e52fcecc1ae 100644 --- a/tests/wpt/web-platform-tests/element-timing/same-origin-redirects.html +++ b/tests/wpt/web-platform-tests/element-timing/same-origin-redirects.html @@ -10,7 +10,7 @@ <body> <script> async_test(t => { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); // First redirect let destUrl = '/common/redirect.py?location=' // Second redirect diff --git a/tests/wpt/web-platform-tests/element-timing/scroll-to-text.html b/tests/wpt/web-platform-tests/element-timing/scroll-to-text.html index ca06e91c530..0508d2bcf99 100644 --- a/tests/wpt/web-platform-tests/element-timing/scroll-to-text.html +++ b/tests/wpt/web-platform-tests/element-timing/scroll-to-text.html @@ -15,7 +15,7 @@ <p elementtiming='observeMe'>Test text</p> <script> async_test((t) => { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver(t.step_func_done(() => {})); observer.observe({type: 'element', buffered: true}); window.onload = () => { diff --git a/tests/wpt/web-platform-tests/element-timing/text-with-display-style.html b/tests/wpt/web-platform-tests/element-timing/text-with-display-style.html index faf644fd8d2..94e89fcf727 100644 --- a/tests/wpt/web-platform-tests/element-timing/text-with-display-style.html +++ b/tests/wpt/web-platform-tests/element-timing/text-with-display-style.html @@ -21,7 +21,7 @@ h3 { <h3 id='title3' elementtiming='h3'>I am h3</h3> <script> async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const beforeRender = performance.now(); let observedFlex = false; let observedGrid = false; diff --git a/tests/wpt/web-platform-tests/element-timing/toJSON.html b/tests/wpt/web-platform-tests/element-timing/toJSON.html index ba13a0fa907..24c7d1e0a65 100644 --- a/tests/wpt/web-platform-tests/element-timing/toJSON.html +++ b/tests/wpt/web-platform-tests/element-timing/toJSON.html @@ -8,7 +8,7 @@ <img elementtiming='img' src="resources/square100.png"/> <script> async_test(function (t) { - assert_precondition(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); + assert_implements(window.PerformanceElementTiming, "PerformanceElementTiming is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { assert_equals(entryList.getEntries().length, 1); diff --git a/tests/wpt/web-platform-tests/event-timing/buffered-flag.html b/tests/wpt/web-platform-tests/event-timing/buffered-flag.html index dc70ff253ff..7ee152be938 100644 --- a/tests/wpt/web-platform-tests/event-timing/buffered-flag.html +++ b/tests/wpt/web-platform-tests/event-timing/buffered-flag.html @@ -12,7 +12,7 @@ let firstInputSeen = false; let eventSeen = false; async_test(t => { - assert_precondition(window.PerformanceEventTiming, 'Event Timing is not supported.'); + assert_implements(window.PerformanceEventTiming, 'Event Timing is not supported.'); const validateEntry = t.step_func(entry => { if (entry.entryType === 'first-input') firstInputSeen = true; diff --git a/tests/wpt/web-platform-tests/event-timing/click-timing.html b/tests/wpt/web-platform-tests/event-timing/click-timing.html index 376372a3f11..4544734f73f 100644 --- a/tests/wpt/web-platform-tests/event-timing/click-timing.html +++ b/tests/wpt/web-platform-tests/event-timing/click-timing.html @@ -21,7 +21,7 @@ let timeAfterSecondClick; let observedEntries = []; async_test(function(t) { - assert_precondition(window.PerformanceEventTiming, 'Event Timing is not supported.'); + assert_implements(window.PerformanceEventTiming, 'Event Timing is not supported.'); new PerformanceObserver(t.step_func(entryList => { observedEntries = observedEntries.concat(entryList.getEntries().filter( entry => entry.name === 'mousedown')); diff --git a/tests/wpt/web-platform-tests/event-timing/crossiframe.html b/tests/wpt/web-platform-tests/event-timing/crossiframe.html index 55e2becfcbc..71140868434 100644 --- a/tests/wpt/web-platform-tests/event-timing/crossiframe.html +++ b/tests/wpt/web-platform-tests/event-timing/crossiframe.html @@ -48,7 +48,7 @@ } promise_test(async t => { - assert_precondition(window.PerformanceEventTiming, "Event Timing is not supported"); + assert_implements(window.PerformanceEventTiming, "Event Timing is not supported"); clickTimeMin = performance.now(); let observedEntries = false; const observerPromise = new Promise(resolve => { diff --git a/tests/wpt/web-platform-tests/event-timing/event-click-counts.html b/tests/wpt/web-platform-tests/event-timing/event-click-counts.html index 034e172c1df..d4e87c58969 100644 --- a/tests/wpt/web-platform-tests/event-timing/event-click-counts.html +++ b/tests/wpt/web-platform-tests/event-timing/event-click-counts.html @@ -10,7 +10,7 @@ <button id='button'>Click me</button> <script> promise_test( t => { - assert_precondition(window.EventCounts, "Event Counts isn't supported"); + assert_implements(window.EventCounts, "Event Counts isn't supported"); function testClicks(expectedCount, resolve) { const clickCount = performance.eventCounts.get('click'); if (clickCount < expectedCount) { diff --git a/tests/wpt/web-platform-tests/event-timing/event-counts-zero.html b/tests/wpt/web-platform-tests/event-timing/event-counts-zero.html index 0cc9e2ee38a..3ec90dd6913 100644 --- a/tests/wpt/web-platform-tests/event-timing/event-counts-zero.html +++ b/tests/wpt/web-platform-tests/event-timing/event-counts-zero.html @@ -8,7 +8,7 @@ <script src=/resources/testdriver-vendor.js></script> <script> test(() => { - assert_precondition(window.EventCounts, "Event Counts isn't supported"); + assert_implements(window.EventCounts, "Event Counts isn't supported"); const eventTypes = [ 'auxclick', 'click', diff --git a/tests/wpt/web-platform-tests/event-timing/only-observe-firstInput.html b/tests/wpt/web-platform-tests/event-timing/only-observe-firstInput.html index ad71153d40b..54a6036f91a 100644 --- a/tests/wpt/web-platform-tests/event-timing/only-observe-firstInput.html +++ b/tests/wpt/web-platform-tests/event-timing/only-observe-firstInput.html @@ -20,7 +20,7 @@ PerformanceObserver should observe one and only one entry. */ async_test(function(t) { - assert_precondition(window.PerformanceEventTiming, 'Event Timing is not supported.'); + assert_implements(window.PerformanceEventTiming, 'Event Timing is not supported.'); let hasObservedFirstInput = false; new PerformanceObserver(t.step_func((entryList) => { assert_false(hasObservedFirstInput); diff --git a/tests/wpt/web-platform-tests/event-timing/programmatic-click-not-observed.html b/tests/wpt/web-platform-tests/event-timing/programmatic-click-not-observed.html index 1c2921ca489..0a189b0bc2a 100644 --- a/tests/wpt/web-platform-tests/event-timing/programmatic-click-not-observed.html +++ b/tests/wpt/web-platform-tests/event-timing/programmatic-click-not-observed.html @@ -18,7 +18,7 @@ delayCalled = true; } async_test(function(t) { - assert_precondition(window.PerformanceEventTiming, 'Event Timing is not supported.'); + assert_implements(window.PerformanceEventTiming, 'Event Timing is not supported.'); const observer = new PerformanceObserver(t.step_func_done((entryList) => { const entries = entryList.getEntries().filter(e => e.name === 'mousedown'); // There must only be one click entry: from the clickAndBlockMain() call. diff --git a/tests/wpt/web-platform-tests/event-timing/retrievability.html b/tests/wpt/web-platform-tests/event-timing/retrievability.html index d2b6da2439f..087cd13184b 100644 --- a/tests/wpt/web-platform-tests/event-timing/retrievability.html +++ b/tests/wpt/web-platform-tests/event-timing/retrievability.html @@ -30,7 +30,7 @@ Validate entries */ async_test(function(t) { - assert_precondition(window.PerformanceEventTiming, 'Event Timing is not supported.'); + assert_implements(window.PerformanceEventTiming, 'Event Timing is not supported.'); new PerformanceObserver(t.step_func_done(() => { validateEntries(); t.done(); diff --git a/tests/wpt/web-platform-tests/event-timing/retrieve-firstInput.html b/tests/wpt/web-platform-tests/event-timing/retrieve-firstInput.html index acff788259f..27b17cd1816 100644 --- a/tests/wpt/web-platform-tests/event-timing/retrieve-firstInput.html +++ b/tests/wpt/web-platform-tests/event-timing/retrieve-firstInput.html @@ -12,7 +12,7 @@ <script> async_test(function(t) { - assert_precondition(window.PerformanceEventTiming, 'Event Timing is not supported.'); + assert_implements(window.PerformanceEventTiming, 'Event Timing is not supported.'); function testEntries() { // First callback is not ensured to have the entry. if (performance.getEntriesByType('first-input').length === 0) { diff --git a/tests/wpt/web-platform-tests/event-timing/supported-types.window.js b/tests/wpt/web-platform-tests/event-timing/supported-types.window.js index 5360bdd9e82..1cc43495c09 100644 --- a/tests/wpt/web-platform-tests/event-timing/supported-types.window.js +++ b/tests/wpt/web-platform-tests/event-timing/supported-types.window.js @@ -1,6 +1,6 @@ test(() => { - assert_precondition(window.PerformanceEventTiming, 'Event Timing is not supported.'); - assert_precondition(typeof PerformanceObserver.supportedEntryTypes !== "undefined", + assert_implements(window.PerformanceEventTiming, 'Event Timing is not supported.'); + assert_implements(typeof PerformanceObserver.supportedEntryTypes !== "undefined", 'supportedEntryTypes is not supported'); const types = PerformanceObserver.supportedEntryTypes; assert_true(types.includes("first-input"), diff --git a/tests/wpt/web-platform-tests/event-timing/timingconditions.html b/tests/wpt/web-platform-tests/event-timing/timingconditions.html index 02da2976cee..12280cb894a 100644 --- a/tests/wpt/web-platform-tests/event-timing/timingconditions.html +++ b/tests/wpt/web-platform-tests/event-timing/timingconditions.html @@ -35,7 +35,7 @@ } async_test(function(t) { - assert_precondition(window.PerformanceEventTiming, 'Event Timing is not supported.'); + assert_implements(window.PerformanceEventTiming, 'Event Timing is not supported.'); new PerformanceObserver(t.step_func_done(entryList => { const observerCallbackTime = performance.now(); const entries = entryList.getEntries().filter( diff --git a/tests/wpt/web-platform-tests/event-timing/toJSON.html b/tests/wpt/web-platform-tests/event-timing/toJSON.html index a11073aa9a0..a2d7df42da5 100644 --- a/tests/wpt/web-platform-tests/event-timing/toJSON.html +++ b/tests/wpt/web-platform-tests/event-timing/toJSON.html @@ -10,7 +10,7 @@ <button id='button'>Generate a 'click' event</button> <script> async_test(function (t) { - assert_precondition(window.PerformanceEventTiming, 'Event Timing is not supported.'); + assert_implements(window.PerformanceEventTiming, 'Event Timing is not supported.'); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { const entry = entryList.getEntries()[0]; diff --git a/tests/wpt/web-platform-tests/fetch/metadata/portal.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/portal.https.sub.html index 96067ae82ab..8403a296fe1 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/portal.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/portal.https.sub.html @@ -12,7 +12,7 @@ function create_test(host, expectations) { async_test(t => { - assert_precondition("HTMLPortalElement" in window, "Portals are not supported."); + assert_implements("HTMLPortalElement" in window, "Portals are not supported."); let p = document.createElement('portal'); p.addEventListener('message', t.step_func(e => { diff --git a/tests/wpt/web-platform-tests/html/browsers/history/the-history-interface/001.html b/tests/wpt/web-platform-tests/html/browsers/history/the-history-interface/001.html index b4a5fd4bf4d..6d48d108bbe 100644 --- a/tests/wpt/web-platform-tests/html/browsers/history/the-history-interface/001.html +++ b/tests/wpt/web-platform-tests/html/browsers/history/the-history-interface/001.html @@ -274,8 +274,8 @@ function reportload() { assert_false( cloneobj === iframe.contentWindow.history.state ); }, 'history.state should be a clone of the original object, not a reference to it (2)'); test(function () { - assert_false( iframe.contentWindow.history.state === ev.state ); - }, 'history.state should be a separate clone of the object, not a reference to the object passed to the event handler'); + assert_true( iframe.contentWindow.history.state === ev.state ); + }, 'history.state should be identical to the object passed to the event handler unless history.state is updated'); try { iframe.contentWindow.persistval = true; iframe.contentWindow.history.pushState('','', location.href.replace(/\/[^\/]*$/,'/blank3.html') ); diff --git a/tests/wpt/web-platform-tests/html/browsers/history/the-history-interface/002.html b/tests/wpt/web-platform-tests/html/browsers/history/the-history-interface/002.html index dcda248282f..c054246770f 100644 --- a/tests/wpt/web-platform-tests/html/browsers/history/the-history-interface/002.html +++ b/tests/wpt/web-platform-tests/html/browsers/history/the-history-interface/002.html @@ -249,8 +249,8 @@ function reportload() { assert_false( cloneobj === iframe.contentWindow.history.state ); }, 'history.state should be a clone of the original object, not a reference to it (2)'); test(function () { - assert_false( iframe.contentWindow.history.state === ev.state ); - }, 'history.state should be a separate clone of the object, not a reference to the object passed to the event handler'); + assert_true( iframe.contentWindow.history.state === ev.state ); + }, 'history.state should be identical to the object passed to the event handler unless history.state is updated'); try { iframe.contentWindow.persistval = true; iframe.contentWindow.history.replaceState('','', location.href.replace(/\/[^\/]*$/,'/blank3.html') ); diff --git a/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/resources/reporting-empty-frame.html.headers b/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/resources/reporting-empty-frame.html.headers index 66302f108fd..b7c8b304178 100644 --- a/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/resources/reporting-empty-frame.html.headers +++ b/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/resources/reporting-empty-frame.html.headers @@ -1,2 +1,2 @@ cross-origin-embedder-policy: require-corp; report-to="endpoint" -cross-origin-embedder-policy-report-only: require-corp; report-to="report-only-endpoint"; +cross-origin-embedder-policy-report-only: require-corp; report-to="report-only-endpoint" diff --git a/tests/wpt/web-platform-tests/html/rendering/widgets/baseline-alignment-and-overflow.tentative.html b/tests/wpt/web-platform-tests/html/rendering/widgets/baseline-alignment-and-overflow.tentative.html index 1c0b312eb45..5f677b5f0f6 100644 --- a/tests/wpt/web-platform-tests/html/rendering/widgets/baseline-alignment-and-overflow.tentative.html +++ b/tests/wpt/web-platform-tests/html/rendering/widgets/baseline-alignment-and-overflow.tentative.html @@ -174,7 +174,7 @@ This table gets populated by the script. // wait for images to load await new Promise(resolve => window.onload = e => resolve()); for (const img of document.images) { - assert_precondition(img.complete); // either error state or loaded + assert_true(img.complete); // either error state or loaded } // get layout info from refs @@ -218,7 +218,7 @@ This table gets populated by the script. const allowedDelta = 3; // This is not using test() because promise_setup() only allows promise_test(). promise_test(async () => { - assert_precondition(input.type === input.getAttribute('type'), 'input type should be supported') + assert_equals(input.type, input.getAttribute('type'), 'input type should be supported') const offsetTopActual = row.firstChild.firstChild.offsetTop; assert_approx_equals(offsetTopActual, expectedOffsetTop(input), allowedDelta, '<span>.offsetTop'); }, testName(input.outerHTML)); diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-img-element/currentSrc-blob-cache.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-img-element/currentSrc-blob-cache.html new file mode 100644 index 00000000000..a5e108dcd6e --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-img-element/currentSrc-blob-cache.html @@ -0,0 +1,45 @@ +<!doctype html> +<meta charset="utf-8"> +<title>currentSrc is right even if underlying image is a shared blob</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1625786"> +<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io"> +<link rel="author" title="Mozilla" href="https://mozilla.org"> +<img id="first"> +<img id="second"> +<script> +promise_test(async t => { + let canvas = document.createElement("canvas"); + canvas.width = 100; + canvas.height = 100; + let ctx = canvas.getContext("2d"); + ctx.fillStyle = "green"; + ctx.rect(0, 0, 100, 100); + ctx.fill(); + + let blob = await new Promise(resolve => canvas.toBlob(resolve)); + + let first = document.querySelector("#first"); + let second = document.querySelector("#second"); + + let firstLoad = new Promise(resolve => { + first.addEventListener("load", resolve, { once: true }); + }); + + let secondLoad = new Promise(resolve => { + second.addEventListener("load", resolve, { once: true }); + }); + + let uri1 = URL.createObjectURL(blob); + let uri2 = URL.createObjectURL(blob); + first.src = uri1; + second.src = uri2; + + await firstLoad; + await secondLoad; + + assert_equals(first.src, first.currentSrc); + assert_equals(second.src, second.currentSrc); +}); +</script> diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-video-element/resize-during-playback.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-video-element/resize-during-playback.html index 3ade1effc4b..1b057bbeac3 100644 --- a/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-video-element/resize-during-playback.html +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-video-element/resize-during-playback.html @@ -12,7 +12,7 @@ for (const format of ['mp4', 'webm']) { promise_test(async (t) => { const video = document.createElement('video'); - assert_precondition(video.canPlayType(`video/${format}`), `${format} supported`); + assert_implements_optional(video.canPlayType(`video/${format}`), `${format} supported`); // Load the video and wait for initial resize event. video.src = `/media/400x300-red-resize-200x150-green.${format}`; diff --git a/tests/wpt/web-platform-tests/interfaces/netinfo.idl b/tests/wpt/web-platform-tests/interfaces/netinfo.idl index 72967839688..530deb998c4 100644 --- a/tests/wpt/web-platform-tests/interfaces/netinfo.idl +++ b/tests/wpt/web-platform-tests/interfaces/netinfo.idl @@ -36,7 +36,6 @@ interface NetworkInformation : EventTarget { readonly attribute Megabit downlinkMax; readonly attribute Megabit downlink; readonly attribute Millisecond rtt; - readonly attribute boolean saveData; attribute EventHandler onchange; }; diff --git a/tests/wpt/web-platform-tests/interfaces/webauthn.idl b/tests/wpt/web-platform-tests/interfaces/webauthn.idl index 8dceeb5768b..34a3df1ce1a 100644 --- a/tests/wpt/web-platform-tests/interfaces/webauthn.idl +++ b/tests/wpt/web-platform-tests/interfaces/webauthn.idl @@ -166,65 +166,6 @@ partial dictionary AuthenticationExtensionsClientInputs { }; partial dictionary AuthenticationExtensionsClientInputs { - USVString txAuthSimple; -}; - -partial dictionary AuthenticationExtensionsClientOutputs { - USVString txAuthSimple; -}; - -dictionary txAuthGenericArg { - required USVString contentType; // MIME-Type of the content, e.g., "image/png" - required ArrayBuffer content; -}; - -partial dictionary AuthenticationExtensionsClientInputs { - txAuthGenericArg txAuthGeneric; -}; - -partial dictionary AuthenticationExtensionsClientOutputs { - ArrayBuffer txAuthGeneric; -}; - -typedef sequence<AAGUID> AuthenticatorSelectionList; - -partial dictionary AuthenticationExtensionsClientInputs { - AuthenticatorSelectionList authnSel; -}; - -typedef BufferSource AAGUID; - -partial dictionary AuthenticationExtensionsClientOutputs { - boolean authnSel; -}; - -partial dictionary AuthenticationExtensionsClientInputs { - boolean exts; -}; - -typedef sequence<USVString> AuthenticationExtensionsSupported; - -partial dictionary AuthenticationExtensionsClientOutputs { - AuthenticationExtensionsSupported exts; -}; - -partial dictionary AuthenticationExtensionsClientInputs { - boolean uvi; -}; - -partial dictionary AuthenticationExtensionsClientOutputs { - ArrayBuffer uvi; -}; - -partial dictionary AuthenticationExtensionsClientInputs { - boolean loc; -}; - -partial dictionary AuthenticationExtensionsClientOutputs { - GeolocationCoordinates loc; -}; - -partial dictionary AuthenticationExtensionsClientInputs { boolean uvm; }; @@ -235,11 +176,6 @@ partial dictionary AuthenticationExtensionsClientOutputs { UvmEntries uvm; }; -dictionary AuthenticatorBiometricPerfBounds { - float FAR; - float FRR; -}; - partial dictionary AuthenticationExtensionsClientInputs { boolean credProps; }; diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/contracted-image.html b/tests/wpt/web-platform-tests/largest-contentful-paint/contracted-image.html index ed6adfb2c7c..8816bf4ba99 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/contracted-image.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/contracted-image.html @@ -13,7 +13,7 @@ <script src="resources/largest-contentful-paint-helpers.js"></script> <script> async_test(function (t) { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); const beforeLoad = performance.now(); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/cross-origin-image.sub.html b/tests/wpt/web-platform-tests/largest-contentful-paint/cross-origin-image.sub.html index be0c8a1e11e..0cfdd1791ba 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/cross-origin-image.sub.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/cross-origin-image.sub.html @@ -7,7 +7,7 @@ <script src="resources/largest-contentful-paint-helpers.js"></script> <script> async_test(function (t) { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); const beforeLoad = performance.now(); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/expanded-image.html b/tests/wpt/web-platform-tests/largest-contentful-paint/expanded-image.html index e0b3545c21c..55adff91f2f 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/expanded-image.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/expanded-image.html @@ -13,7 +13,7 @@ <script src="resources/largest-contentful-paint-helpers.js"></script> <script> async_test(function (t) { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); const beforeLoad = performance.now(); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/first-letter-background.html b/tests/wpt/web-platform-tests/largest-contentful-paint/first-letter-background.html index 80b8f1891fd..09fe1f5beb6 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/first-letter-background.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/first-letter-background.html @@ -15,7 +15,7 @@ div { <script src="resources/largest-contentful-paint-helpers.js"></script> <script> async_test(function (t) { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); let beforeLoad = performance.now(); let observedFirstLetter = false; const observer = new PerformanceObserver( diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/first-paint-equals-lcp-text.html b/tests/wpt/web-platform-tests/largest-contentful-paint/first-paint-equals-lcp-text.html index 7a01cb15943..97eb67e320e 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/first-paint-equals-lcp-text.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/first-paint-equals-lcp-text.html @@ -6,8 +6,8 @@ <script src="/resources/testharnessreport.js"></script> <script> async_test(function (t) { - assert_precondition(window.PerformancePaintTiming, "PerformancePaintTiming is not implemented"); - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.PerformancePaintTiming, "PerformancePaintTiming is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); let firstPaintTime = 0; let firstContentfulPaintTime = 0; let largestContentfulPaintTime = 0; diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/iframe-content-not-observed.html b/tests/wpt/web-platform-tests/largest-contentful-paint/iframe-content-not-observed.html index ea8e0d79f38..e605e9f21f6 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/iframe-content-not-observed.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/iframe-content-not-observed.html @@ -8,7 +8,7 @@ <body> <script> async_test((t) => { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); const observer = new PerformanceObserver( t.step_func_done(entryList => { assert_unreached("Should not have received an entry!"); diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/image-src-change.html b/tests/wpt/web-platform-tests/largest-contentful-paint/image-src-change.html index cbe46f402b4..bd78476390c 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/image-src-change.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/image-src-change.html @@ -8,7 +8,7 @@ <img src='/images/blue.png' id='image_id'/> <script> async_test(function (t) { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); let beforeLoad = performance.now(); let firstCallback = true; const observer = new PerformanceObserver( diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/larger-image.html b/tests/wpt/web-platform-tests/largest-contentful-paint/larger-image.html index a571b8afe79..a9675386a08 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/larger-image.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/larger-image.html @@ -13,7 +13,7 @@ <p>More text!</p> <script> async_test(function (t) { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); const beforeLoad = performance.now(); const observer = new PerformanceObserver( t.step_func(entryList => { diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/larger-text.html b/tests/wpt/web-platform-tests/largest-contentful-paint/larger-text.html index af8bbc06b32..ca711f22411 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/larger-text.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/larger-text.html @@ -18,7 +18,7 @@ <img src='/images/green-2x2.png'/> <script> async_test(function (t) { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); let beforeRender; const observer = new PerformanceObserver( t.step_func(entryList => { diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/loadTime-after-appendChild.html b/tests/wpt/web-platform-tests/largest-contentful-paint/loadTime-after-appendChild.html index f320b03df4d..2d19e73e60f 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/loadTime-after-appendChild.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/loadTime-after-appendChild.html @@ -7,7 +7,7 @@ <script src="resources/largest-contentful-paint-helpers.js"></script> <script> async_test(function (t) { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); let beforeLoad; const observer = new PerformanceObserver( t.step_func_done(entryList => { diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/multiple-redirects-TAO.html b/tests/wpt/web-platform-tests/largest-contentful-paint/multiple-redirects-TAO.html index ec8ddc3ec61..ee832c41043 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/multiple-redirects-TAO.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/multiple-redirects-TAO.html @@ -12,7 +12,7 @@ <body> <script> async_test(t => { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); let destUrl = get_host_info().HTTP_REMOTE_ORIGIN + '/element-timing/resources/multiple-redirects.py?'; destUrl += 'redirect_count=2'; diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/observe-after-untrusted-scroll.html b/tests/wpt/web-platform-tests/largest-contentful-paint/observe-after-untrusted-scroll.html index 4a1a214c833..c84f922e5e5 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/observe-after-untrusted-scroll.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/observe-after-untrusted-scroll.html @@ -7,7 +7,7 @@ <script src="resources/largest-contentful-paint-helpers.js"></script> <script> async_test(function (t) { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); const beforeLoad = performance.now(); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/observe-image.html b/tests/wpt/web-platform-tests/largest-contentful-paint/observe-image.html index 58eb5364a92..707840671b1 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/observe-image.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/observe-image.html @@ -7,7 +7,7 @@ <script src="resources/largest-contentful-paint-helpers.js"></script> <script> async_test(function (t) { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); const beforeLoad = performance.now(); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/observe-text.html b/tests/wpt/web-platform-tests/largest-contentful-paint/observe-text.html index 402fcd80195..a0a07d9422d 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/observe-text.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/observe-text.html @@ -11,7 +11,7 @@ p { </style> <script> async_test(function (t) { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); let beforeRender; const observer = new PerformanceObserver( t.step_func_done(function(entryList) { diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/redirects-tao-star.html b/tests/wpt/web-platform-tests/largest-contentful-paint/redirects-tao-star.html index 0667266e6d2..1daea61486c 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/redirects-tao-star.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/redirects-tao-star.html @@ -11,7 +11,7 @@ <body> <script> async_test(t => { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); let destUrl = get_host_info().HTTP_REMOTE_ORIGIN + '/resource-timing/resources/multi_redirect.py?'; destUrl += 'page_origin=' + get_host_info().HTTP_ORIGIN; diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/repeated-image.html b/tests/wpt/web-platform-tests/largest-contentful-paint/repeated-image.html index 8c3c8909099..a28409a848c 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/repeated-image.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/repeated-image.html @@ -13,7 +13,7 @@ <script src="resources/largest-contentful-paint-helpers.js"></script> <script> async_test(function (t) { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); let beforeLoad = performance.now(); let firstCallback = true; const url = window.location.origin + '/images/black-rectangle.png'; diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/resources/invisible-images.js b/tests/wpt/web-platform-tests/largest-contentful-paint/resources/invisible-images.js index fd13e9454de..bad078e35f0 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/resources/invisible-images.js +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/resources/invisible-images.js @@ -1,5 +1,5 @@ async_test(t => { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); const observer = new PerformanceObserver( t.step_func(entryList => { entryList.getEntries().forEach(entry => { diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/same-origin-redirects.html b/tests/wpt/web-platform-tests/largest-contentful-paint/same-origin-redirects.html index e17fdbb69e6..b5cf9da2d12 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/same-origin-redirects.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/same-origin-redirects.html @@ -10,7 +10,7 @@ <body> <script> async_test(t => { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); // First redirect let destUrl = '/common/redirect.py?location=' // Second redirect diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/text-with-display-style.html b/tests/wpt/web-platform-tests/largest-contentful-paint/text-with-display-style.html index 24541541a8b..e041a9fc21a 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/text-with-display-style.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/text-with-display-style.html @@ -12,7 +12,7 @@ <h1 id='title'>I am a title!</h1> <script> async_test(function (t) { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); let beforeRender; /* In this test, we first observe a header with style 'display: flex'. * Once observed, we remove it and add a header with style 'display: grid'. diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/toJSON.html b/tests/wpt/web-platform-tests/largest-contentful-paint/toJSON.html index 25be5eb2dc9..36e2a7fdfa2 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/toJSON.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/toJSON.html @@ -7,7 +7,7 @@ <p>Text!</p> <script> async_test(function (t) { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { const entry = entryList.getEntries()[0]; diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/video-poster.html b/tests/wpt/web-platform-tests/largest-contentful-paint/video-poster.html index 535f30e2565..b3a29188630 100644 --- a/tests/wpt/web-platform-tests/largest-contentful-paint/video-poster.html +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/video-poster.html @@ -6,7 +6,7 @@ <script src="resources/largest-contentful-paint-helpers.js"></script> <script> async_test(function (t) { - assert_precondition(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); + assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"); const beforeLoad = performance.now(); const observer = new PerformanceObserver( t.step_func_done(function(entryList) { diff --git a/tests/wpt/web-platform-tests/layout-instability/buffer-layout-shift.html b/tests/wpt/web-platform-tests/layout-instability/buffer-layout-shift.html index 50cabda8d20..705569f96cf 100644 --- a/tests/wpt/web-platform-tests/layout-instability/buffer-layout-shift.html +++ b/tests/wpt/web-platform-tests/layout-instability/buffer-layout-shift.html @@ -11,7 +11,7 @@ <script src="resources/util.js"></script> <script> promise_test(async t => { - assert_precondition(window.LayoutShift, 'Layout Instability is not supported.'); + assert_implements(window.LayoutShift, 'Layout Instability is not supported.'); // Wait for the initial render to complete. await waitForAnimationFrames(2); diff --git a/tests/wpt/web-platform-tests/layout-instability/buffered-flag.html b/tests/wpt/web-platform-tests/layout-instability/buffered-flag.html index 1d200712c28..1c672624732 100644 --- a/tests/wpt/web-platform-tests/layout-instability/buffered-flag.html +++ b/tests/wpt/web-platform-tests/layout-instability/buffered-flag.html @@ -11,7 +11,7 @@ <script src="resources/util.js"></script> <script> promise_test(async t => { - assert_precondition(window.LayoutShift, 'Layout Instability is not supported.'); + assert_implements(window.LayoutShift, 'Layout Instability is not supported.'); // Wait for the initial render to complete. await waitForAnimationFrames(2); diff --git a/tests/wpt/web-platform-tests/layout-instability/recent-input.html b/tests/wpt/web-platform-tests/layout-instability/recent-input.html index 52adbf723ea..292b683bcb5 100644 --- a/tests/wpt/web-platform-tests/layout-instability/recent-input.html +++ b/tests/wpt/web-platform-tests/layout-instability/recent-input.html @@ -22,7 +22,7 @@ let timeAfterClick; promise_test(async t => { - assert_precondition(window.LayoutShift, 'Layout Instability is not supported.'); + assert_implements(window.LayoutShift, 'Layout Instability is not supported.'); // Wait for the initial render to complete. await waitForAnimationFrames(2); diff --git a/tests/wpt/web-platform-tests/layout-instability/supported-layout-type.html b/tests/wpt/web-platform-tests/layout-instability/supported-layout-type.html index cee4b808c87..3ba209f50a4 100644 --- a/tests/wpt/web-platform-tests/layout-instability/supported-layout-type.html +++ b/tests/wpt/web-platform-tests/layout-instability/supported-layout-type.html @@ -7,8 +7,8 @@ <script src="/resources/testharnessreport.js"></script> <script> test(() => { - assert_precondition(window.LayoutShift, 'Layout Instability is not supported.'); - assert_precondition(typeof PerformanceObserver.supportedEntryTypes !== "undefined", + assert_implements(window.LayoutShift, 'Layout Instability is not supported.'); + assert_implements(typeof PerformanceObserver.supportedEntryTypes !== "undefined", 'supportedEntryTypes is not supported.'); assert_greater_than(PerformanceObserver.supportedEntryTypes.indexOf("layout-shift"), -1, "There should be an entry 'layout-shift' in PerformanceObserver.supportedEntryTypes"); diff --git a/tests/wpt/web-platform-tests/layout-instability/toJSON.html b/tests/wpt/web-platform-tests/layout-instability/toJSON.html index 00f074a4dd8..711cd238431 100644 --- a/tests/wpt/web-platform-tests/layout-instability/toJSON.html +++ b/tests/wpt/web-platform-tests/layout-instability/toJSON.html @@ -11,7 +11,7 @@ <script src="resources/util.js"></script> <script> promise_test(async t => { - assert_precondition(window.LayoutShift, 'Layout Instability is not supported.'); + assert_implements(window.LayoutShift, 'Layout Instability is not supported.'); // Wait for the initial render to complete. await waitForAnimationFrames(2); diff --git a/tests/wpt/web-platform-tests/longtask-timing/buffered-flag.window.js b/tests/wpt/web-platform-tests/longtask-timing/buffered-flag.window.js index f1ca54f5322..88e1363beba 100644 --- a/tests/wpt/web-platform-tests/longtask-timing/buffered-flag.window.js +++ b/tests/wpt/web-platform-tests/longtask-timing/buffered-flag.window.js @@ -1,5 +1,5 @@ async_test(t => { - assert_precondition(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); new PerformanceObserver(t.step_func((entryList, obs) => { const observer = new PerformanceObserver(t.step_func_done(list => { let longtaskObserved = false; diff --git a/tests/wpt/web-platform-tests/longtask-timing/containerTypes.html b/tests/wpt/web-platform-tests/longtask-timing/containerTypes.html index 94daab793c6..5a703f3995c 100644 --- a/tests/wpt/web-platform-tests/longtask-timing/containerTypes.html +++ b/tests/wpt/web-platform-tests/longtask-timing/containerTypes.html @@ -19,7 +19,7 @@ const Containers = [ ]; Containers.forEach(container => { promise_test(async t => { - assert_precondition(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); const initialTime = performance.now(); return new Promise(resolve => { const observer = new PerformanceObserver(t.step_func(entryList => { diff --git a/tests/wpt/web-platform-tests/longtask-timing/long-microtask.window.js b/tests/wpt/web-platform-tests/longtask-timing/long-microtask.window.js index 9219fdb5c49..ef16f00dbe5 100644 --- a/tests/wpt/web-platform-tests/longtask-timing/long-microtask.window.js +++ b/tests/wpt/web-platform-tests/longtask-timing/long-microtask.window.js @@ -1,5 +1,5 @@ async_test(function (t) { - assert_precondition(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); new PerformanceObserver( t.step_func_done(entryList => { const entries = entryList.getEntries(); diff --git a/tests/wpt/web-platform-tests/longtask-timing/longtask-attributes.html b/tests/wpt/web-platform-tests/longtask-timing/longtask-attributes.html index 24540d7c22f..9af1c7bf95b 100644 --- a/tests/wpt/web-platform-tests/longtask-timing/longtask-attributes.html +++ b/tests/wpt/web-platform-tests/longtask-timing/longtask-attributes.html @@ -10,7 +10,7 @@ <div id="log"></div> <script> async_test(function (t) { - assert_precondition(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); const observer = new PerformanceObserver( t.step_func(function (entryList) { const entries = entryList.getEntries(); diff --git a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-childiframe-crossorigin.html b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-childiframe-crossorigin.html index 20a94a1eef4..d0fdf742804 100644 --- a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-childiframe-crossorigin.html +++ b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-childiframe-crossorigin.html @@ -10,7 +10,7 @@ <div id="log"></div> <script> async_test(function (t) { - assert_precondition(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); const observer = new PerformanceObserver( t.step_func(function (entryList) { const entries = entryList.getEntries(); diff --git a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-childiframe.html b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-childiframe.html index 4feae7e55c1..4c325c42adb 100644 --- a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-childiframe.html +++ b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-childiframe.html @@ -11,7 +11,7 @@ <script> const initialTime = performance.now(); async_test(function (t) { - assert_precondition(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); const observer = new PerformanceObserver( t.step_func(function (entryList) { const entries = entryList.getEntries(); diff --git a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-externalscript.html b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-externalscript.html index db5c9db4a16..8636025cf28 100644 --- a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-externalscript.html +++ b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-externalscript.html @@ -10,7 +10,7 @@ <div id="log"></div> <script> async_test(function (t) { - assert_precondition(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); const observer = new PerformanceObserver( t.step_func(function (entryList) { const entries = entryList.getEntries(); diff --git a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-parentiframe.html b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-parentiframe.html index c6b7e3e5838..7fd5fb672bd 100644 --- a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-parentiframe.html +++ b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-parentiframe.html @@ -8,7 +8,7 @@ <script> const t = async_test(t => { - assert_precondition(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); window.addEventListener('message', t.step_func(e => { assert_equals(e.data['entryType'], 'longtask'); assert_equals(e.data['frame-attribution'], 'same-origin-ancestor'); diff --git a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-raf.html b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-raf.html index 110ae751ee3..40508e1e677 100644 --- a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-raf.html +++ b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-raf.html @@ -10,7 +10,7 @@ <div id="log"></div> <script> async_test(function (t) { - assert_precondition(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); const observer = new PerformanceObserver( t.step_func(function (entryList) { const entries = entryList.getEntries(); diff --git a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-sibling-iframe-crossorigin.html b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-sibling-iframe-crossorigin.html index ba9c7170626..d66fe0c63ba 100644 --- a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-sibling-iframe-crossorigin.html +++ b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-sibling-iframe-crossorigin.html @@ -8,7 +8,7 @@ <script> async_test(t => { - assert_precondition(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); window.addEventListener('message', t.step_func(e => { assert_equals(e.data['entryType'], 'longtask'); assert_equals(e.data['frame-attribution'], 'cross-origin-unreachable'); diff --git a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-sibling-iframe.html b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-sibling-iframe.html index 8f530fab069..396a9beeeaa 100644 --- a/tests/wpt/web-platform-tests/longtask-timing/longtask-in-sibling-iframe.html +++ b/tests/wpt/web-platform-tests/longtask-timing/longtask-in-sibling-iframe.html @@ -8,7 +8,7 @@ <script> async_test(t => { - assert_precondition(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); window.addEventListener('message', t.step_func(e => { assert_equals(e.data['entryType'], 'longtask'); // Ignore any long task that may be produced by the top-level frame. diff --git a/tests/wpt/web-platform-tests/longtask-timing/longtask-tojson.html b/tests/wpt/web-platform-tests/longtask-timing/longtask-tojson.html index 6574b62d348..b1f9b3c9b1c 100644 --- a/tests/wpt/web-platform-tests/longtask-timing/longtask-tojson.html +++ b/tests/wpt/web-platform-tests/longtask-timing/longtask-tojson.html @@ -7,7 +7,7 @@ <body> <script> async_test(function (t) { - assert_precondition(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); const observer = new PerformanceObserver( t.step_func(function (entryList) { const entries = entryList.getEntries(); diff --git a/tests/wpt/web-platform-tests/longtask-timing/shared-renderer/longtask-in-new-window.html b/tests/wpt/web-platform-tests/longtask-timing/shared-renderer/longtask-in-new-window.html index 18d36b1e734..7668d995d86 100644 --- a/tests/wpt/web-platform-tests/longtask-timing/shared-renderer/longtask-in-new-window.html +++ b/tests/wpt/web-platform-tests/longtask-timing/shared-renderer/longtask-in-new-window.html @@ -11,7 +11,7 @@ This window opens a new window which contains a longtask. We test that the longtask from the new window is not observed by the observer of this window. */ async_test(t => { - assert_precondition(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); const observer = new PerformanceObserver( t.step_func(function (entryList) { const entries = entryList.getEntries(); diff --git a/tests/wpt/web-platform-tests/longtask-timing/supported-longtask-types.window.js b/tests/wpt/web-platform-tests/longtask-timing/supported-longtask-types.window.js index aaa6415a8d3..efb393ad844 100644 --- a/tests/wpt/web-platform-tests/longtask-timing/supported-longtask-types.window.js +++ b/tests/wpt/web-platform-tests/longtask-timing/supported-longtask-types.window.js @@ -1,5 +1,5 @@ test(() => { - assert_precondition(typeof PerformanceObserver.supportedEntryTypes !== "undefined", 'supportedEntryTypes is not supported'); + assert_implements(typeof PerformanceObserver.supportedEntryTypes !== "undefined", 'supportedEntryTypes is not supported'); const types = PerformanceObserver.supportedEntryTypes; assert_true(types.includes("longtask"), "There should be 'longtask' in PerformanceObserver.supportedEntryTypes"); @@ -21,8 +21,8 @@ function syncWait(waitDuration) { const entryType = "longtask"; promise_test(async () => { - assert_precondition(typeof PerformanceObserver.supportedEntryTypes !== "undefined", 'supportedEntryTypes is not supported'); - assert_precondition(typeof PerformanceObserver.supportedEntryTypes.includes(entryType), `supportedEntryTypes does not include '${entryType}'`); + assert_implements(typeof PerformanceObserver.supportedEntryTypes !== "undefined", 'supportedEntryTypes is not supported'); + assert_implements(typeof PerformanceObserver.supportedEntryTypes.includes(entryType), `supportedEntryTypes does not include '${entryType}'`); await new Promise((resolve) => { new PerformanceObserver(function (list, observer) { observer.disconnect(); diff --git a/tests/wpt/web-platform-tests/mathml/presentation-markup/operators/mo-font-relative-lengths-001.html b/tests/wpt/web-platform-tests/mathml/presentation-markup/operators/mo-font-relative-lengths-001.html new file mode 100644 index 00000000000..b18d7dbfbe2 --- /dev/null +++ b/tests/wpt/web-platform-tests/mathml/presentation-markup/operators/mo-font-relative-lengths-001.html @@ -0,0 +1,113 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Font-relative lengths on an operator</title> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#dictionary-based-attributes"> +<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#embellished-operators"> +<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#definition-of-space-like-elements"> +<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#layout-of-mrow"> +<meta name="assert" content="Verify font-relative lengths refer to the core operator, not the embellished operator"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> + math { + font: 100px/1 Ahem; + } + @font-face { + font-family: operators; + src: url("/fonts/math/operators.woff"); + } + mo { + font-family: operators; + } +</style> +<script> + setup({ explicit_done: true }); + window.addEventListener("load", () => { document.fonts.ready.then(runTests); }); + + function runTests() { + var epsilon = 1; + var baseSizePx = 100; + + test(function() { + var beforeRight = document.getElementById("before1").getBoundingClientRect().right; + var afterLeft = document.getElementById("after1").getBoundingClientRect().left; + var fontScalePercent = .5; + var lspaceEm = 1; + var moWidthEm = 1; + assert_approx_equals(afterLeft - beforeRight, baseSizePx * fontScalePercent * (lspaceEm + moWidthEm), epsilon, "baseSizePx * fontScalePercent * lspaceEm"); + }, `font-relative lspace refers to the core operator`); + + test(function() { + var beforeRight = document.getElementById("before2").getBoundingClientRect().right; + var afterLeft = document.getElementById("after2").getBoundingClientRect().left; + var fontScalePercent = 2; + var rspaceEm = 1; + var moWidthEm = 1; + assert_approx_equals(afterLeft - beforeRight, baseSizePx * fontScalePercent * (rspaceEm + moWidthEm), epsilon, "baseSizePx * fontScalePercent * rspaceEm"); + }, `font-relative rspace refers to the core operator`); + + test(function() { + var moStretchSize = document.getElementById("operator1").getBoundingClientRect().height; + var fontScalePercent = .5; + var minsizeEm = 8; + var beforeHeight = document.getElementById("before1").getBoundingClientRect().height; + + assert_approx_equals(moStretchSize, baseSizePx * minsizeEm * fontScalePercent, epsilon, "baseSizePx * fontScalePercent * minsizeEm"); + + // This is really testing the same thing but do make sure minsize is + // applied i.e. the unconstrained target size is less than the actual + // stretch size. + assert_approx_equals(beforeHeight, moStretchSize / 2, epsilon); + + }, `font-relative minsize refers to the core operator`); + + test(function() { + var moStretchSize = document.getElementById("operator2").getBoundingClientRect().height; + var fontScalePercent = 2; + var maxsizeEm = 1; + var afterHeight = document.getElementById("after2").getBoundingClientRect().height; + + assert_approx_equals(moStretchSize, baseSizePx * maxsizeEm * fontScalePercent, epsilon, "baseSizePx * fontScalePercent * maxsizeEm"); + + // This is really testing the same thing but do make sure maxsize is + // applied i.e. the unconstrained target size is more than the actual + // stretch size. + assert_approx_equals(afterHeight, 2 * moStretchSize, epsilon); + + }, `font-relative maxsize refers to the core operator`); + + done(); + } +</script> +</head> +<body> + <div id="log"></div> + <p> + <math> + <mrow> + <mspace id="before1" width="1em" height="1em" depth="1em" style="background: blue"/> + <mrow style="font-size: 50%;"> + <mo id="operator1" lspace="1em" rspace="0em" minsize="8em">⥯</mo> + <mspace id="after1" width="1em" height=".5em" depth=".5em" style="background: green"/> + </mrow> + <mn><!-- not space like --></mn> + </mrow> + </math> + </p> + <p> + <math> + <mrow> + <mrow style="font-size: 200%"> + <mspace id="before2" width="1em" height=".5em" depth=".5em" style="background: green"/> + <mo id="operator2" lspace="0em" rspace="1em" maxsize="1em">⥯</mo> + </mrow> + <mspace id="after2" width="1em" height="2em" depth="2em" style="background: blue"/> + <mn><!-- not space like --></mn> + </mrow> + </math> + </p> +</body> +</html> diff --git a/tests/wpt/web-platform-tests/paint-timing/basetest.html b/tests/wpt/web-platform-tests/paint-timing/basetest.html index d4dfe7ed822..1c875984598 100644 --- a/tests/wpt/web-platform-tests/paint-timing/basetest.html +++ b/tests/wpt/web-platform-tests/paint-timing/basetest.html @@ -9,7 +9,7 @@ <script> async_test(function(t) { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); t.step(function() { const bufferedEntries = performance.getEntriesByType('paint'); assert_equals(bufferedEntries.length, 0, "No paint entries yet"); diff --git a/tests/wpt/web-platform-tests/paint-timing/buffered-flag.window.js b/tests/wpt/web-platform-tests/paint-timing/buffered-flag.window.js index 4654c925ca0..b3a6a6374c7 100644 --- a/tests/wpt/web-platform-tests/paint-timing/buffered-flag.window.js +++ b/tests/wpt/web-platform-tests/paint-timing/buffered-flag.window.js @@ -1,5 +1,5 @@ async_test(t => { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); // First observer creates second in callback to ensure the entry has been dispatched by the time // the second observer begins observing. let entries_seen = 0; diff --git a/tests/wpt/web-platform-tests/paint-timing/child-painting-first-image.html b/tests/wpt/web-platform-tests/paint-timing/child-painting-first-image.html index d78af081ef8..a7ed2c6f101 100644 --- a/tests/wpt/web-platform-tests/paint-timing/child-painting-first-image.html +++ b/tests/wpt/web-platform-tests/paint-timing/child-painting-first-image.html @@ -5,7 +5,7 @@ <script> async_test(function (t) { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); window.addEventListener('message', t.step_func(e => { assert_equals(e.data, '2 paint first-paint paint first-contentful-paint'); // When only child frame paints, expect only first-paint. diff --git a/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-canvas-context.html b/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-canvas-context.html index 5f3c9d9983b..077c1aa3ddc 100644 --- a/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-canvas-context.html +++ b/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-canvas-context.html @@ -9,7 +9,7 @@ <canvas id="canvas" width="50" height="50"></canvas> <script> promise_test(async t => { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); await new Promise(r => window.addEventListener('load', r)); await assertNoFirstContentfulPaint(t); const canvas = document.getElementById('canvas'); diff --git a/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-gradient.html b/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-gradient.html index 1d15812a0f3..b9f86d8dd73 100644 --- a/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-gradient.html +++ b/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-gradient.html @@ -16,7 +16,7 @@ <div id="main"></div> <script> promise_test(async t => { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); await new Promise(r => window.addEventListener('load', r)); await assertNoFirstContentfulPaint(t); }, 'Gradients should not count as contentful'); diff --git a/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-text-input.html b/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-text-input.html index b22c618c119..0b7e568359f 100644 --- a/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-text-input.html +++ b/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-text-input.html @@ -9,7 +9,7 @@ <input id="input" type="text" /> <script> promise_test(async t => { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); await new Promise(r => window.addEventListener('load', r)); await assertNoFirstContentfulPaint(t); const input = document.getElementById('input'); diff --git a/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-video-frame.html b/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-video-frame.html index 0f61b7e5289..cdfd1670715 100644 --- a/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-video-frame.html +++ b/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-video-frame.html @@ -9,7 +9,7 @@ <video id="video" autoplay></video> <script> promise_test(async t => { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); await new Promise(r => window.addEventListener('load', r)); await assertNoFirstContentfulPaint(t); // Set actual video content to trigger FCP. diff --git a/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-video-poster.html b/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-video-poster.html index 5c1048ac0a7..eb9b1399b52 100644 --- a/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-video-poster.html +++ b/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-video-poster.html @@ -9,7 +9,7 @@ <video id="video" width="50" height="50"></video> <script> promise_test(async t => { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); await new Promise(r => window.addEventListener('load', r)); await assertNoFirstContentfulPaint(t); const video = document.getElementById('video'); diff --git a/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-with-rtl.html b/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-with-rtl.html index 868d2fcaf8f..e9fc2857832 100644 --- a/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-with-rtl.html +++ b/tests/wpt/web-platform-tests/paint-timing/fcp-only/fcp-with-rtl.html @@ -19,7 +19,7 @@ <div id="text">TEXT</div> <script> promise_test(async t => { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); await new Promise(r => window.addEventListener('load', r)); await assertNoFirstContentfulPaint(t); document.body.style.direction = 'ltr' diff --git a/tests/wpt/web-platform-tests/paint-timing/first-contentful-bg-image.html b/tests/wpt/web-platform-tests/paint-timing/first-contentful-bg-image.html index 9c3b2200fb6..3da3d2553ee 100644 --- a/tests/wpt/web-platform-tests/paint-timing/first-contentful-bg-image.html +++ b/tests/wpt/web-platform-tests/paint-timing/first-contentful-bg-image.html @@ -11,7 +11,7 @@ <footer> <script> async_test(function (t) { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); const body = document.getElementsByTagName('body')[0]; body.style.backgroundImage = 'url(resources/circles.png)'; window.onload = function() { diff --git a/tests/wpt/web-platform-tests/paint-timing/first-contentful-canvas.html b/tests/wpt/web-platform-tests/paint-timing/first-contentful-canvas.html index ab47aa0c21c..667591cfe36 100644 --- a/tests/wpt/web-platform-tests/paint-timing/first-contentful-canvas.html +++ b/tests/wpt/web-platform-tests/paint-timing/first-contentful-canvas.html @@ -9,7 +9,7 @@ <script> async_test(function (t) { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); context.beginPath(); diff --git a/tests/wpt/web-platform-tests/paint-timing/first-contentful-image.html b/tests/wpt/web-platform-tests/paint-timing/first-contentful-image.html index 034391c796c..5c29bfe070f 100644 --- a/tests/wpt/web-platform-tests/paint-timing/first-contentful-image.html +++ b/tests/wpt/web-platform-tests/paint-timing/first-contentful-image.html @@ -9,7 +9,7 @@ <script> async_test(function (t) { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); const img = document.createElement("IMG"); img.src = "resources/circles.png"; img.onload = function() { diff --git a/tests/wpt/web-platform-tests/paint-timing/first-contentful-paint.html b/tests/wpt/web-platform-tests/paint-timing/first-contentful-paint.html index 67d7b95eaa5..de2ac035232 100644 --- a/tests/wpt/web-platform-tests/paint-timing/first-contentful-paint.html +++ b/tests/wpt/web-platform-tests/paint-timing/first-contentful-paint.html @@ -10,7 +10,7 @@ <script> async_test(function (t) { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); const bufferedEntries = performance.getEntriesByType('paint'); assert_equals(bufferedEntries.length, 0, "No paint entries yet"); const div = document.createElement("div"); diff --git a/tests/wpt/web-platform-tests/paint-timing/first-contentful-svg.html b/tests/wpt/web-platform-tests/paint-timing/first-contentful-svg.html index 8cda11c9567..9909ec659ef 100644 --- a/tests/wpt/web-platform-tests/paint-timing/first-contentful-svg.html +++ b/tests/wpt/web-platform-tests/paint-timing/first-contentful-svg.html @@ -9,7 +9,7 @@ <script> async_test(function (t) { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); const img = document.createElement("IMG"); img.src = "resources/circle.svg"; img.onload = function() { diff --git a/tests/wpt/web-platform-tests/paint-timing/first-image-child.html b/tests/wpt/web-platform-tests/paint-timing/first-image-child.html index 3f073144692..9b48ff89056 100644 --- a/tests/wpt/web-platform-tests/paint-timing/first-image-child.html +++ b/tests/wpt/web-platform-tests/paint-timing/first-image-child.html @@ -10,7 +10,7 @@ <img src='resources/circles.png'/> <script> async_test(function (t) { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); window.addEventListener('message', t.step_func(e => { // Child iframe should not have any paint-timing entries. diff --git a/tests/wpt/web-platform-tests/paint-timing/first-paint-bg-color.html b/tests/wpt/web-platform-tests/paint-timing/first-paint-bg-color.html index 5e863794d41..21271da4cef 100644 --- a/tests/wpt/web-platform-tests/paint-timing/first-paint-bg-color.html +++ b/tests/wpt/web-platform-tests/paint-timing/first-paint-bg-color.html @@ -11,7 +11,7 @@ <footer> <script> async_test(function (t) { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); document.body.style.backgroundColor = "#AA0000"; function testPaintEntries() { diff --git a/tests/wpt/web-platform-tests/paint-timing/first-paint-only.html b/tests/wpt/web-platform-tests/paint-timing/first-paint-only.html index ea735a246b3..99f41f97b17 100644 --- a/tests/wpt/web-platform-tests/paint-timing/first-paint-only.html +++ b/tests/wpt/web-platform-tests/paint-timing/first-paint-only.html @@ -9,7 +9,7 @@ <script> async_test(function (t) { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); const div = document.createElement("div"); div.style.width = "100px"; div.style.height = "100px"; diff --git a/tests/wpt/web-platform-tests/paint-timing/paint-visited.html b/tests/wpt/web-platform-tests/paint-timing/paint-visited.html index 9a5561d5f7f..d611197b288 100644 --- a/tests/wpt/web-platform-tests/paint-timing/paint-visited.html +++ b/tests/wpt/web-platform-tests/paint-timing/paint-visited.html @@ -21,7 +21,7 @@ window.onload = function() { history.replaceState({}, "", current_url); } async_test(function(t) { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); function testPaintEntries() { const bufferedEntries = performance.getEntriesByType('paint'); if (bufferedEntries.length < 2) { diff --git a/tests/wpt/web-platform-tests/paint-timing/resources/utils.js b/tests/wpt/web-platform-tests/paint-timing/resources/utils.js index a1fb993eb90..2ee0e3d0626 100644 --- a/tests/wpt/web-platform-tests/paint-timing/resources/utils.js +++ b/tests/wpt/web-platform-tests/paint-timing/resources/utils.js @@ -36,7 +36,7 @@ async function test_fcp(label) { const style = document.createElement('style'); document.head.appendChild(style); await promise_test(async t => { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); const main = document.getElementById('main'); await new Promise(r => window.addEventListener('load', r)); await assertNoFirstContentfulPaint(t); diff --git a/tests/wpt/web-platform-tests/paint-timing/sibling-painting-first-image.html b/tests/wpt/web-platform-tests/paint-timing/sibling-painting-first-image.html index 16a6f145db0..d8fec53047f 100644 --- a/tests/wpt/web-platform-tests/paint-timing/sibling-painting-first-image.html +++ b/tests/wpt/web-platform-tests/paint-timing/sibling-painting-first-image.html @@ -6,7 +6,7 @@ <iframe id="listening-iframe" src="resources/subframe-sending-paint.html"></iframe> <script> async_test(function (t) { - assert_precondition(window.PerformancePaintTiming, "Paint Timing isn't supported."); + assert_implements(window.PerformancePaintTiming, "Paint Timing isn't supported."); let paintingIframeHasDispatchedEntries = false; window.addEventListener('message', t.step_func(e => { if (!paintingIframeHasDispatchedEntries) { diff --git a/tests/wpt/web-platform-tests/paint-timing/supported-paint-type.window.js b/tests/wpt/web-platform-tests/paint-timing/supported-paint-type.window.js index c2c3cf5d6dd..518faff5cfb 100644 --- a/tests/wpt/web-platform-tests/paint-timing/supported-paint-type.window.js +++ b/tests/wpt/web-platform-tests/paint-timing/supported-paint-type.window.js @@ -1,13 +1,13 @@ test(() => { - assert_precondition(typeof PerformanceObserver.supportedEntryTypes !== "undefined", 'supportedEntryTypes is not supported'); + assert_implements(typeof PerformanceObserver.supportedEntryTypes !== "undefined", 'supportedEntryTypes is not supported'); assert_true(PerformanceObserver.supportedEntryTypes.includes("paint"), "There should be an entry 'paint' in PerformanceObserver.supportedEntryTypes"); }, "supportedEntryTypes contains 'paint'."); const entryType = 'paint'; promise_test(async() => { - assert_precondition(typeof PerformanceObserver.supportedEntryTypes !== "undefined", 'supportedEntryTypes is not supported'); - assert_precondition(typeof PerformanceObserver.supportedEntryTypes.includes(entryType), `supportedEntryTypes does not include '${entryType}'`); + assert_implements(typeof PerformanceObserver.supportedEntryTypes !== "undefined", 'supportedEntryTypes is not supported'); + assert_implements(typeof PerformanceObserver.supportedEntryTypes.includes(entryType), `supportedEntryTypes does not include '${entryType}'`); await new Promise((resolve) => { new PerformanceObserver(function (list, observer) { observer.disconnect(); diff --git a/tests/wpt/web-platform-tests/performance-timeline/po-observe-type.any.js b/tests/wpt/web-platform-tests/performance-timeline/po-observe-type.any.js index 2c0719a8d14..b9854cc1466 100644 --- a/tests/wpt/web-platform-tests/performance-timeline/po-observe-type.any.js +++ b/tests/wpt/web-platform-tests/performance-timeline/po-observe-type.any.js @@ -1,5 +1,15 @@ // META: script=performanceobservers.js +test(function () { + const obs = new PerformanceObserver(() => {}); + assert_throws_js(TypeError, function () { + obs.observe({}); + }); + assert_throws_js(TypeError, function () { + obs.observe({entryType: ['mark', 'measure']}); + }); +}, "Calling observe() without 'type' or 'entryTypes' throws a TypeError"); + test(() => { const obs = new PerformanceObserver(() =>{}); obs.observe({entryTypes: ["mark"]}); @@ -18,10 +28,10 @@ test(() => { test(() => { const obs = new PerformanceObserver(() =>{}); - assert_throws_dom("SyntaxError", function () { + assert_throws_js(TypeError, function () { obs.observe({type: "mark", entryTypes: ["measure"]}); }); -}, "Calling observe() with type and entryTypes should throw a SyntaxError"); +}, "Calling observe() with type and entryTypes should throw a TypeError"); test(function () { const obs = new PerformanceObserver(() =>{}); diff --git a/tests/wpt/web-platform-tests/performance-timeline/po-observe.any.js b/tests/wpt/web-platform-tests/performance-timeline/po-observe.any.js index 7d7de376b25..5b593374baf 100644 --- a/tests/wpt/web-platform-tests/performance-timeline/po-observe.any.js +++ b/tests/wpt/web-platform-tests/performance-timeline/po-observe.any.js @@ -1,34 +1,25 @@ // META: script=performanceobservers.js test(function () { - var obs = new PerformanceObserver(function () { return true; }); - assert_throws_dom("SyntaxError", function () { - obs.observe({}); - }); - assert_throws_dom("SyntaxError", function () { - obs.observe({entryType: []}); - }); - }, "no 'type' or 'entryTypes' throws a SyntaxError"); - test(function () { - var obs = new PerformanceObserver(function () { return true; }); + const obs = new PerformanceObserver(() => {}); assert_throws_js(TypeError, function () { obs.observe({entryTypes: "mark"}); }); }, "entryTypes must be a sequence or throw a TypeError"); test(function () { - var obs = new PerformanceObserver(function () { return true; }); + const obs = new PerformanceObserver(() => {}); obs.observe({entryTypes: []}); }, "Empty sequence entryTypes does not throw an exception."); test(function () { - var obs = new PerformanceObserver(function () { return true; }); + const obs = new PerformanceObserver(() => {}); obs.observe({entryTypes: ["this-cannot-match-an-entryType"]}); obs.observe({entryTypes: ["marks","navigate", "resources"]}); }, "Unknown entryTypes do not throw an exception."); test(function () { - var obs = new PerformanceObserver(function () { return true; }); + const obs = new PerformanceObserver(() => {}); obs.observe({entryTypes: ["mark","this-cannot-match-an-entryType"]}); obs.observe({entryTypes: ["this-cannot-match-an-entryType","mark"]}); obs.observe({entryTypes: ["mark"], others: true}); diff --git a/tests/wpt/web-platform-tests/portals/about-blank-cannot-host.html b/tests/wpt/web-platform-tests/portals/about-blank-cannot-host.html index 7aba015e69b..c43fbc93ba7 100644 --- a/tests/wpt/web-platform-tests/portals/about-blank-cannot-host.html +++ b/tests/wpt/web-platform-tests/portals/about-blank-cannot-host.html @@ -4,7 +4,7 @@ <script> promise_test(async (t) => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); let hostWindow = window.open(); assert_equals(hostWindow.location.href, "about:blank"); diff --git a/tests/wpt/web-platform-tests/portals/csp/frame-src.sub.html b/tests/wpt/web-platform-tests/portals/csp/frame-src.sub.html index 1b37fd4ac21..13d9e79667f 100644 --- a/tests/wpt/web-platform-tests/portals/csp/frame-src.sub.html +++ b/tests/wpt/web-platform-tests/portals/csp/frame-src.sub.html @@ -6,7 +6,7 @@ </body> <script> async_test(function(t) { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var w = window.open("resources/frame-src.sub.html?frame_src_policy=%27none%27"); w.onload = function() { w.document.addEventListener("securitypolicyviolation", @@ -21,7 +21,7 @@ }, "Tests that a portal can't be loaded when it violates frame-src"); async_test(function(t) { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var w = window.open(`resources/frame-src.sub.html?frame_src_policy=http://{{hosts[][www]}}:{{ports[http][0]}}`); w.onload = function() { w.document.onsecuritypolicyviolation = t.unreached_func("Portal should load."); @@ -32,7 +32,7 @@ } }, "Tests that a portal can be loaded when the origin matches the frame-src CSP header."); async_test(function(t) { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var w = window.open(`resources/frame-src.sub.html?frame_src_policy=http://{{hosts[][www]}}:{{ports[http][0]}}`); w.onload = function() { var portal = w.document.createElement("portal"); diff --git a/tests/wpt/web-platform-tests/portals/history/history-manipulation-inside-portal.html b/tests/wpt/web-platform-tests/portals/history/history-manipulation-inside-portal.html index efbf1de136c..d4b0cf4db9e 100644 --- a/tests/wpt/web-platform-tests/portals/history/history-manipulation-inside-portal.html +++ b/tests/wpt/web-platform-tests/portals/history/history-manipulation-inside-portal.html @@ -16,42 +16,42 @@ } promise_test(async () => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); assertInitialHistoryState(); await runTestInPortal(portalSrc, 'testHistoryPushStateInPortal'); assertInitialHistoryState(); }, 'history.pushState navigates independently with replacement in a portal'); promise_test(async () => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); assertInitialHistoryState(); await runTestInPortal(portalSrc, 'testHistoryReplaceStateInPortal'); assertInitialHistoryState(); }, 'history.replaceState navigates independently in a portal'); promise_test(async () => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); assertInitialHistoryState(); await runTestInPortal(portalSrc, 'testLocationAssignInPortal'); assertInitialHistoryState(); }, 'location.assign navigates independently with replacement in a portal'); promise_test(async () => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); assertInitialHistoryState(); await runTestInPortal(portalSrc, 'testLocationReplaceInPortal'); assertInitialHistoryState(); }, 'location.replace navigates independently in a portal'); promise_test(async () => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); assertInitialHistoryState(); await runTestInPortal(portalSrc, 'testSetLocationHrefInPortal'); assertInitialHistoryState(); }, 'Setting location.href navigates independently with replacement in a portal'); promise_test(async () => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); assertInitialHistoryState(); await runTestInPortal(portalSrc, 'testSyntheticAnchorClickInPortal'); assertInitialHistoryState(); diff --git a/tests/wpt/web-platform-tests/portals/htmlportalelement-event-handler-content-attributes.html b/tests/wpt/web-platform-tests/portals/htmlportalelement-event-handler-content-attributes.html index 04b4615205a..0836c8c00b5 100644 --- a/tests/wpt/web-platform-tests/portals/htmlportalelement-event-handler-content-attributes.html +++ b/tests/wpt/web-platform-tests/portals/htmlportalelement-event-handler-content-attributes.html @@ -7,7 +7,7 @@ let eventNames = ["load", "message", "messageerror"]; test(() => { try { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); let portal = document.createElement("portal"); for (let eventName of eventNames) { window.testValue = "not fired"; diff --git a/tests/wpt/web-platform-tests/portals/portal-activate-data.html b/tests/wpt/web-platform-tests/portals/portal-activate-data.html index 260bb00ff06..54fdca5d8cd 100644 --- a/tests/wpt/web-platform-tests/portals/portal-activate-data.html +++ b/tests/wpt/web-platform-tests/portals/portal-activate-data.html @@ -13,7 +13,7 @@ function nextMessage(target) { } async function openPortalAndActivate(logic, activateOptions, testWindow) { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); const w = testWindow || await openBlankPortalHost(); try { const portal = w.document.createElement('portal'); diff --git a/tests/wpt/web-platform-tests/portals/portal-activate-event.html b/tests/wpt/web-platform-tests/portals/portal-activate-event.html index 990dc2d4b85..69d8a7c930e 100644 --- a/tests/wpt/web-platform-tests/portals/portal-activate-event.html +++ b/tests/wpt/web-platform-tests/portals/portal-activate-event.html @@ -4,7 +4,7 @@ <script src="/resources/testharnessreport.js"></script> <script> async_test(function(t) { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); let test = "eventlistener"; var bc = new BroadcastChannel(`test-${test}`); bc.onmessage = t.step_func_done(function(e) { @@ -16,7 +16,7 @@ }, "Tests that the PortalActivateEvent is dispatched when a portal is activated."); async_test(function(t) { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); let test = "eventhandler"; var bc = new BroadcastChannel(`test-${test}`); bc.onmessage = t.step_func_done(function(e) { @@ -28,7 +28,7 @@ }, "Tests that the portalactivate event handler is dispatched when a portal is activated."); async_test(function(t) { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); let test = "bodyeventhandler"; var bc = new BroadcastChannel(`test-${test}`); bc.onmessage = t.step_func_done(function(e) { diff --git a/tests/wpt/web-platform-tests/portals/portal-non-http-navigation.html b/tests/wpt/web-platform-tests/portals/portal-non-http-navigation.html index e2b5d3d3937..aa02c15efa9 100644 --- a/tests/wpt/web-platform-tests/portals/portal-non-http-navigation.html +++ b/tests/wpt/web-platform-tests/portals/portal-non-http-navigation.html @@ -5,7 +5,7 @@ <body> <script> async_test(t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var portal = document.createElement("portal"); portal.src = "data:text/html,empty portal"; portal.onload = t.unreached_func("Portal loaded data URL."); @@ -14,7 +14,7 @@ async_test(t => { }, "Tests that a portal can't navigate to a data URL."); async_test(t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var portal = document.createElement("portal"); portal.src = "about:blank"; portal.onload = t.unreached_func("Portal loaded about:blank."); @@ -23,7 +23,7 @@ async_test(t => { }, "Tests that a portal can't navigate to about:blank."); async_test(t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var portal = document.createElement("portal"); portal.src = "resources/simple-portal.html"; portal.onload = t.step_func(() => { diff --git a/tests/wpt/web-platform-tests/portals/portal-onload-event.html b/tests/wpt/web-platform-tests/portals/portal-onload-event.html index da770013e26..f6b97a814ed 100644 --- a/tests/wpt/web-platform-tests/portals/portal-onload-event.html +++ b/tests/wpt/web-platform-tests/portals/portal-onload-event.html @@ -4,7 +4,7 @@ <script src="/resources/testharnessreport.js"></script> <script> async_test(function(t) { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var w = window.open("resources/simple-portal.html"); w.onload = function() { var portal = w.document.createElement("portal"); diff --git a/tests/wpt/web-platform-tests/portals/portals-activate-empty-browsing-context.html b/tests/wpt/web-platform-tests/portals/portals-activate-empty-browsing-context.html index d904cd58543..b1787782ffd 100644 --- a/tests/wpt/web-platform-tests/portals/portals-activate-empty-browsing-context.html +++ b/tests/wpt/web-platform-tests/portals/portals-activate-empty-browsing-context.html @@ -4,7 +4,7 @@ <body> <script> promise_test(async t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); let portal = document.createElement('portal'); document.body.appendChild(portal); t.add_cleanup(() => { document.body.removeChild(portal); }); @@ -13,7 +13,7 @@ promise_test(async t => { }, "A portal that has never been navigated cannot be activated"); promise_test(async t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); let portal = document.createElement('portal'); document.body.appendChild(portal); t.add_cleanup(() => { document.body.removeChild(portal); }); diff --git a/tests/wpt/web-platform-tests/portals/portals-activate-inside-iframe.html b/tests/wpt/web-platform-tests/portals/portals-activate-inside-iframe.html index 587e483479c..f4039540961 100644 --- a/tests/wpt/web-platform-tests/portals/portals-activate-inside-iframe.html +++ b/tests/wpt/web-platform-tests/portals/portals-activate-inside-iframe.html @@ -4,7 +4,7 @@ <body> <script> promise_test(async t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var iframe = document.createElement("iframe"); iframe.src = "resources/portal-inside-iframe.html" var waitForLoad = new Promise((resolve, reject) => { diff --git a/tests/wpt/web-platform-tests/portals/portals-activate-inside-portal.html b/tests/wpt/web-platform-tests/portals/portals-activate-inside-portal.html index bd0d9e27bb6..19b57b3e42e 100644 --- a/tests/wpt/web-platform-tests/portals/portals-activate-inside-portal.html +++ b/tests/wpt/web-platform-tests/portals/portals-activate-inside-portal.html @@ -4,7 +4,7 @@ <body> <script> promise_test(async () => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var portal = document.createElement("portal"); portal.src = "resources/portal-activate-inside-portal.html"; let waitForMessage = new Promise((resolve, reject) => { diff --git a/tests/wpt/web-platform-tests/portals/portals-activate-network-error.html b/tests/wpt/web-platform-tests/portals/portals-activate-network-error.html index c2094fd4ded..60ee5c902da 100644 --- a/tests/wpt/web-platform-tests/portals/portals-activate-network-error.html +++ b/tests/wpt/web-platform-tests/portals/portals-activate-network-error.html @@ -4,7 +4,7 @@ <body> <script> async_test(t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); let portal = document.createElement('portal'); portal.src = "resources/invalid.asis"; document.body.appendChild(portal); diff --git a/tests/wpt/web-platform-tests/portals/portals-activate-no-browsing-context.html b/tests/wpt/web-platform-tests/portals/portals-activate-no-browsing-context.html index bfc45f68c18..ccf1e9504be 100644 --- a/tests/wpt/web-platform-tests/portals/portals-activate-no-browsing-context.html +++ b/tests/wpt/web-platform-tests/portals/portals-activate-no-browsing-context.html @@ -3,7 +3,7 @@ <script src="/resources/testharnessreport.js"></script> <script> promise_test(async t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); let activatePromise = document.createElement('portal').activate(); await promise_rejects_dom(t, 'InvalidStateError', activatePromise); }, "A portal with nothing in it cannot be activated"); diff --git a/tests/wpt/web-platform-tests/portals/portals-activate-resolution.html b/tests/wpt/web-platform-tests/portals/portals-activate-resolution.html index ada8d4619a0..7094768a4f8 100644 --- a/tests/wpt/web-platform-tests/portals/portals-activate-resolution.html +++ b/tests/wpt/web-platform-tests/portals/portals-activate-resolution.html @@ -4,7 +4,7 @@ <script src="resources/open-blank-host.js"></script> <script> promise_test(async () => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var win = await openBlankPortalHost(); var portal = win.document.createElement("portal"); portal.src = new URL("resources/simple-portal.html", location.href) diff --git a/tests/wpt/web-platform-tests/portals/portals-activate-twice.html b/tests/wpt/web-platform-tests/portals/portals-activate-twice.html index eaef8b7cc94..0eea5465a2b 100644 --- a/tests/wpt/web-platform-tests/portals/portals-activate-twice.html +++ b/tests/wpt/web-platform-tests/portals/portals-activate-twice.html @@ -3,7 +3,7 @@ <script src="/resources/testharnessreport.js"></script> <script> promise_test(async t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); let waitForMessage = new Promise((resolve, reject) => { window.onmessage = e => resolve(e.data); }); @@ -13,7 +13,7 @@ promise_test(async t => { }, "Calling activate when a portal is already activating should fail"); promise_test(async t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); let waitForMessage = new Promise((resolve, reject) => { window.onmessage = e => resolve(e.data); }); diff --git a/tests/wpt/web-platform-tests/portals/portals-adopt-predecessor.html b/tests/wpt/web-platform-tests/portals/portals-adopt-predecessor.html index 21893987e63..04c61960627 100644 --- a/tests/wpt/web-platform-tests/portals/portals-adopt-predecessor.html +++ b/tests/wpt/web-platform-tests/portals/portals-adopt-predecessor.html @@ -13,7 +13,7 @@ } promise_test(async () => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var test = "adopt-once"; window.open(`resources/portals-adopt-predecessor.html?test=${test}`); var message = await waitForCompletion(test); @@ -21,7 +21,7 @@ }, "Tests that a portal can adopt its predecessor."); promise_test(async () => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var test = "adopt-twice"; window.open(`resources/portals-adopt-predecessor.html?test=${test}`); var message = await waitForCompletion(test); @@ -29,7 +29,7 @@ }, "Tests that trying to adopt the predecessor twice will throw an exception."); async_test(function(t) { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var test = "adopt-after-event"; var bc = new BroadcastChannel(`test-${test}`); bc.onmessage = t.step_func_done(function(e) { @@ -40,7 +40,7 @@ }, "Tests that trying to adopt the predecessor after the PortalActivateEvent will throw an exception."); promise_test(async t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var test = "adopt-and-activate"; window.open(`resources/portals-adopt-predecessor.html?test=${test}`); var message = await waitForCompletion(test); @@ -48,7 +48,7 @@ }, "Tests that activating an adopted predecessor without inserting it works"); async_test(t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var test = "adopt-attach-remove"; var bc = new BroadcastChannel(`test-${test}`); bc.onmessage = t.step_func_done(function(e) { @@ -59,7 +59,7 @@ }, "Tests that an adopting, inserting and then removing a predecessor works correctly"); async_test(t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var test = "adopt-and-discard"; var bc = new BroadcastChannel(`test-${test}`); bc.onmessage = t.step_func_done(function(e) { @@ -70,7 +70,7 @@ }, "Tests that the adopted predecessor is destroyed if it isn't inserted"); async_test(t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var test = "adopt-to-disconnected-node"; var bc = new BroadcastChannel(`test-${test}`); bc.onmessage = t.step_func_done(function(e) { diff --git a/tests/wpt/web-platform-tests/portals/portals-cross-origin-load.sub.html b/tests/wpt/web-platform-tests/portals/portals-cross-origin-load.sub.html index be817b8a0aa..04db38a8e9a 100644 --- a/tests/wpt/web-platform-tests/portals/portals-cross-origin-load.sub.html +++ b/tests/wpt/web-platform-tests/portals/portals-cross-origin-load.sub.html @@ -4,7 +4,7 @@ <body> <script> promise_test(async () => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var portal = document.createElement("portal"); portal.src = "http://{{hosts[alt][www]}}:{{ports[http][0]}}/portals/resources/simple-portal.html"; return new Promise((resolve, reject) => { diff --git a/tests/wpt/web-platform-tests/portals/portals-focus.sub.html b/tests/wpt/web-platform-tests/portals/portals-focus.sub.html index 54fcf3a3d47..ccbac7db906 100644 --- a/tests/wpt/web-platform-tests/portals/portals-focus.sub.html +++ b/tests/wpt/web-platform-tests/portals/portals-focus.sub.html @@ -8,7 +8,7 @@ <body> <script> async function createPortal(doc, url) { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); let portal = doc.createElement("portal"); portal.src = url; doc.body.appendChild(portal); diff --git a/tests/wpt/web-platform-tests/portals/portals-host-exposure.sub.html b/tests/wpt/web-platform-tests/portals/portals-host-exposure.sub.html index 3ff88413691..93ee8ecdc09 100644 --- a/tests/wpt/web-platform-tests/portals/portals-host-exposure.sub.html +++ b/tests/wpt/web-platform-tests/portals/portals-host-exposure.sub.html @@ -4,7 +4,7 @@ <body> <script> function openPortalAndReceiveMessage(portalSrc) { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); let portal = document.createElement('portal'); portal.src = portalSrc; let received = new Promise((resolve, reject) => { diff --git a/tests/wpt/web-platform-tests/portals/portals-host-hidden-after-activation.html b/tests/wpt/web-platform-tests/portals/portals-host-hidden-after-activation.html index 571ec55810a..9638a6c7c6a 100644 --- a/tests/wpt/web-platform-tests/portals/portals-host-hidden-after-activation.html +++ b/tests/wpt/web-platform-tests/portals/portals-host-hidden-after-activation.html @@ -19,7 +19,7 @@ } promise_test(async () => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); const portalUrl = encodeURIComponent("portal-host-hidden-after-activation-portal.html"); window.open(`resources/portal-embed-and-activate.html?url=${portalUrl}`); var results = await waitForMessages(); diff --git a/tests/wpt/web-platform-tests/portals/portals-host-post-message.sub.html b/tests/wpt/web-platform-tests/portals/portals-host-post-message.sub.html index 8750dd43d01..e547642c9f2 100644 --- a/tests/wpt/web-platform-tests/portals/portals-host-post-message.sub.html +++ b/tests/wpt/web-platform-tests/portals/portals-host-post-message.sub.html @@ -17,7 +17,7 @@ } async function createPortalAndLoopMessage(portalSrc, params) { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var portal = await createPortal(portalSrc); var waitForResponse = new Promise((resolve, reject) => { portal.addEventListener("message", e => { resolve(e); }); @@ -73,7 +73,7 @@ }, "postMessage with object message"); promise_test(async () => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); function checkPort(port) { return new Promise((resolve, reject) => { var channel = new MessageChannel(); @@ -138,7 +138,7 @@ }, "postMessage with invalid transferable should throw error"); promise_test(async () => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var receiveMessage = new Promise((resolve, reject) => { var bc = new BroadcastChannel("portal-host-post-message-after-activate"); bc.onmessage = e => { resolve(e); }; @@ -151,7 +151,7 @@ }, "Calling postMessage after receiving onactivate event should fail"); promise_test(() => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var portal = document.createElement("portal"); portal.src = "resources/portal-host-post-message-navigate-1.html"; var count = 0; diff --git a/tests/wpt/web-platform-tests/portals/portals-navigate-after-adoption.html b/tests/wpt/web-platform-tests/portals/portals-navigate-after-adoption.html index f4039020313..1ca1cfb79f3 100644 --- a/tests/wpt/web-platform-tests/portals/portals-navigate-after-adoption.html +++ b/tests/wpt/web-platform-tests/portals/portals-navigate-after-adoption.html @@ -27,7 +27,7 @@ async function openPortalAndActivate(logic) { } promise_test(async () => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); let messageFromNewSrc = await openPortalAndActivate( 'let predecessor = event.adoptPredecessor();' + 'let readyPromise = new Promise((resolve, reject) => {' + diff --git a/tests/wpt/web-platform-tests/portals/portals-nested.html b/tests/wpt/web-platform-tests/portals/portals-nested.html index 41d053bd48d..b4b396ff8dd 100644 --- a/tests/wpt/web-platform-tests/portals/portals-nested.html +++ b/tests/wpt/web-platform-tests/portals/portals-nested.html @@ -4,7 +4,7 @@ <body> <script> promise_test(() => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var portal = document.createElement("portal"); portal.src = "resources/portals-nested-portal.html"; document.body.appendChild(portal); diff --git a/tests/wpt/web-platform-tests/portals/portals-post-message.sub.html b/tests/wpt/web-platform-tests/portals/portals-post-message.sub.html index f3927a0c05a..2f6b25d97da 100644 --- a/tests/wpt/web-platform-tests/portals/portals-post-message.sub.html +++ b/tests/wpt/web-platform-tests/portals/portals-post-message.sub.html @@ -12,7 +12,7 @@ const crossOriginUrl = "http://{{hosts[alt][www]}}:{{ports[http][0]}}/portals/resources/portal-post-message-portal.html" async function createAndInsertPortal(portalSrc) { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var portal = document.createElement("portal"); portal.src = portalSrc; document.body.append(portal); @@ -185,7 +185,7 @@ } promise_test(async t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); window.open("resources/portal-post-message-before-activate-window.html"); let {postMessageTS, activateTS} = await waitForMessage( "portals-post-message-before-activate"); @@ -193,14 +193,14 @@ }, "postMessage before activate should work and preserve order"); promise_test(async t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); window.open("resources/portal-post-message-during-activate-window.html"); let error = await waitForMessage("portals-post-message-during-activate"); assert_equals(error, "InvalidStateError"); }, "postMessage during activate throws error"); promise_test(async t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); window.open("resources/portal-post-message-after-activate-window.html"); let error = await waitForMessage("portals-post-message-after-activate"); assert_equals(error, "InvalidStateError"); diff --git a/tests/wpt/web-platform-tests/portals/portals-referrer-inherit-header.html b/tests/wpt/web-platform-tests/portals/portals-referrer-inherit-header.html index da908cb2c21..1fbd88893e4 100644 --- a/tests/wpt/web-platform-tests/portals/portals-referrer-inherit-header.html +++ b/tests/wpt/web-platform-tests/portals/portals-referrer-inherit-header.html @@ -4,7 +4,7 @@ <body> <script> promise_test(async () => { - assert_precondition('HTMLPortalElement' in self, 'HTMLPortalElement is required for this test'); + assert_implements('HTMLPortalElement' in self, 'HTMLPortalElement is required for this test'); let portal = document.createElement('portal'); let referrerPromise = new Promise((resolve, reject) => { portal.addEventListener('message', e => resolve(e.data), {once: true}); diff --git a/tests/wpt/web-platform-tests/portals/portals-referrer-inherit-meta.html b/tests/wpt/web-platform-tests/portals/portals-referrer-inherit-meta.html index eecb247973e..e77894cfa4d 100644 --- a/tests/wpt/web-platform-tests/portals/portals-referrer-inherit-meta.html +++ b/tests/wpt/web-platform-tests/portals/portals-referrer-inherit-meta.html @@ -5,7 +5,7 @@ <body> <script> promise_test(async () => { - assert_precondition('HTMLPortalElement' in self, 'HTMLPortalElement is required for this test'); + assert_implements('HTMLPortalElement' in self, 'HTMLPortalElement is required for this test'); let portal = document.createElement('portal'); let referrerPromise = new Promise((resolve, reject) => { portal.addEventListener('message', e => resolve(e.data), {once: true}); diff --git a/tests/wpt/web-platform-tests/portals/portals-referrer.html b/tests/wpt/web-platform-tests/portals/portals-referrer.html index b9abcdb80de..4cd3b908958 100644 --- a/tests/wpt/web-platform-tests/portals/portals-referrer.html +++ b/tests/wpt/web-platform-tests/portals/portals-referrer.html @@ -4,7 +4,7 @@ <body> <script> promise_test(async () => { - assert_precondition('HTMLPortalElement' in self, 'HTMLPortalElement is required for this test'); + assert_implements('HTMLPortalElement' in self, 'HTMLPortalElement is required for this test'); let portal = document.createElement('portal'); let referrerPromise = new Promise((resolve, reject) => { portal.addEventListener('message', e => resolve(e.data), {once: true}); @@ -21,7 +21,7 @@ promise_test(async () => { }, "portal contents should be loaded with referrer"); promise_test(async () => { - assert_precondition('HTMLPortalElement' in self, 'HTMLPortalElement is required for this test'); + assert_implements('HTMLPortalElement' in self, 'HTMLPortalElement is required for this test'); let portal = document.createElement('portal'); portal.referrerPolicy = 'no-referrer'; let referrerPromise = new Promise((resolve, reject) => { @@ -39,7 +39,7 @@ promise_test(async () => { }, "portal contents should be loaded with no referrer if referrerpolicy=no-referrer"); promise_test(async () => { - assert_precondition('HTMLPortalElement' in self, 'HTMLPortalElement is required for this test'); + assert_implements('HTMLPortalElement' in self, 'HTMLPortalElement is required for this test'); let portal = document.createElement('portal'); portal.referrerPolicy = 'origin'; let referrerPromise = new Promise((resolve, reject) => { diff --git a/tests/wpt/web-platform-tests/portals/portals-repeated-activate.html b/tests/wpt/web-platform-tests/portals/portals-repeated-activate.html index bf8d8ad4264..f2f36cb7682 100644 --- a/tests/wpt/web-platform-tests/portals/portals-repeated-activate.html +++ b/tests/wpt/web-platform-tests/portals/portals-repeated-activate.html @@ -3,7 +3,7 @@ <script src="/resources/testharnessreport.js"></script> <script> async_test(t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); let win = window.open("resources/portal-repeated-activate-window.html"); win.onload = () => win.activate(); window.onmessage = t.step_func_done(() => {}); diff --git a/tests/wpt/web-platform-tests/portals/portals-set-src-after-activate.html b/tests/wpt/web-platform-tests/portals/portals-set-src-after-activate.html index f9728170858..e485ef4d51c 100644 --- a/tests/wpt/web-platform-tests/portals/portals-set-src-after-activate.html +++ b/tests/wpt/web-platform-tests/portals/portals-set-src-after-activate.html @@ -10,7 +10,7 @@ function nextMessage(target) { } promise_test(async () => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); const w = await openBlankPortalHost(); try { const portal = w.document.createElement('portal'); diff --git a/tests/wpt/web-platform-tests/portals/predecessor-fires-unload.html b/tests/wpt/web-platform-tests/portals/predecessor-fires-unload.html index dce2afb8e6f..cb6d98c01d0 100644 --- a/tests/wpt/web-platform-tests/portals/predecessor-fires-unload.html +++ b/tests/wpt/web-platform-tests/portals/predecessor-fires-unload.html @@ -12,7 +12,7 @@ function timePasses(delay) { } promise_test(async () => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); const w = await openBlankPortalHost(); try { const portal = w.document.createElement('portal'); @@ -30,7 +30,7 @@ promise_test(async () => { }, "pagehide and unload should fire if the predecessor is not adopted"); promise_test(async () => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); localStorage.setItem('predecessor-fires-unload-events', ''); window.open('resources/predecessor-fires-unload-watch-unload.html', '_blank', 'noopener'); while (localStorage.getItem('predecessor-fires-unload-events') != 'pagehide unload') { diff --git a/tests/wpt/web-platform-tests/portals/xfo/portals-xfo-deny.sub.html b/tests/wpt/web-platform-tests/portals/xfo/portals-xfo-deny.sub.html index 2110d4906f9..efc925276c9 100644 --- a/tests/wpt/web-platform-tests/portals/xfo/portals-xfo-deny.sub.html +++ b/tests/wpt/web-platform-tests/portals/xfo/portals-xfo-deny.sub.html @@ -8,7 +8,7 @@ // completion event. async_test(t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var portal = document.createElement('portal'); portal.src = "/portals/xfo/resources/xfo-deny.asis"; portal.onmessage = t.unreached_func("should not have received a message"); @@ -18,7 +18,7 @@ async_test(t => { }, "`XFO: DENY` blocks same-origin portals."); async_test(t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var portal = document.createElement('portal'); portal.src = "http://{{domains[www]}}:{{ports[http][0]}}/portals/xfo/resources/xfo-deny.asis"; portal.onmessage = t.unreached_func("should not have received a message"); @@ -28,7 +28,7 @@ async_test(t => { }, "`XFO: DENY` blocks cross-origin portals."); async_test(t => { - assert_precondition("HTMLPortalElement" in self); + assert_implements("HTMLPortalElement" in self); var portal = document.createElement('portal'); portal.src = "/portals/xfo/resources/xfo-deny.asis"; portal.onmessage = t.unreached_func("should not have received a message"); diff --git a/tests/wpt/web-platform-tests/resources/chromium/webxr-test.js b/tests/wpt/web-platform-tests/resources/chromium/webxr-test.js index a04aa37229c..a9dd9b1d7c7 100644 --- a/tests/wpt/web-platform-tests/resources/chromium/webxr-test.js +++ b/tests/wpt/web-platform-tests/resources/chromium/webxr-test.js @@ -214,6 +214,7 @@ class MockRuntime { 'unbounded': device.mojom.XRSessionFeature.REF_SPACE_UNBOUNDED, 'hit-test': device.mojom.XRSessionFeature.HIT_TEST, 'dom-overlay': device.mojom.XRSessionFeature.DOM_OVERLAY, + 'light-estimation': device.mojom.XRSessionFeature.LIGHT_ESTIMATION, }; static sessionModeToMojoMap = { diff --git a/tests/wpt/web-platform-tests/resources/test/tests/unit/assert_implements.html b/tests/wpt/web-platform-tests/resources/test/tests/unit/assert_implements.html new file mode 100644 index 00000000000..6e35f385027 --- /dev/null +++ b/tests/wpt/web-platform-tests/resources/test/tests/unit/assert_implements.html @@ -0,0 +1,43 @@ +<!DOCTYPE HTML> +<html lang="en"> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/test/tests/unit/helpers.js"></script> +<title>assert_implements unittests</title> +<script> +'use strict'; + +test(() => { + // All values in JS that are not falsy are truthy, so we just check some + // common cases here. + assert_implements(true, 'true is a truthy value'); + assert_implements(5, 'positive integeter is a truthy value'); + assert_implements(-5, 'negative integeter is a truthy value'); + assert_implements('foo', 'non-empty string is a truthy value'); +}, 'truthy values'); + +test_failure(() => { + assert_implements(false); +}, 'false is a falsy value'); + +test_failure(() => { + assert_implements(0); +}, '0 is a falsy value'); + +test_failure(() => { + assert_implements(''); +}, 'empty string is a falsy value'); + +test_failure(() => { + assert_implements(null); +}, 'null is a falsy value'); + +test_failure(() => { + assert_implements(undefined); +}, 'undefined is a falsy value'); + +test_failure(() => { + assert_implements(NaN); +}, 'NaN is a falsy value'); +</script> diff --git a/tests/wpt/web-platform-tests/resources/test/tests/unit/assert_implements_optional.html b/tests/wpt/web-platform-tests/resources/test/tests/unit/assert_implements_optional.html new file mode 100644 index 00000000000..4f23e203c57 --- /dev/null +++ b/tests/wpt/web-platform-tests/resources/test/tests/unit/assert_implements_optional.html @@ -0,0 +1,43 @@ +<!DOCTYPE HTML> +<html lang="en"> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/test/tests/unit/helpers.js"></script> +<title>assert_implements_optional unittests</title> +<script> +'use strict'; + +test(() => { + // All values in JS that are not falsy are truthy, so we just check some + // common cases here. + assert_implements_optional(true, 'true is a truthy value'); + assert_implements_optional(5, 'positive integeter is a truthy value'); + assert_implements_optional(-5, 'negative integeter is a truthy value'); + assert_implements_optional('foo', 'non-empty string is a truthy value'); +}, 'truthy values'); + +test_failure(() => { + assert_implements_optional(false); +}, 'false is a falsy value'); + +test_failure(() => { + assert_implements_optional(0); +}, '0 is a falsy value'); + +test_failure(() => { + assert_implements_optional(''); +}, 'empty string is a falsy value'); + +test_failure(() => { + assert_implements_optional(null); +}, 'null is a falsy value'); + +test_failure(() => { + assert_implements_optional(undefined); +}, 'undefined is a falsy value'); + +test_failure(() => { + assert_implements_optional(NaN); +}, 'NaN is a falsy value'); +</script> diff --git a/tests/wpt/web-platform-tests/resources/test/tests/unit/assert_object_equals.html b/tests/wpt/web-platform-tests/resources/test/tests/unit/assert_object_equals.html index bb3a97e471a..19296b8293f 100644 --- a/tests/wpt/web-platform-tests/resources/test/tests/unit/assert_object_equals.html +++ b/tests/wpt/web-platform-tests/resources/test/tests/unit/assert_object_equals.html @@ -3,29 +3,11 @@ <meta charset="utf-8"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/resources/test/tests/unit/helpers.js"></script> <title>Assertion functions</title> <script> 'use strict'; -// The `assert_throws_*` functions cannot be used for this -// purpose because they fail in response to AssertionError exceptions, even -// when this is expressed as the expected error. -function test_failure(fn, name) { - test(function() { - try { - fn(); - } catch (err) { - if (err instanceof AssertionError) { - return; - } - throw new AssertionError('Expected an AssertionError, but'); - } - throw new AssertionError( - 'Expected an AssertionError, but no error was thrown' - ); - }, name); -} - test(function() { assert_object_equals({}, {}); }, 'empty objects'); diff --git a/tests/wpt/web-platform-tests/resources/test/tests/unit/helpers.js b/tests/wpt/web-platform-tests/resources/test/tests/unit/helpers.js new file mode 100644 index 00000000000..b273a72589f --- /dev/null +++ b/tests/wpt/web-platform-tests/resources/test/tests/unit/helpers.js @@ -0,0 +1,21 @@ +// Helper for testing assertion failure cases for a testharness.js API +// +// The `assert_throws_*` functions cannot be used for this purpose because they +// always fail in response to AssertionError exceptions, even when this is +// expressed as the expected error. +function test_failure(fn, name) { + test(function() { + try { + fn(); + } catch (err) { + if (err instanceof AssertionError) { + return; + } + throw new AssertionError('Expected an AssertionError, but'); + } + throw new AssertionError( + 'Expected an AssertionError, but no error was thrown' + ); + }, name); +} + diff --git a/tests/wpt/web-platform-tests/resources/testharness.js b/tests/wpt/web-platform-tests/resources/testharness.js index 63883e15504..15df5b6a342 100644 --- a/tests/wpt/web-platform-tests/resources/testharness.js +++ b/tests/wpt/web-platform-tests/resources/testharness.js @@ -1848,6 +1848,49 @@ policies and contribution forms [3]. } expose(assert_any, "assert_any"); + /** + * Assert that a feature is implemented, based on a 'truthy' condition. + * + * This function should be used to early-exit from tests in which there is + * no point continuing without support for a non-optional spec or spec + * feature. For example: + * + * assert_implements(window.Foo, 'Foo is not supported'); + * + * @param {object} condition The truthy value to test + * @param {string} description Error description for the case that the condition is not truthy. + */ + function assert_implements(condition, description) { + assert(!!condition, "assert_implements", description); + } + expose(assert_implements, "assert_implements") + + /** + * Assert that an optional feature is implemented, based on a 'truthy' condition. + * + * This function should be used to early-exit from tests in which there is + * no point continuing without support for an explicitly optional spec or + * spec feature. For example: + * + * assert_implements_optional(video.canPlayType("video/webm"), + * "webm video playback not supported"); + * + * @param {object} condition The truthy value to test + * @param {string} description Error description for the case that the condition is not truthy. + */ + function assert_implements_optional(condition, description) { + if (!condition) { + // Due to the difficulty of changing logging statuses, we re-use + // the PRECONDITION_FAILED status for assert_implements_optional. + // See the RFC: https://github.com/web-platform-tests/rfcs/pull/48 + // + // TODO(smcgruer): Once assert_precondition is removed, rename the + // exception and move this comment to where PRECONDITION_FAILED is used. + throw new PreconditionFailedError(description); + } + } + expose(assert_implements_optional, "assert_implements_optional") + function assert_precondition(precondition, description) { if (!precondition) { throw new PreconditionFailedError(description); diff --git a/tests/wpt/web-platform-tests/shadow-dom/declarative/script-access.tentative.html b/tests/wpt/web-platform-tests/shadow-dom/declarative/script-access.tentative.html new file mode 100644 index 00000000000..3ecfce55aa3 --- /dev/null +++ b/tests/wpt/web-platform-tests/shadow-dom/declarative/script-access.tentative.html @@ -0,0 +1,88 @@ +<!DOCTYPE html> +<title>Declarative Shadow DOM</title> +<link rel='author' title='Mason Freed' href='mailto:masonfreed@chromium.org'> +<link rel='help' href='https://github.com/whatwg/dom/issues/831'> +<script src='/resources/testharness.js'></script> +<script src='/resources/testharnessreport.js'></script> + +<body> +<script> +let templatesSeen = 0; +function myObserver(mutationsList, observer) { + for (let mutation of mutationsList) { + for (let n of mutation.addedNodes) { + if (n.localName === 'template') { + templatesSeen++; + switch (mutation.target.id) { + case 'openhost': + case 'closedhost': + const shadowroot = n.getAttribute('shadowroot'); + assert_in_array(shadowroot, ['open','closed'], 'Declarative template should have shadowroot attribute'); + assert_equals(n.content, null, 'Declarative template content should be null'); + assert_equals(n.innerHTML, "", 'Declarative template innerHTML should be empty'); + + // Make sure removing the shadowroot attribute doesn't affect things. + n.removeAttribute('shadowroot'); + assert_equals(n.content, null, 'Declarative template content should *still* be null'); + assert_equals(n.innerHTML, "", 'Declarative template innerHTML should *still* be empty'); + break; + case 'noroot': + // Make sure adding 'shadowroot' attribute doesn't trigger a shadow root, + // even if added before parsing completes. + n.setAttribute('shadowroot','open'); + assert_not_equals(n.content, null, 'Regular template should have content, even after adding shadowroot attribute'); + assert_not_equals(n.innerHTML, "", 'Regular template should have innerHTML, even after adding shadowroot attribute'); + break; + default: + assert_unreached('Unrecognized template'); + } + } + } + } +} +const observer = new MutationObserver(myObserver); +observer.observe(document.body, { childList: true, subtree: true }); +assert_equals(templatesSeen, 0, 'No mutations yet'); +</script> + +<div id=openhost> + <template shadowroot=open> + <slot></slot> + </template> +</div> + +<div id=closedhost> + <template shadowroot=closed> + <slot></slot> + </template> +</div> + +<div id=noroot> + <template> + <slot></slot> + </template> +</div> + +<script> +test(t => { + t.add_cleanup(function() { observer.disconnect(); }); + + assert_equals(templatesSeen, 3); + + // Open shadow root + let host = document.querySelector('#openhost'); + assert_equals(host.querySelector('template'), null, 'No leftover template node'); + assert_true(!!host.shadowRoot, 'Shadow root should exist'); + + // Closed shadow root + host = document.querySelector('#closedhost'); + assert_equals(host.querySelector('template'), null, 'No leftover template node'); + assert_true(!host.shadowRoot, 'Closed shadow root (can\'t detect)'); + + // No shadow root + host = document.querySelector('#noroot'); + assert_true(!!host.querySelector('template'), 'Template node still present'); + assert_true(!host.shadowRoot, 'No shadow root'); +},'Declarative Shadow DOM: template .content() should be null'); +</script> +</body>
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/speech-api/historical.html b/tests/wpt/web-platform-tests/speech-api/historical.html index 9da70c44de9..99d2fab5f52 100644 --- a/tests/wpt/web-platform-tests/speech-api/historical.html +++ b/tests/wpt/web-platform-tests/speech-api/historical.html @@ -18,7 +18,7 @@ }); test(() => { - assert_precondition('SpeechRecognition' in window, 'SpeechRecognition exposed'); + assert_implements('SpeechRecognition' in window, 'SpeechRecognition exposed'); assert_false("serviceURI" in SpeechRecognition.prototype); }, "SpeechRecognition's serviceURI attribute should not exist"); @@ -27,7 +27,7 @@ test(() => { "emma", ].forEach(name => { test(() => { - assert_precondition('SpeechRecognitionEvent' in window, 'SpeechRecognitionEvent exposed'); + assert_implements('SpeechRecognitionEvent' in window, 'SpeechRecognitionEvent exposed'); assert_false(name in SpeechRecognitionEvent.prototype); }, `SpeechRecognitionEvent's ${name} attribute should not exist`); }); diff --git a/tests/wpt/web-platform-tests/svg/painting/reftests/display-none-mask-ref.html b/tests/wpt/web-platform-tests/svg/painting/reftests/display-none-mask-ref.html new file mode 100644 index 00000000000..7835597d961 --- /dev/null +++ b/tests/wpt/web-platform-tests/svg/painting/reftests/display-none-mask-ref.html @@ -0,0 +1,50 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="UTF-8"> +</head> + +<body> + <svg width="200" height="200"> + <foreignObject x="0" y="0" width="200" height="200"> + <div style="width: 200px; height: 200px; background: red"></div> + </foreignObject> + </svg> + <svg width="200" height="200"> + <foreignObject x="0" y="0" width="200" height="200"> + <div style="width: 200px; height: 200px; background: red"></div> + </foreignObject> + </svg> + <svg width="200" height="200"> + <foreignObject x="0" y="0" width="200" height="200"> + <div style="width: 200px; height: 200px;"></div> + </foreignObject> + </svg> + <svg width="200" height="200"> + <foreignObject x="0" y="0" width="200" height="200"> + <div style="width: 200px; height: 200px;"></div> + </foreignObject> + </svg> + + <!-- make sure masking actually works --> + <svg width="200" height="200"> + <rect x="0" y="0" width="100" height="50" fill="red"></rect> + <rect x="0" y="100" width="100" height="50" fill="red"></rect> + </svg> + <svg width="200" height="200"> + <rect x="0" y="0" width="100" height="50" fill="red"></rect> + <rect x="0" y="100" width="100" height="50" fill="red"></rect> + </svg> + + <!-- make sure masking works on active content --> + <svg width="200" height="200"> + <rect x="0" y="0" width="100" height="50" fill="red"></rect> + <rect x="0" y="100" width="100" height="50" fill="red"></rect> + </svg> + <svg width="200" height="200"> + <rect x="0" y="0" width="100" height="50" fill="red"></rect> + <rect x="0" y="100" width="100" height="50" fill="red"></rect> + </svg> +</body> +</html> diff --git a/tests/wpt/web-platform-tests/svg/painting/reftests/display-none-mask.html b/tests/wpt/web-platform-tests/svg/painting/reftests/display-none-mask.html new file mode 100644 index 00000000000..5a746c9fdae --- /dev/null +++ b/tests/wpt/web-platform-tests/svg/painting/reftests/display-none-mask.html @@ -0,0 +1,69 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="UTF-8"> + <link rel="match" href="display-none-mask-ref.html" /> +</head> + +<body> + <svg width="200" height="200"> + <foreignObject x="0" y="0" width="200" height="200" style="mask: url('#notfound');"> + <div style="width: 200px; height: 200px; background: red"></div> + </foreignObject> + </svg> + <svg width="200" height="200"> + <foreignObject x="0" y="0" width="200" height="200" style="mask: url('#noneMask');"> + <div style="width: 200px; height: 200px; background: red"></div> + </foreignObject> + </svg> + <svg width="200" height="200"> + <foreignObject x="0" y="0" width="200" height="200"> + <div style="width: 200px; height: 200px; background: red; mask: url('#notfound');"></div> + </foreignObject> + </svg> + <svg width="200" height="200"> + <foreignObject x="0" y="0" width="200" height="200"> + <div style="width: 200px; height: 200px; background: red; mask: url('#noneMask');"></div> + </foreignObject> + </svg> + + <svg width="200" height="200" style="display:none"> + <defs> + <mask id="noneMask"> + <rect x="0" y="0" width="200" height="200" fill="#4d4d4d"></rect> + </mask> + </defs> + </svg> + + <!-- make sure masking actually works --> + <svg width="200" height="200"> + <defs> + <mask id="aMask"> + <rect x="0" y="0" width="100" height="50" fill="#ffffff"></rect> + <rect x="0" y="100" width="100" height="50" fill="#ffffff"></rect> + </mask> + </defs> + <foreignObject x="0" y="0" width="200" height="200" style="mask: url('#aMask');"> + <div style="width: 200px; height: 200px; background: red;"></div> + </foreignObject> + </svg> + <svg width="200" height="200"> + <foreignObject x="0" y="0" width="200" height="200"> + <div style="width: 200px; height: 200px; background: red; mask: url('#aMask');"></div> + </foreignObject> + </svg> + + <!-- make sure masking works on active content --> + <svg width="200" height="200"> + <foreignObject x="0" y="0" width="200" height="200" style="mask: url('#aMask');"> + <div style="width: 200px; height: 200px; background: red; will-change: transform"></div> + </foreignObject> + </svg> + <svg width="200" height="200"> + <foreignObject x="0" y="0" width="200" height="200"> + <div style="width: 200px; height: 200px; background: red; will-change: transform; mask: url('#aMask');"></div> + </foreignObject> + </svg> +</body> +</html> diff --git a/tests/wpt/web-platform-tests/svg/shapes/scripted/stroke-dashes-hit-at-high-scale.svg b/tests/wpt/web-platform-tests/svg/shapes/scripted/stroke-dashes-hit-at-high-scale.svg new file mode 100644 index 00000000000..b57a9e0aa77 --- /dev/null +++ b/tests/wpt/web-platform-tests/svg/shapes/scripted/stroke-dashes-hit-at-high-scale.svg @@ -0,0 +1,27 @@ +<svg id="svg" xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml" viewBox="0 0 36 36" width="600" height="600"> + <title>Strokes w/dashes are properly hit-tested, even at large scale factors</title> + <h:script src="/resources/testharness.js"/> + <h:script src="/resources/testharnessreport.js"/> + <metadata> + <h:link rel="help" href="https://svgwg.org/svg2-draft/shapes.html#CircleElement"/> + <h:link rel="help" href="https://svgwg.org/svg2-draft/painting.html#StrokeProperties"/> + </metadata> + <circle id="circle" cx="6" cy="10" r="5" stroke="blue" stroke-width="1" stroke-dasharray="10 21.4159" fill="none"/> + <script> + <![CDATA[ + test(function() { + let svg = document.getElementById("svg"); + let circle = document.getElementById("circle"); + let hitTest = function(x, y) { + return document.elementFromPoint( + x * svg.width.baseVal.value / svg.viewBox.baseVal.width, + y * svg.height.baseVal.value / svg.viewBox.baseVal.height); + } + assert_equals(hitTest(11, 10), circle, "hit-test the beginning of the dash (t=0)"); + assert_equals(hitTest(8.70, 14.21), circle, "hit-test the middle of the dash (t=5)"); + assert_equals(hitTest(4.10, 14.63), circle, "hit-test the end of the dash (t=9.8)"); + assert_equals(hitTest(3.74, 14.46), svg, "hit-test past the end of the dash (t=10.2)"); + }); + ]]> + </script> +</svg> diff --git a/tests/wpt/web-platform-tests/svg/struct/reftests/support/sprites.svg b/tests/wpt/web-platform-tests/svg/struct/reftests/support/sprites.svg new file mode 100644 index 00000000000..f73b8851913 --- /dev/null +++ b/tests/wpt/web-platform-tests/svg/struct/reftests/support/sprites.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg"> + <rect id="green-rect" width="100" height="100" fill="green"/> +</svg> diff --git a/tests/wpt/web-platform-tests/svg/struct/reftests/use-adopted-with-external-resource.tentative.svg b/tests/wpt/web-platform-tests/svg/struct/reftests/use-adopted-with-external-resource.tentative.svg new file mode 100644 index 00000000000..830d4555e5a --- /dev/null +++ b/tests/wpt/web-platform-tests/svg/struct/reftests/use-adopted-with-external-resource.tentative.svg @@ -0,0 +1,14 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml"> + <title>Adopting a <use> (from an inactive document) requests an external resource</title> + <h:link rel="match" href="reference/green-100x100.svg"/> + <script type="text/plain" template=""><![CDATA[ + <svg xmlns="http://www.w3.org/2000/svg"> + <use href="support/sprites.svg#green-rect"/> + </svg>]]> + </script> + <script> + let text = document.querySelector('script[template]').textContent; + let doc = new DOMParser().parseFromString(text, 'image/svg+xml'); + document.documentElement.appendChild(doc.documentElement); + </script> +</svg> diff --git a/tests/wpt/web-platform-tests/svg/types/scripted/SVGGeometryElement.isPointInStroke-02.svg b/tests/wpt/web-platform-tests/svg/types/scripted/SVGGeometryElement.isPointInStroke-02.svg new file mode 100644 index 00000000000..909b035ef47 --- /dev/null +++ b/tests/wpt/web-platform-tests/svg/types/scripted/SVGGeometryElement.isPointInStroke-02.svg @@ -0,0 +1,35 @@ +<svg id="svg" xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml" viewBox="0 0 36 36" width="600" height="600"> + <title>isPointInStroke w/dashes works properly at large scale factors</title> + <h:script src="/resources/testharness.js"/> + <h:script src="/resources/testharnessreport.js"/> + <metadata> + <h:link rel="help" href="https://svgwg.org/svg2-draft/types.html#InterfaceSVGGeometryElement"/> + <h:link rel="help" href="https://svgwg.org/svg2-draft/types.html#__svg__SVGGeometryElement__isPointInStroke"/> + </metadata> + <circle id="circle" cx="6" cy="10" r="5" stroke="blue" stroke-width="1" stroke-dasharray="10 21.4159" fill="none"/> + <script> + <![CDATA[ + test(function() { + let svg = document.getElementById("svg"); + let circle = document.getElementById("circle"); + let pt = svg.createSVGPoint(); + + pt.x = 11; + pt.y = 10; + assert_true(circle.isPointInStroke(pt), "hit-test the beginning of the dash (t=0)"); + + pt.x = 8.70; + pt.y = 14.21; + assert_true(circle.isPointInStroke(pt), "hit-test the middle of the dash (t=5)"); + + pt.x = 4.10; + pt.y = 14.63; + assert_true(circle.isPointInStroke(pt), "hit-test the end of the dash (t=9.8)"); + + pt.x = 3.74; + pt.y = 14.46; + assert_false(circle.isPointInStroke(pt), "hit-test past the end of the dash (t=10.2)"); + }); + ]]> + </script> +</svg> diff --git a/tests/wpt/web-platform-tests/tools/ci/jobs.py b/tests/wpt/web-platform-tests/tools/ci/jobs.py index 3d809efa37c..a8ae5d237a4 100644 --- a/tests/wpt/web-platform-tests/tools/ci/jobs.py +++ b/tests/wpt/web-platform-tests/tools/ci/jobs.py @@ -41,7 +41,10 @@ job_path_map = { "css/css-ui/", "WebIDL"], "wpt_integration": ["tools/"], - "wptrunner_infrastructure": ["infrastructure/", "tools/", "resources/"], + "wptrunner_infrastructure": ["infrastructure/", + "tools/", + "resources/", + "webdriver/tests/support"], } diff --git a/tests/wpt/web-platform-tests/tools/ci/run_tc.py b/tests/wpt/web-platform-tests/tools/ci/run_tc.py index 69625710ad9..e8dfa6163e5 100755 --- a/tests/wpt/web-platform-tests/tools/ci/run_tc.py +++ b/tests/wpt/web-platform-tests/tools/ci/run_tc.py @@ -43,6 +43,7 @@ import subprocess import sys import tarfile import tempfile +import time import zipfile from socket import error as SocketError # NOQA: N812 import errno @@ -152,13 +153,12 @@ def install_chrome(channel): dest = os.path.join("/tmp", deb_archive) deb_url = "https://dl.google.com/linux/direct/%s" % deb_archive with open(dest, "w") as f: - if not download_url_to_descriptor(f, deb_url): - raise RuntimeError("Can't download %s. Aborting" % deb_url) - + download_url_to_descriptor(f, deb_url) run(["sudo", "apt-get", "-qqy", "update"]) run(["sudo", "gdebi", "-qn", "/tmp/%s" % deb_archive]) + def install_webkitgtk_from_apt_repository(channel): # Configure webkitgtk.org/debian repository for $channel and pin it with maximum priority run(["sudo", "apt-key", "adv", "--fetch-keys", "https://webkitgtk.org/debian/apt.key"]) @@ -178,12 +178,12 @@ def download_url_to_descriptor(fd, url, max_retries=3): """Download an URL in chunks and saves it to a file descriptor (truncating it) It doesn't close the descriptor, but flushes it on success. It retries the download in case of ECONNRESET up to max_retries.""" - download_succeed = False - if max_retries < 0: - max_retries = 0 - for current_retry in range(max_retries+1): + if max_retries < 1: + max_retries = 1 + wait = 1 + for current_retry in range(1, max_retries+1): try: - print("INFO: Downloading %s Try %d/%d" % (url, current_retry + 1, max_retries)) + print("INFO: Downloading %s Try %d/%d" % (url, current_retry, max_retries)) resp = urlopen(url) # We may come here in a retry, ensure to truncate fd before start writing. fd.seek(0) @@ -194,22 +194,23 @@ def download_url_to_descriptor(fd, url, max_retries=3): break # Download finished fd.write(chunk) fd.flush() - download_succeed = True - break # Sucess + # Success + return except SocketError as e: - if e.errno != errno.ECONNRESET: - raise # Unknown error - if current_retry < max_retries: - print("ERROR: Connection reset by peer. Retrying ...") - continue # Retry - return download_succeed + if current_retry < max_retries and e.errno == errno.ECONNRESET: + # Retry + print("ERROR: Connection reset by peer. Retrying after %ds..." % wait) + time.sleep(wait) + wait *= 2 + else: + # Maximum retries or unknown error + raise def install_webkitgtk_from_tarball_bundle(channel): with tempfile.NamedTemporaryFile(suffix=".tar.xz") as temp_tarball: download_url = "https://webkitgtk.org/built-products/nightly/webkitgtk-nightly-build-last.tar.xz" - if not download_url_to_descriptor(temp_tarball, download_url): - raise RuntimeError("Can't download %s. Aborting" % download_url) + download_url_to_descriptor(temp_tarball, download_url) run(["sudo", "tar", "xfa", temp_tarball.name, "-C", "/"]) # Install dependencies run(["sudo", "apt-get", "-qqy", "update"]) @@ -224,6 +225,7 @@ def install_webkitgtk(channel): else: raise ValueError("Unrecognized release channel: %s" % channel) + def start_xvfb(): start(["sudo", "Xvfb", os.environ["DISPLAY"], "-screen", "0", "%sx%sx%s" % (os.environ["SCREEN_WIDTH"], @@ -267,8 +269,10 @@ def download_artifacts(artifacts): for artifact in artifacts: base_url = task_url(artifact["task"]) if artifact["task"] not in artifact_list_by_task: - resp = urlopen(base_url + "/artifacts") - artifacts_data = json.load(resp) + with tempfile.TemporaryFile() as f: + download_url_to_descriptor(f, base_url + "/artifacts") + f.seek(0) + artifacts_data = json.load(f) artifact_list_by_task[artifact["task"]] = artifacts_data artifacts_data = artifact_list_by_task[artifact["task"]] @@ -428,9 +432,10 @@ def fetch_event_data(): # For example under local testing return None - url = task_url(task_id) - resp = urlopen(url) - task_data = json.load(resp) + with tempfile.TemporaryFile() as f: + download_url_to_descriptor(f, task_url(task_id)) + f.seek(0) + task_data = json.load(f) event_data = task_data.get("extra", {}).get("github_event") if event_data is not None: return json.loads(event_data) diff --git a/tests/wpt/web-platform-tests/tools/ci/tests/test_jobs.py b/tests/wpt/web-platform-tests/tools/ci/tests/test_jobs.py index 94f7998770c..3790c04e7b2 100644 --- a/tests/wpt/web-platform-tests/tools/ci/tests/test_jobs.py +++ b/tests/wpt/web-platform-tests/tools/ci/tests/test_jobs.py @@ -134,3 +134,7 @@ def test_wpt_infrastructure(): includes=["wptrunner_infrastructure"]) == {"wptrunner_infrastructure"} assert jobs.get_jobs(["infrastructure/assumptions/ahem.html"], includes=["wptrunner_infrastructure"]) == {"wptrunner_infrastructure"} + +def test_wdspec_support(): + assert jobs.get_jobs(["webdriver/tests/support/__init__.py"], + includes=["wptrunner_infrastructure"]) == {"wptrunner_infrastructure"} diff --git a/tests/wpt/web-platform-tests/tools/docker/README.md b/tests/wpt/web-platform-tests/tools/docker/README.md index 450981f686b..8b0737359ea 100644 --- a/tests/wpt/web-platform-tests/tools/docker/README.md +++ b/tests/wpt/web-platform-tests/tools/docker/README.md @@ -4,7 +4,8 @@ images must be updated as well. To do this, assuming you have docker installed: In this directory, run ```sh -docker build -t <tag> . +# --pull forces Docker to get the newest base image. +docker build --pull -t <tag> . docker push <tag> ``` diff --git a/tests/wpt/web-platform-tests/tools/docker/frontend.py b/tests/wpt/web-platform-tests/tools/docker/frontend.py index 976156cf65a..59a1cff2ebd 100644 --- a/tests/wpt/web-platform-tests/tools/docker/frontend.py +++ b/tests/wpt/web-platform-tests/tools/docker/frontend.py @@ -8,6 +8,7 @@ wpt_root = os.path.abspath(os.path.join(here, os.pardir, os.pardir)) def build(*args, **kwargs): subprocess.check_call(["docker", "build", + "--pull", "--tag", "wpt:local", here]) diff --git a/tests/wpt/web-platform-tests/tools/manifest/tests/test_manifest.py b/tests/wpt/web-platform-tests/tools/manifest/tests/test_manifest.py index 6d329ad38f9..b618d75ec1e 100644 --- a/tests/wpt/web-platform-tests/tools/manifest/tests/test_manifest.py +++ b/tests/wpt/web-platform-tests/tools/manifest/tests/test_manifest.py @@ -1,5 +1,4 @@ import os -import sys import mock @@ -109,7 +108,7 @@ def manifest_tree(draw): @h.given(manifest_tree()) # FIXME: Workaround for https://github.com/web-platform-tests/wpt/issues/22758 -@h.settings(suppress_health_check=(h.HealthCheck.too_slow,) if sys.version_info.major == 3 else ()) +@h.settings(suppress_health_check=(h.HealthCheck.too_slow,)) @h.example([SourceFileWithTest("a", "0"*40, item.ConformanceCheckerTest)]) def test_manifest_to_json(s): m = manifest.Manifest() @@ -126,7 +125,7 @@ def test_manifest_to_json(s): @h.given(manifest_tree()) # FIXME: Workaround for https://github.com/web-platform-tests/wpt/issues/22758 -@h.settings(suppress_health_check=(h.HealthCheck.too_slow,) if sys.version_info.major == 3 else ()) +@h.settings(suppress_health_check=(h.HealthCheck.too_slow,)) @h.example([SourceFileWithTest("a", "0"*40, item.TestharnessTest)]) @h.example([SourceFileWithTest("a", "0"*40, item.RefTest, references=[("/aa", "==")])]) def test_manifest_idempotent(s): diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/requirements.txt b/tests/wpt/web-platform-tests/tools/wptrunner/requirements.txt index c7ddcd75456..9b84e7334bb 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/requirements.txt +++ b/tests/wpt/web-platform-tests/tools/wptrunner/requirements.txt @@ -4,6 +4,6 @@ mozlog==6.0 mozdebug==0.2 # Pillow 7 requires Python 3 pillow==6.2.2 # pyup: <7.0 -urllib3[secure]==1.25.8 +urllib3[secure]==1.25.9 requests==2.23.0 six==1.14.0 diff --git a/tests/wpt/web-platform-tests/trust-tokens/end-to-end/has-trust-token.tentative.https.html b/tests/wpt/web-platform-tests/trust-tokens/end-to-end/has-trust-token.tentative.https.html deleted file mode 100644 index 17e037f7393..00000000000 --- a/tests/wpt/web-platform-tests/trust-tokens/end-to-end/has-trust-token.tentative.https.html +++ /dev/null @@ -1,58 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>Tests the Trust Token API's hasTrustToken function (tentative: the API is a prototype).</title> -<link rel="help" href="https://github.com/WICG/trust-token-api#trust-token-redemption" /> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> - -<script> - 'use strict'; - - promise_test((t) => { - return promise_rejects_js(t, TypeError, document.hasTrustToken( - "http://not-a-secure-url.example")); - }, - 'hasTrustToken requires a secure URL as its issuer argument.'); - - promise_test((t) => { - return promise_rejects_js(t, TypeError, document.hasTrustToken( - "file:///")); - }, - 'hasTrustToken requires a HTTP(S) URL as its issuer argument.'); - - // These hasTrustToken calls all affect global state: each call in the form - // of hasTrustToken(issuer) will result in |issuer| becoming associated in - // persistent storage with the calling top frame's origin. - // - // TODO(davidvc, crbug.com/1061764): Add a way to reset the global state after - // the test concludes. - // - // TODO(davidvc, crbug.com/1063140): Once it's possible to write WPTs that - // result in a trust token being deposited in storage, this should be - // expanded to cover the case where the user _does_ have a token. - promise_test(async (t) => { - let result = await document.hasTrustToken("https://issuer.example/"); - assert_false(result, "The client should not possess any trust tokens for " + - "https://issuer.example since it has not executed an issuance operation" + - " against that issuer."); - - result = await document.hasTrustToken("https://issuer2.example/"); - assert_false(result, "The client should not possess any trust tokens for" + - " https://issuer2.example since it has not executed an issuance " + - "operation against that issuer."); - - await promise_rejects_dom(t, "OperationError", document.hasTrustToken( - "https://issuer3.example/"), - "The first two hasTrustToken operations associated this top-level" + - " origin with the maximum number of issuers (2), so an attempt to " + - " execute hasTrustToken against another issuer should fail."); - - result = await document.hasTrustToken("https://issuer2.example/"); - assert_false(result, "Since this top-level origin is already associated " + - "with https://issuer2.example, subsequent hasTrustToken operations should " + - "not error out even though the top-level origin is at its " + - "number-of-issuers limit."); - }, "When given a valid, secure origin, hasTrustToken should succeed " + - "unless associating that origin with the top-level domain would exceed " + - "the top-level origin's number-of-associated-issuers limit."); -</script> diff --git a/tests/wpt/web-platform-tests/video-rvfc/request-video-frame-callback-repeating.html b/tests/wpt/web-platform-tests/video-rvfc/request-video-frame-callback-repeating.html index 0f9aa55717c..bfdedb4bec0 100644 --- a/tests/wpt/web-platform-tests/video-rvfc/request-video-frame-callback-repeating.html +++ b/tests/wpt/web-platform-tests/video-rvfc/request-video-frame-callback-repeating.html @@ -36,26 +36,42 @@ async_test(function(t) { async_test(function(t) { let video = document.createElement('video'); - let numberOfCallsLeft = 10; - let lastPresentedFrames = -1; + let maxNumberOfCalls = 10; + let currentCallNumber = 0; + let lastMetadata; - function frameNumberVerifier(time, metadata) { - assert_greater_than(metadata.presentedFrames, lastPresentedFrames, "presentedFrames should be monotonically increasing"); + function verifyMetadata(last, current) { + assert_greater_than(current.presentedFrames, last.presentedFrames, "presentedFrames should be monotonically increasing"); + assert_greater_than(current.presentationTime, last.presentationTime, "presentationTime should be monotonically increasing"); + assert_greater_than(current.expectedDisplayTime, last.expectedDisplayTime, "expectedDisplayTime should be monotonically increasing"); - lastPresentedFrames = metadata.presentedFrames; + // We aren't seeking through the file, so this should be increasing from frame to frame. + assert_greater_than(current.mediaTime, last.mediaTime, "mediaTime should be increasing"); - if (--numberOfCallsLeft) { + // The test video's size doesn't change. + assert_equals(current.width, last.width, "width should remain constant"); + assert_equals(current.height, last.height, "height should remain constant"); + } + + function repeatingCallback(time, metadata) { + // Skip the first call to verifyMetadata. + if (currentCallNumber) + verifyMetadata(lastMetadata, metadata) + + lastMetadata = metadata; + + if (++currentCallNumber > maxNumberOfCalls) { t.done() } else { - video.requestVideoFrameCallback(t.step_func(frameNumberVerifier)); + video.requestVideoFrameCallback(t.step_func(repeatingCallback)); } } - video.requestVideoFrameCallback(t.step_func(frameNumberVerifier)); + video.requestVideoFrameCallback(t.step_func(repeatingCallback)); video.src = getVideoURI('/media/movie_5'); video.play(); -}, 'Test chaining calls to video.rVFC.'); +}, 'Test chaining calls to video.rVFC, and verify the required parameters.'); </script> </html> diff --git a/tests/wpt/web-platform-tests/video-rvfc/request-video-frame-callback-webrtc.https.html b/tests/wpt/web-platform-tests/video-rvfc/request-video-frame-callback-webrtc.https.html new file mode 100644 index 00000000000..b6131d6a808 --- /dev/null +++ b/tests/wpt/web-platform-tests/video-rvfc/request-video-frame-callback-webrtc.https.html @@ -0,0 +1,149 @@ +<!doctype html> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <title>WebRTC video.requestVideoFrameCallback() test</title> + <script src="/webrtc/RTCPeerConnection-helper.js"></script> +</head> +<body> + <div id="log"></div> + <div> + <video id="local-view" muted autoplay="autoplay"></video> + <video id="remote-view" muted autoplay="autoplay"/> + </video> + </div> + + <!-- These files are in place when executing on W3C. --> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script type="text/javascript"> + var test = async_test('Test video.requestVideoFrameCallback() parameters for WebRTC applications.'); + + // + // This test is based on /webrtc/simplecall.https.html, but it calls to + // video.requestVideoFrameCallback() before ending, to verify WebRTC required + // and optional parameters. + // + + var gFirstConnection = null; + var gSecondConnection = null; + var gCallbackCounter = 0; + var verify_params = (now, metadata) => { + gCallbackCounter = gCallbackCounter + 1; + assert_greater_than(now, 0); + + // Verify all required fields + assert_greater_than(metadata.presentationTime, 0); + assert_greater_than(metadata.expectedDisplayTime, 0); + assert_greater_than(metadata.presentedFrames, 0); + assert_greater_than(metadata.width, 0); + assert_greater_than(metadata.height, 0); + assert_true("mediaTime" in metadata, "mediaTime should be present"); + + // Verify WebRTC only fields. + assert_true("rtpTimestamp" in metadata, "rtpTimestamp should be present"); + assert_true("receiveTime" in metadata, "receiveTime should be present"); + // captureTime is not available until roundtrip time estimation is done. + if (gCallbackCounter > 60 || "captureTime" in metadata) { + assert_true("captureTime" in metadata, "captureTime should be present"); + test.done(); + } + else { + // Keep requesting callbacks. + document.getElementById('remote-view').requestVideoFrameCallback(test.step_func(verify_params)); + } + } + + // If the remote video gets video data that implies the negotiation + // as well as the ICE and DTLS connection are up. + document.getElementById('remote-view') + .addEventListener('loadedmetadata', function() { + document.getElementById('remote-view').requestVideoFrameCallback(test.step_func(verify_params)); + }); + + + function getNoiseStreamOkCallback(localStream) { + gFirstConnection = new RTCPeerConnection(null); + gFirstConnection.onicecandidate = onIceCandidateToFirst; + + gSecondConnection = new RTCPeerConnection(null); + gSecondConnection.onicecandidate = onIceCandidateToSecond; + gSecondConnection.ontrack = onRemoteTrack; + + localStream.getTracks().forEach(function(track) { + // Bidirectional streams are needed in order for captureTime to be + // populated. Use the same source in both directions. + gFirstConnection.addTrack(track, localStream); + gSecondConnection.addTrack(track, localStream); + }); + + gFirstConnection.createOffer().then(onOfferCreated, failed('createOffer')); + + var videoTag = document.getElementById('local-view'); + videoTag.srcObject = localStream; + }; + + var onOfferCreated = test.step_func(function(offer) { + gFirstConnection.setLocalDescription(offer); + + // This would normally go across the application's signaling solution. + // In our case, the "signaling" is to call this function. + receiveCall(offer.sdp); + }); + + function receiveCall(offerSdp) { + var parsedOffer = new RTCSessionDescription({ type: 'offer', + sdp: offerSdp }); + gSecondConnection.setRemoteDescription(parsedOffer); + + gSecondConnection.createAnswer().then(onAnswerCreated, + failed('createAnswer')); + }; + + var onAnswerCreated = test.step_func(function(answer) { + gSecondConnection.setLocalDescription(answer); + + // Similarly, this would go over the application's signaling solution. + handleAnswer(answer.sdp); + }); + + function handleAnswer(answerSdp) { + var parsedAnswer = new RTCSessionDescription({ type: 'answer', + sdp: answerSdp }); + gFirstConnection.setRemoteDescription(parsedAnswer); + }; + + var onIceCandidateToFirst = test.step_func(function(event) { + // If event.candidate is null = no more candidates. + if (event.candidate) { + gSecondConnection.addIceCandidate(event.candidate); + } + }); + + var onIceCandidateToSecond = test.step_func(function(event) { + if (event.candidate) { + gFirstConnection.addIceCandidate(event.candidate); + } + }); + + var onRemoteTrack = test.step_func(function(event) { + var videoTag = document.getElementById('remote-view'); + if (!videoTag.srcObject) { + videoTag.srcObject = event.streams[0]; + } + }); + + // Returns a suitable error callback. + function failed(function_name) { + return test.unreached_func('WebRTC called error callback for ' + function_name); + } + + // This function starts the test. + test.step(function() { + getNoiseStream({ video: true, audio: true }) + .then(test.step_func(getNoiseStreamOkCallback), failed('getNoiseStream')); + }); +</script> + +</body> +</html>
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/video-rvfc/request-video-frame-callback.html b/tests/wpt/web-platform-tests/video-rvfc/request-video-frame-callback.html index 743cbc60b54..6660fadeaf4 100644 --- a/tests/wpt/web-platform-tests/video-rvfc/request-video-frame-callback.html +++ b/tests/wpt/web-platform-tests/video-rvfc/request-video-frame-callback.html @@ -29,6 +29,24 @@ async_test(function(t) { }, 'Test we can register a video.rVFC callback.'); +async_test(function(t) { + let video = document.createElement('video'); + + video.requestVideoFrameCallback( + t.step_func(video_now => { + // Queue a call to window.rAF, and make sure it is executed within the + // same turn of the event loop (with the same 'time' parameter). + window.requestAnimationFrame( t.step_func_done( window_now => { + assert_equals(video_now, window_now); + })); + }) + ); + + video.src = testVideo.url; + video.play(); + +}, 'Test video.rVFC callbacks run before window.rAF callbacks.'); + async_test(function(t) { let video = document.createElement('video'); diff --git a/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/accumulation-per-property-001.html b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/accumulation-per-property-001.html new file mode 100644 index 00000000000..a3fd115563b --- /dev/null +++ b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/accumulation-per-property-001.html @@ -0,0 +1,24 @@ +<!doctype html> +<meta charset=utf-8> +<title>Accumulation for each property</title> +<link rel="help" href="https://drafts.csswg.org/web-animations/#animation-types"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<script src="property-list.js"></script> +<script src="property-types.js"></script> +<script src="property-utils.js"></script> +<style> +html { + font-size: 10px; +} +</style> +<body> +<div id="log"></div> +<script> +'use strict'; + +test(function() { + runAnimationTypeTest(gCSSProperties1, 'testAccumulation'); +}, 'Setup'); +</script> diff --git a/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/accumulation-per-property-002.html b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/accumulation-per-property-002.html new file mode 100644 index 00000000000..5cf411edf6e --- /dev/null +++ b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/accumulation-per-property-002.html @@ -0,0 +1,24 @@ +<!doctype html> +<meta charset=utf-8> +<title>Accumulation for each property</title> +<link rel="help" href="https://drafts.csswg.org/web-animations/#animation-types"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<script src="property-list.js"></script> +<script src="property-types.js"></script> +<script src="property-utils.js"></script> +<style> +html { + font-size: 10px; +} +</style> +<body> +<div id="log"></div> +<script> +'use strict'; + +test(function() { + runAnimationTypeTest(gCSSProperties2, 'testAccumulation'); +}, 'Setup'); +</script> diff --git a/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/accumulation-per-property.html b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/accumulation-per-property.html deleted file mode 100644 index 420617d1194..00000000000 --- a/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/accumulation-per-property.html +++ /dev/null @@ -1,59 +0,0 @@ -<!doctype html> -<meta charset=utf-8> -<title>Accumulation for each property</title> -<link rel="help" href="https://drafts.csswg.org/web-animations/#animation-types"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="../../testcommon.js"></script> -<script src="property-list.js"></script> -<script src="property-types.js"></script> -<style> -html { - font-size: 10px; -} -</style> -<body> -<div id="log"></div> -<script> -'use strict'; - -test(function() { - for (const property in gCSSProperties) { - if (!isSupported(property)) { - continue; - } - - const setupFunction = gCSSProperties[property].setup; - for (const animationType of gCSSProperties[property].types) { - let typeObject; - let animationTypeString; - if (typeof animationType === 'string') { - typeObject = types[animationType]; - animationTypeString = animationType; - } else if (typeof animationType === 'object' && - animationType.type && typeof animationType.type === 'string') { - typeObject = types[animationType.type]; - animationTypeString = animationType.type; - } - - // First, test that the animation type object has 'testAccumulation'. - // We use test() function here so that we can continue the remainder tests - // even if this test fails. - test(t => { - assert_own_property(typeObject, 'testAccumulation', animationTypeString + - ' should have testAccumulation property'); - assert_equals(typeof typeObject.testAccumulation, 'function', - 'testAccumulation method should be a function'); - }, `${property} (type: ${animationTypeString}) has testAccumulation` - + ' function'); - - if (typeObject.testAccumulation && - typeof typeObject.testAccumulation === 'function') { - typeObject.testAccumulation(property, - setupFunction, - animationType.options); - } - } - } -}, 'Setup'); -</script> diff --git a/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/addition-per-property-001.html b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/addition-per-property-001.html new file mode 100644 index 00000000000..2fbec2c4cd0 --- /dev/null +++ b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/addition-per-property-001.html @@ -0,0 +1,24 @@ +<!doctype html> +<meta charset=utf-8> +<title>Addition for each property</title> +<link rel="help" href="https://drafts.csswg.org/web-animations/#animation-types"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<script src="property-list.js"></script> +<script src="property-types.js"></script> +<script src="property-utils.js"></script> +<style> +html { + font-size: 10px; +} +</style> +<body> +<div id="log"></div> +<script> +'use strict'; + +test(function() { + runAnimationTypeTest(gCSSProperties1, 'testAddition'); +}, "Setup"); +</script> diff --git a/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/addition-per-property-002.html b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/addition-per-property-002.html new file mode 100644 index 00000000000..3b1c40e3c73 --- /dev/null +++ b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/addition-per-property-002.html @@ -0,0 +1,24 @@ +<!doctype html> +<meta charset=utf-8> +<title>Addition for each property</title> +<link rel="help" href="https://drafts.csswg.org/web-animations/#animation-types"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<script src="property-list.js"></script> +<script src="property-types.js"></script> +<script src="property-utils.js"></script> +<style> +html { + font-size: 10px; +} +</style> +<body> +<div id="log"></div> +<script> +'use strict'; + +test(function() { + runAnimationTypeTest(gCSSProperties2, 'testAddition'); +}, "Setup"); +</script> diff --git a/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/addition-per-property.html b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/addition-per-property.html deleted file mode 100644 index f17eedabbdd..00000000000 --- a/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/addition-per-property.html +++ /dev/null @@ -1,59 +0,0 @@ -<!doctype html> -<meta charset=utf-8> -<title>Addition for each property</title> -<link rel="help" href="https://drafts.csswg.org/web-animations/#animation-types"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="../../testcommon.js"></script> -<script src="property-list.js"></script> -<script src="property-types.js"></script> -<style> -html { - font-size: 10px; -} -</style> -<body> -<div id="log"></div> -<script> -'use strict'; - -test(function() { - for (const property in gCSSProperties) { - if (!isSupported(property)) { - continue; - } - - const setupFunction = gCSSProperties[property].setup; - for (const animationType of gCSSProperties[property].types) { - let typeObject; - let animationTypeString; - if (typeof animationType === 'string') { - typeObject = types[animationType]; - animationTypeString = animationType; - } else if (typeof animationType === 'object' && - animationType.type && typeof animationType.type === 'string') { - typeObject = types[animationType.type]; - animationTypeString = animationType.type; - } - - // First, test that the animation type object has 'testAddition'. - // We use test() function here so that we can continue the remainder tests - // even if this test fails. - test(t => { - assert_own_property(typeObject, 'testAddition', animationTypeString + - ' should have testAddition property'); - assert_equals(typeof typeObject.testAddition, 'function', - 'testAddition method should be a function'); - }, `${property} (type: ${animationTypeString}) has testAddition` - + ' function'); - - if (typeObject.testAddition && - typeof typeObject.testAddition === 'function') { - typeObject.testAddition(property, - setupFunction, - animationType.options); - } - } - } -}, "Setup"); -</script> diff --git a/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/interpolation-per-property-001.html b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/interpolation-per-property-001.html new file mode 100644 index 00000000000..97f28224733 --- /dev/null +++ b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/interpolation-per-property-001.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Interpolation for each property</title> +<link rel="help" href="https://drafts.csswg.org/web-animations/#animation-types"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<script src="property-list.js"></script> +<script src="property-types.js"></script> +<script src="property-utils.js"></script> +<style> +html { + font-size: 10px; +} +</style> +<body> +<div id="log"></div> +<script> +'use strict'; + +test(function() { + runAnimationTypeTest(gCSSProperties1, 'testInterpolation'); +}, 'Setup'); +</script> diff --git a/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/interpolation-per-property-002.html b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/interpolation-per-property-002.html new file mode 100644 index 00000000000..9ccc613cfc6 --- /dev/null +++ b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/interpolation-per-property-002.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Interpolation for each property</title> +<link rel="help" href="https://drafts.csswg.org/web-animations/#animation-types"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<script src="property-list.js"></script> +<script src="property-types.js"></script> +<script src="property-utils.js"></script> +<style> +html { + font-size: 10px; +} +</style> +<body> +<div id="log"></div> +<script> +'use strict'; + +test(function() { + runAnimationTypeTest(gCSSProperties2, 'testInterpolation'); +}, 'Setup'); +</script> diff --git a/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/interpolation-per-property.html b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/interpolation-per-property.html deleted file mode 100644 index fe23d89fd06..00000000000 --- a/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/interpolation-per-property.html +++ /dev/null @@ -1,59 +0,0 @@ -<!DOCTYPE html> -<meta charset=utf-8> -<title>Interpolation for each property</title> -<link rel="help" href="https://drafts.csswg.org/web-animations/#animation-types"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="../../testcommon.js"></script> -<script src="property-list.js"></script> -<script src="property-types.js"></script> -<style> -html { - font-size: 10px; -} -</style> -<body> -<div id="log"></div> -<script> -'use strict'; - -test(function() { - for (const property in gCSSProperties) { - if (!isSupported(property)) { - continue; - } - - const setupFunction = gCSSProperties[property].setup; - for (const animationType of gCSSProperties[property].types) { - let typeObject; - let animationTypeString; - if (typeof animationType === 'string') { - typeObject = types[animationType]; - animationTypeString = animationType; - } else if (typeof animationType === 'object' && - animationType.type && typeof animationType.type === 'string') { - typeObject = types[animationType.type]; - animationTypeString = animationType.type; - } - - // First, test that the animation type object has 'testInterpolation'. - // We use test() function() here so that we can continue the remainder tests - // even if this test fails. - test(t => { - assert_own_property(typeObject, 'testInterpolation', animationTypeString + - ' should have testInterpolation property'); - assert_equals(typeof typeObject.testInterpolation, 'function', - 'testInterpolation method should be a function'); - }, `${property} (type: ${animationTypeString}) has testInterpolation` - + ' function'); - - if (typeObject.testInterpolation && - typeof typeObject.testInterpolation === 'function') { - typeObject.testInterpolation(property, - setupFunction, - animationType.options); - } - } - } -}, 'Setup'); -</script> diff --git a/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/property-list.js b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/property-list.js index 2f91ebc372c..32de670ed3c 100644 --- a/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/property-list.js +++ b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/property-list.js @@ -1,6 +1,6 @@ 'use strict'; -const gCSSProperties = { +const gCSSProperties1 = { 'align-content': { // https://drafts.csswg.org/css-align/#propdef-align-content types: [ @@ -701,6 +701,9 @@ const gCSSProperties = { { type: 'discrete', options: [ [ '1 2', '3 4' ] ] } ] }, +}; + +const gCSSProperties2 = { 'inline-size': { // https://drafts.csswg.org/css-logical-props/#propdef-inline-size types: [ diff --git a/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/property-utils.js b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/property-utils.js new file mode 100644 index 00000000000..d3a7b12a61f --- /dev/null +++ b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/property-utils.js @@ -0,0 +1,38 @@ +'use strict'; + +function runAnimationTypeTest(gCSSProperties, testType) { + for (const property in gCSSProperties) { + if (!isSupported(property)) { + continue; + } + + const setupFunction = gCSSProperties[property].setup; + for (const animationType of gCSSProperties[property].types) { + let typeObject; + let animationTypeString; + if (typeof animationType === 'string') { + typeObject = types[animationType]; + animationTypeString = animationType; + } else if (typeof animationType === 'object' && + animationType.type && typeof animationType.type === 'string') { + typeObject = types[animationType.type]; + animationTypeString = animationType.type; + } + + // First, test that the animation type object has 'testAccumulation', or + // 'testAddition', or 'testInterpolation'. + // We use test() function here so that we can continue the remainder tests + // even if this test fails. + test(t => { + assert_own_property(typeObject, testType, animationTypeString + + ` should have ${testType} property`); + assert_equals(typeof typeObject[testType], 'function', + `${testType} method should be a function`); + }, `${property} (type: ${animationTypeString}) has ${testType} function`); + + if (typeObject[testType] && typeof typeObject[testType] === 'function') { + typeObject[testType](property, setupFunction, animationType.options); + } + } + } +} diff --git a/tests/wpt/web-platform-tests/webgpu/constants.js b/tests/wpt/web-platform-tests/webgpu/common/constants.js index 28771fb0e3e..9d3dd1a32de 100644 --- a/tests/wpt/web-platform-tests/webgpu/constants.js +++ b/tests/wpt/web-platform-tests/webgpu/common/constants.js @@ -2,12 +2,12 @@ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts **/ -// https://github.com/gpuweb/gpuweb/blob/402b69138fbedf4a3c9c85cd1bf7e1cc27c1b34e/spec/index.bs +// https://github.com/gpuweb/gpuweb/blob/0a48816412b5d08a5fb8b89005e019165a1a2c63/spec/index.bs // String enums export let ExtensionName; (function (ExtensionName) { - ExtensionName["AnisotropicFiltering"] = "anisotropic-filtering"; + ExtensionName["TextureCompressionBC"] = "texture-compression-bc"; })(ExtensionName || (ExtensionName = {})); export let AddressMode; @@ -25,8 +25,10 @@ export let BindingType; BindingType["StorageBuffer"] = "storage-buffer"; BindingType["ReadonlyStorageBuffer"] = "readonly-storage-buffer"; BindingType["Sampler"] = "sampler"; + BindingType["ComparisonSampler"] = "comparison-sampler"; BindingType["SampledTexture"] = "sampled-texture"; - BindingType["StorageTexture"] = "storage-texture"; + BindingType["ReadonlyStorageTexture"] = "readonly-storage-texture"; + BindingType["WriteonlyStorageTexture"] = "writeonly-storage-texture"; })(BindingType || (BindingType = {})); export let BlendFactor; diff --git a/tests/wpt/web-platform-tests/webgpu/framework/allowed_characters.js b/tests/wpt/web-platform-tests/webgpu/common/framework/allowed_characters.js index af8f45172b5..af8f45172b5 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/allowed_characters.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/allowed_characters.js diff --git a/tests/wpt/web-platform-tests/webgpu/framework/collect_garbage.js b/tests/wpt/web-platform-tests/webgpu/common/framework/collect_garbage.js index dc5a9caf850..dc5a9caf850 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/collect_garbage.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/collect_garbage.js diff --git a/tests/wpt/web-platform-tests/webgpu/framework/fixture.js b/tests/wpt/web-platform-tests/webgpu/common/framework/fixture.js index 11b5f405456..55f8ec48b22 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/fixture.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/fixture.js @@ -4,7 +4,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } -import { assert } from './util/index.js'; +import { assert } from './util/util.js'; export class SkipTestCase extends Error {} // A Fixture is a class used to instantiate each test case at run time. // A new instance of the Fixture is created for every single test case // (i.e. every time the test function is run). diff --git a/tests/wpt/web-platform-tests/webgpu/framework/generate_minimal_query_list.js b/tests/wpt/web-platform-tests/webgpu/common/framework/generate_minimal_query_list.js index 12311acac05..f5344545725 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/generate_minimal_query_list.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/generate_minimal_query_list.js @@ -3,7 +3,7 @@ **/ import { Logger } from './logger.js'; -import { makeFilter } from './test_filter/index.js'; +import { makeFilter } from './test_filter/load_filter.js'; import { treeFromFilterResults } from './tree.js'; function makeQuerySplitterTree(caselist, expectationStrings) { diff --git a/tests/wpt/web-platform-tests/webgpu/framework/gpu/implementation.js b/tests/wpt/web-platform-tests/webgpu/common/framework/gpu/implementation.js index 653b60ab433..670872b5d6e 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/gpu/implementation.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/gpu/implementation.js @@ -3,7 +3,7 @@ **/ /// <reference types="@webgpu/types" /> -import { assert } from '../util/index.js'; +import { assert } from '../util/util.js'; let impl = undefined; export function getGPU() { if (impl) { diff --git a/tests/wpt/web-platform-tests/webgpu/framework/id.js b/tests/wpt/web-platform-tests/webgpu/common/framework/id.js index cb21a667d60..cb21a667d60 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/id.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/id.js diff --git a/tests/wpt/web-platform-tests/webgpu/framework/listing.js b/tests/wpt/web-platform-tests/webgpu/common/framework/listing.js index 856afa99c36..856afa99c36 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/listing.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/listing.js diff --git a/tests/wpt/web-platform-tests/webgpu/framework/loader.js b/tests/wpt/web-platform-tests/webgpu/common/framework/loader.js index 328989a8d7b..ac175a5b85f 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/loader.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/loader.js @@ -4,7 +4,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } -import { loadFilter } from './test_filter/index.js'; +import { loadFilter } from './test_filter/load_filter.js'; function* concat(lists) { for (const specs of lists) { @@ -14,11 +14,11 @@ function* concat(lists) { class DefaultTestFileLoader { async listing(suite) { - return (await import(`../suites/${suite}/index.js`)).listing; + return (await import(`../../${suite}/listing.js`)).listing; } import(path) { - return import('../suites/' + path); + return import('../../' + path); } } diff --git a/tests/wpt/web-platform-tests/webgpu/framework/logger.js b/tests/wpt/web-platform-tests/webgpu/common/framework/logger.js index b3ddbb61555..3f624a86e32 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/logger.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/logger.js @@ -5,9 +5,10 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } import { SkipTestCase } from './fixture.js'; -import { extractPublicParams } from './params/index.js'; +import { extractPublicParams } from './params_utils.js'; import { makeQueryString } from './url_query.js'; -import { assert, getStackTrace, now } from './util/index.js'; +import { getStackTrace } from './util/stack.js'; +import { assert, now } from './util/util.js'; import { version } from './version.js'; export class LogMessageWithStack extends Error { constructor(name, ex, includeStack = true) { diff --git a/tests/wpt/web-platform-tests/webgpu/common/framework/params.js b/tests/wpt/web-platform-tests/webgpu/common/framework/params.js new file mode 100644 index 00000000000..f8e46b62dba --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/params.js @@ -0,0 +1,135 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +let _Symbol$iterator, _Symbol$iterator2, _Symbol$iterator3, _Symbol$iterator4; + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +import { paramsEquals } from './params_utils.js'; +import { assert } from './util/util.js'; +export function poptions(name, values) { + return new POptions(name, values); +} +export function pbool(name) { + return new POptions(name, [false, true]); +} +export function pexclude(params, exclude) { + return new PExclude(params, exclude); +} +export function pfilter(cases, pred) { + return new PFilter(cases, pred); +} +export function pcombine(...params) { + return new PCombine(params); +} +_Symbol$iterator = Symbol.iterator; + +class POptions { + constructor(name, values) { + _defineProperty(this, "name", void 0); + + _defineProperty(this, "values", void 0); + + this.name = name; + this.values = values; + } + + *[_Symbol$iterator]() { + for (const value of this.values) { + yield { + [this.name]: value + }; + } + } + +} + +_Symbol$iterator2 = Symbol.iterator; + +class PExclude { + constructor(cases, exclude) { + _defineProperty(this, "cases", void 0); + + _defineProperty(this, "exclude", void 0); + + this.cases = cases; + this.exclude = Array.from(exclude); + } + + *[_Symbol$iterator2]() { + for (const p of this.cases) { + if (this.exclude.every(e => !paramsEquals(p, e))) { + yield p; + } + } + } + +} + +_Symbol$iterator3 = Symbol.iterator; + +class PFilter { + constructor(cases, pred) { + _defineProperty(this, "cases", void 0); + + _defineProperty(this, "pred", void 0); + + this.cases = cases; + this.pred = pred; + } + + *[_Symbol$iterator3]() { + for (const p of this.cases) { + if (this.pred(p)) { + yield p; + } + } + } + +} + +_Symbol$iterator4 = Symbol.iterator; + +class PCombine { + constructor(params) { + _defineProperty(this, "params", void 0); + + this.params = params; + } + + [_Symbol$iterator4]() { + return PCombine.cartesian(this.params); + } + + static merge(a, b) { + for (const key of Object.keys(a)) { + assert(!b.hasOwnProperty(key), 'Duplicate key: ' + key); + } + + return { ...a, + ...b + }; + } + + static *cartesian(iters) { + if (iters.length === 0) { + return; + } + + if (iters.length === 1) { + yield* iters[0]; + return; + } + + const [as, ...rest] = iters; + + for (const a of as) { + for (const b of PCombine.cartesian(rest)) { + yield PCombine.merge(a, b); + } + } + } + +} +//# sourceMappingURL=params.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/framework/params/index.js b/tests/wpt/web-platform-tests/webgpu/common/framework/params_utils.js index de922526696..cde89843f9e 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/params/index.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/params_utils.js @@ -2,11 +2,7 @@ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts **/ -import { objectEquals } from '../util/index.js'; -export * from './combine.js'; -export * from './exclude.js'; -export * from './filter.js'; -export * from './options.js'; +import { objectEquals } from './util/util.js'; export function extractPublicParams(params) { const publicParams = {}; @@ -73,4 +69,4 @@ export function paramsSupersets(sup, sub) { return true; } -//# sourceMappingURL=index.js.map
\ No newline at end of file +//# sourceMappingURL=params_utils.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/framework/test_filter/filter_by_group.js b/tests/wpt/web-platform-tests/webgpu/common/framework/test_filter/filter_by_group.js index b43749f9c5d..b43749f9c5d 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/test_filter/filter_by_group.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/test_filter/filter_by_group.js diff --git a/tests/wpt/web-platform-tests/webgpu/framework/test_filter/filter_one_file.js b/tests/wpt/web-platform-tests/webgpu/common/framework/test_filter/filter_one_file.js index 6c634888810..cc261ad2ac1 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/test_filter/filter_one_file.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/test_filter/filter_one_file.js @@ -5,7 +5,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } import { testSpecEquals } from '../id.js'; -import { paramsEquals, paramsSupersets } from '../params/index.js'; +import { paramsEquals, paramsSupersets } from '../params_utils.js'; class FilterOneFile { constructor(specId) { diff --git a/tests/wpt/web-platform-tests/webgpu/framework/test_filter/internal.js b/tests/wpt/web-platform-tests/webgpu/common/framework/test_filter/internal.js index ae55718f3b3..ae55718f3b3 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/test_filter/internal.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/test_filter/internal.js diff --git a/tests/wpt/web-platform-tests/webgpu/framework/test_filter/load_filter.js b/tests/wpt/web-platform-tests/webgpu/common/framework/test_filter/load_filter.js index 787747ead06..2b13d9ed2c9 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/test_filter/load_filter.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/test_filter/load_filter.js @@ -3,21 +3,21 @@ **/ import { allowedTestNameCharacters } from '../allowed_characters.js'; -import { assert, unreachable } from '../util/index.js'; +import { assert, unreachable } from '../util/util.js'; import { FilterByGroup } from './filter_by_group.js'; import { FilterByParamsExact, FilterByParamsMatch, FilterByTestMatch } from './filter_one_file.js'; // Each filter is of one of the forms below (urlencoded). export function makeFilter(filter) { const i1 = filter.indexOf(':'); - assert(i1 !== -1, 'Test queries must fully specify their suite name (e.g. "cts:")'); + assert(i1 !== -1, 'Test queries must fully specify their suite name (e.g. "webgpu:")'); const suite = filter.substring(0, i1); const i2 = filter.indexOf(':', i1 + 1); if (i2 === -1) { - // - cts: - // - cts:buf - // - cts:buffers/ - // - cts:buffers/map + // - webgpu: + // - webgpu:buf + // - webgpu:buffers/ + // - webgpu:buffers/map const groupPrefix = filter.substring(i1 + 1); return new FilterByGroup(suite, groupPrefix); } @@ -27,8 +27,8 @@ export function makeFilter(filter) { const i3sub = filter.substring(i2 + 1).search(endOfTestName); if (i3sub === -1) { - // - cts:buffers/mapWriteAsync: - // - cts:buffers/mapWriteAsync:b + // - webgpu:buffers/mapWriteAsync: + // - webgpu:buffers/mapWriteAsync:b const testPrefix = filter.substring(i2 + 1); return new FilterByTestMatch({ suite, @@ -46,17 +46,17 @@ export function makeFilter(filter) { } if (token === '~') { - // - cts:buffers/mapWriteAsync:basic~ - // - cts:buffers/mapWriteAsync:basic~{} - // - cts:buffers/mapWriteAsync:basic~{filter:"params"} + // - webgpu:buffers/mapWriteAsync:basic~ + // - webgpu:buffers/mapWriteAsync:basic~{} + // - webgpu:buffers/mapWriteAsync:basic~{filter:"params"} return new FilterByParamsMatch({ suite, path }, test, params); } else if (token === '=') { - // - cts:buffers/mapWriteAsync:basic= - // - cts:buffers/mapWriteAsync:basic={} - // - cts:buffers/mapWriteAsync:basic={exact:"params"} + // - webgpu:buffers/mapWriteAsync:basic= + // - webgpu:buffers/mapWriteAsync:basic={} + // - webgpu:buffers/mapWriteAsync:basic={exact:"params"} return new FilterByParamsExact({ suite, path diff --git a/tests/wpt/web-platform-tests/webgpu/common/framework/test_filter/test_filter_result.js b/tests/wpt/web-platform-tests/webgpu/common/framework/test_filter/test_filter_result.js new file mode 100644 index 00000000000..9e32bdbd931 --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/test_filter/test_filter_result.js @@ -0,0 +1,4 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ +//# sourceMappingURL=test_filter_result.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/framework/test_group.js b/tests/wpt/web-platform-tests/webgpu/common/framework/test_group.js index 643e9f60b31..8837b1e924a 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/test_group.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/test_group.js @@ -5,9 +5,9 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } import { allowedTestNameCharacters } from './allowed_characters.js'; -import { extractPublicParams, paramsEquals } from './params/index.js'; +import { extractPublicParams, paramsEquals } from './params_utils.js'; import { checkPublicParamType } from './url_query.js'; -import { assert } from './util/index.js'; +import { assert } from './util/util.js'; const validNames = new RegExp('^[' + allowedTestNameCharacters + ']+$'); export class TestGroup { constructor(fixture) { diff --git a/tests/wpt/web-platform-tests/webgpu/framework/tree.js b/tests/wpt/web-platform-tests/webgpu/common/framework/tree.js index fd7e6704c76..8f96c980749 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/tree.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/tree.js @@ -2,7 +2,7 @@ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts **/ -import { stringifyPublicParams } from './params/index.js'; +import { stringifyPublicParams } from './params_utils.js'; // e.g. iteratePath('a/b/c/d', ':') yields ['a/', 'a/b/', 'a/b/c/', 'a/b/c/d:'] function* iteratePath(path, terminator) { diff --git a/tests/wpt/web-platform-tests/webgpu/framework/url_query.js b/tests/wpt/web-platform-tests/webgpu/common/framework/url_query.js index 1446bc7f7f7..13671ab7dac 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/url_query.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/url_query.js @@ -2,8 +2,8 @@ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts **/ -import { stringifyPublicParams } from './params/index.js'; -import { unreachable } from './util/index.js'; +import { stringifyPublicParams } from './params_utils.js'; +import { unreachable } from './util/util.js'; export function encodeSelectively(s) { let ret = encodeURIComponent(s); ret = ret.replace(/%22/g, '"'); diff --git a/tests/wpt/web-platform-tests/webgpu/framework/util/async_mutex.js b/tests/wpt/web-platform-tests/webgpu/common/framework/util/async_mutex.js index cb900605bcf..cb900605bcf 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/util/async_mutex.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/util/async_mutex.js diff --git a/tests/wpt/web-platform-tests/webgpu/framework/util/stack.js b/tests/wpt/web-platform-tests/webgpu/common/framework/util/stack.js index 92b9c0e6bbc..3d0ec636d85 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/util/stack.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/util/stack.js @@ -3,8 +3,8 @@ **/ // Takes a stack trace, and extracts only the first continuous range of lines -// containing '/suites/', which should provide only the useful part of the stack -// to the caller (for logging). +// containing '/(webgpu|unittests)/', which should provide only the useful part +// of the stack to the caller (for logging). export function getStackTrace(e) { if (!e.stack) { return ''; @@ -14,11 +14,11 @@ export function getStackTrace(e) { const stack = []; const moreStack = []; let found = false; - const suitesRegex = /[\/\\]suites[\/\\]/; + const commonRegex = /[\/\\](webgpu|unittests)[\/\\]/; for (let i = 0; i < parts.length; ++i) { const part = parts[i].trim(); - const isSuites = suitesRegex.test(part); + const isSuites = commonRegex.test(part); // approximate if (found && !isSuites) { moreStack.push(part); @@ -40,38 +40,38 @@ export function getStackTrace(e) { // // Node fail() // > Error: -// > at CaseRecorder.fail (/Users/kainino/src/cts-experiment/src/framework/logger.ts:99:30) -// > at RunCaseSpecific.exports.g.test.t [as fn] (/Users/kainino/src/cts-experiment/src/suites/unittests/logger.spec.ts:80:7) -// x at RunCaseSpecific.run (/Users/kainino/src/cts-experiment/src/framework/test_group.ts:121:18) +// > at CaseRecorder.fail (/Users/kainino/src/cts/src/common/framework/logger.ts:99:30) +// > at RunCaseSpecific.exports.g.test.t [as fn] (/Users/kainino/src/cts/src/unittests/logger.spec.ts:80:7) +// x at RunCaseSpecific.run (/Users/kainino/src/cts/src/common/framework/test_group.ts:121:18) // x at processTicksAndRejections (internal/process/task_queues.js:86:5) // // Node throw // > Error: hello -// > at RunCaseSpecific.g.test.t [as fn] (/Users/kainino/src/cts-experiment/src/suites/unittests/test_group.spec.ts:51:11) -// x at RunCaseSpecific.run (/Users/kainino/src/cts-experiment/src/framework/test_group.ts:121:18) +// > at RunCaseSpecific.g.test.t [as fn] (/Users/kainino/src/cts/src/unittests/test_group.spec.ts:51:11) +// x at RunCaseSpecific.run (/Users/kainino/src/cts/src/common/framework/test_group.ts:121:18) // x at processTicksAndRejections (internal/process/task_queues.js:86:5) // // Firefox fail() // > fail@http://localhost:8080/out/framework/logger.js:104:30 // > expect@http://localhost:8080/out/framework/default_fixture.js:59:16 -// > @http://localhost:8080/out/suites/unittests/util.spec.js:35:5 +// > @http://localhost:8080/out/unittests/util.spec.js:35:5 // x run@http://localhost:8080/out/framework/test_group.js:119:18 // // Firefox throw -// > @http://localhost:8080/out/suites/unittests/test_group.spec.js:48:11 +// > @http://localhost:8080/out/unittests/test_group.spec.js:48:11 // x run@http://localhost:8080/out/framework/test_group.js:119:18 // // Safari fail() // > fail@http://localhost:8080/out/framework/logger.js:104:39 // > expect@http://localhost:8080/out/framework/default_fixture.js:59:20 -// > http://localhost:8080/out/suites/unittests/util.spec.js:35:11 +// > http://localhost:8080/out/unittests/util.spec.js:35:11 // x http://localhost:8080/out/framework/test_group.js:119:20 // x asyncFunctionResume@[native code] // x [native code] // x promiseReactionJob@[native code] // // Safari throw -// > http://localhost:8080/out/suites/unittests/test_group.spec.js:48:20 +// > http://localhost:8080/out/unittests/test_group.spec.js:48:20 // x http://localhost:8080/out/framework/test_group.js:119:20 // x asyncFunctionResume@[native code] // x [native code] @@ -81,18 +81,18 @@ export function getStackTrace(e) { // x Error // x at CaseRecorder.fail (http://localhost:8080/out/framework/logger.js:104:30) // x at DefaultFixture.expect (http://localhost:8080/out/framework/default_fixture.js:59:16) -// > at RunCaseSpecific.fn (http://localhost:8080/out/suites/unittests/util.spec.js:35:5) +// > at RunCaseSpecific.fn (http://localhost:8080/out/unittests/util.spec.js:35:5) // x at RunCaseSpecific.run (http://localhost:8080/out/framework/test_group.js:119:18) // x at async runCase (http://localhost:8080/out/runtime/standalone.js:37:17) // x at async http://localhost:8080/out/runtime/standalone.js:102:7 // // Chrome throw // x Error: hello -// > at RunCaseSpecific.fn (http://localhost:8080/out/suites/unittests/test_group.spec.js:48:11) +// > at RunCaseSpecific.fn (http://localhost:8080/out/unittests/test_group.spec.js:48:11) // x at RunCaseSpecific.run (http://localhost:8080/out/framework/test_group.js:119:18)" // x at async Promise.all (index 0) -// x at async TestGroupTest.run (http://localhost:8080/out/suites/unittests/test_group_test.js:6:5) -// x at async RunCaseSpecific.fn (http://localhost:8080/out/suites/unittests/test_group.spec.js:53:15) +// x at async TestGroupTest.run (http://localhost:8080/out/unittests/test_group_test.js:6:5) +// x at async RunCaseSpecific.fn (http://localhost:8080/out/unittests/test_group.spec.js:53:15) // x at async RunCaseSpecific.run (http://localhost:8080/out/framework/test_group.js:119:7) // x at async runCase (http://localhost:8080/out/runtime/standalone.js:37:17) // x at async http://localhost:8080/out/runtime/standalone.js:102:7 diff --git a/tests/wpt/web-platform-tests/webgpu/framework/util/timeout.js b/tests/wpt/web-platform-tests/webgpu/common/framework/util/timeout.js index e565a518efc..e565a518efc 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/util/timeout.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/util/timeout.js diff --git a/tests/wpt/web-platform-tests/webgpu/framework/util/index.js b/tests/wpt/web-platform-tests/webgpu/common/framework/util/util.js index 2cba5f33998..ca64026916c 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/util/index.js +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/util/util.js @@ -3,7 +3,6 @@ **/ import { timeout } from './timeout.js'; -export * from './stack.js'; export function assert(condition, msg) { if (!condition) { throw new Error(msg); @@ -46,4 +45,4 @@ export function objectEquals(x, y) { export function range(n, fn) { return [...new Array(n)].map((_, i) => fn(i)); } -//# sourceMappingURL=index.js.map
\ No newline at end of file +//# sourceMappingURL=util.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/common/framework/version.js b/tests/wpt/web-platform-tests/webgpu/common/framework/version.js new file mode 100644 index 00000000000..159b3cf420e --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/common/framework/version.js @@ -0,0 +1,3 @@ +// AUTO-GENERATED - DO NOT EDIT. See tools/gen_version. + +export const version = '8b01e69c5c7447d2560323f8d2da319db580e733'; diff --git a/tests/wpt/web-platform-tests/webgpu/runtime/helper/options.js b/tests/wpt/web-platform-tests/webgpu/common/runtime/helper/options.js index 1a90beadf1e..1a90beadf1e 100644 --- a/tests/wpt/web-platform-tests/webgpu/runtime/helper/options.js +++ b/tests/wpt/web-platform-tests/webgpu/common/runtime/helper/options.js diff --git a/tests/wpt/web-platform-tests/webgpu/runtime/helper/test_worker-worker.js b/tests/wpt/web-platform-tests/webgpu/common/runtime/helper/test_worker-worker.js index d382f1e80e4..dd078c313a6 100644 --- a/tests/wpt/web-platform-tests/webgpu/runtime/helper/test_worker-worker.js +++ b/tests/wpt/web-platform-tests/webgpu/common/runtime/helper/test_worker-worker.js @@ -2,9 +2,9 @@ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts **/ -import { assert } from '../../framework/index.js'; import { TestLoader } from '../../framework/loader.js'; import { Logger } from '../../framework/logger.js'; +import { assert } from '../../framework/util/util.js'; // should be DedicatedWorkerGlobalScope const log = new Logger(); const loader = new TestLoader(); diff --git a/tests/wpt/web-platform-tests/webgpu/runtime/helper/test_worker.js b/tests/wpt/web-platform-tests/webgpu/common/runtime/helper/test_worker.js index a67030056f5..a67030056f5 100644 --- a/tests/wpt/web-platform-tests/webgpu/runtime/helper/test_worker.js +++ b/tests/wpt/web-platform-tests/webgpu/common/runtime/helper/test_worker.js diff --git a/tests/wpt/web-platform-tests/webgpu/runtime/wpt.js b/tests/wpt/web-platform-tests/webgpu/common/runtime/wpt.js index fd02f09471b..fd02f09471b 100644 --- a/tests/wpt/web-platform-tests/webgpu/runtime/wpt.js +++ b/tests/wpt/web-platform-tests/webgpu/common/runtime/wpt.js diff --git a/tests/wpt/web-platform-tests/webgpu/cts.html b/tests/wpt/web-platform-tests/webgpu/cts.html index 058d3b3c4ad..62340be400e 100644 --- a/tests/wpt/web-platform-tests/webgpu/cts.html +++ b/tests/wpt/web-platform-tests/webgpu/cts.html @@ -46,37 +46,29 @@ </style> <textarea id=results></textarea> -<script type=module src=/webgpu/runtime/wpt.js></script> -<meta name=variant content='?q=cts:buffers/create_mapped'> -<meta name=variant content='?q=cts:buffers/map'> -<meta name=variant content='?q=cts:buffers/map_detach'> -<meta name=variant content='?q=cts:buffers/map_oom'> -<meta name=variant content='?q=cts:canvas/context_creation'> -<meta name=variant content='?q=cts:command_buffer/basic'> -<meta name=variant content='?q=cts:command_buffer/compute/basic'> -<meta name=variant content='?q=cts:command_buffer/copies'> -<meta name=variant content='?q=cts:command_buffer/render/basic'> -<meta name=variant content='?q=cts:command_buffer/render/rendering'> -<meta name=variant content='?q=cts:command_buffer/render/storeop'> -<meta name=variant content='?q=cts:copyImageBitmapToTexture'> -<meta name=variant content='?q=cts:examples'> -<meta name=variant content='?q=cts:fences'> -<meta name=variant content='?q=cts:resource_init/sampled_texture_clear'> -<meta name=variant content='?q=cts:validation/createBindGroup'> -<meta name=variant content='?q=cts:validation/createBindGroupLayout'> -<meta name=variant content='?q=cts:validation/createPipelineLayout'> -<meta name=variant content='?q=cts:validation/createRenderPipeline'> -<meta name=variant content='?q=cts:validation/createTexture'> -<meta name=variant content='?q=cts:validation/createView'> -<meta name=variant content='?q=cts:validation/error_scope'> -<meta name=variant content='?q=cts:validation/fences'> -<meta name=variant content='?q=cts:validation/queue_submit'> -<meta name=variant content='?q=cts:validation/render_pass'> -<meta name=variant content='?q=cts:validation/render_pass_descriptor'> -<meta name=variant content='?q=cts:validation/setBindGroup'> -<meta name=variant content='?q=cts:validation/setBlendColor'> -<meta name=variant content='?q=cts:validation/setScissorRect'> -<meta name=variant content='?q=cts:validation/setStencilReference'> -<meta name=variant content='?q=cts:validation/setVertexBuffer'> -<meta name=variant content='?q=cts:validation/setViewport'> -<meta name=variant content='?q=cts:validation/vertex_state'> +<script type=module src=/webgpu/common/runtime/wpt.js></script> +<meta name=variant content='?q=webgpu:api/operation/buffers/create_mapped'> +<meta name=variant content='?q=webgpu:api/operation/buffers/map'> +<meta name=variant content='?q=webgpu:api/operation/buffers/map_detach'> +<meta name=variant content='?q=webgpu:api/operation/buffers/map_oom'> +<meta name=variant content='?q=webgpu:api/operation/command_buffer/basic'> +<meta name=variant content='?q=webgpu:api/operation/command_buffer/copies'> +<meta name=variant content='?q=webgpu:api/operation/command_buffer/render/basic'> +<meta name=variant content='?q=webgpu:api/operation/fences'> +<meta name=variant content='?q=webgpu:api/validation/createBindGroup'> +<meta name=variant content='?q=webgpu:api/validation/createBindGroupLayout'> +<meta name=variant content='?q=webgpu:api/validation/createPipelineLayout'> +<meta name=variant content='?q=webgpu:api/validation/createTexture'> +<meta name=variant content='?q=webgpu:api/validation/createView'> +<meta name=variant content='?q=webgpu:api/validation/error_scope'> +<meta name=variant content='?q=webgpu:api/validation/fences'> +<meta name=variant content='?q=webgpu:api/validation/queue_submit'> +<meta name=variant content='?q=webgpu:api/validation/render_pass_descriptor'> +<meta name=variant content='?q=webgpu:api/validation/setBindGroup'> +<meta name=variant content='?q=webgpu:api/validation/setBlendColor'> +<meta name=variant content='?q=webgpu:api/validation/setScissorRect'> +<meta name=variant content='?q=webgpu:api/validation/setStencilReference'> +<meta name=variant content='?q=webgpu:api/validation/setViewport'> +<meta name=variant content='?q=webgpu:examples'> +<meta name=variant content='?q=webgpu:web-platform/canvas/context_creation'> +<meta name=variant content='?q=webgpu:web-platform/copyImageBitmapToTexture'> diff --git a/tests/wpt/web-platform-tests/webgpu/framework/index.js b/tests/wpt/web-platform-tests/webgpu/framework/index.js deleted file mode 100644 index c85a6816888..00000000000 --- a/tests/wpt/web-platform-tests/webgpu/framework/index.js +++ /dev/null @@ -1,12 +0,0 @@ -/** -* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts -**/ - -export * from './fixture.js'; -export * from './params/index.js'; -export * from './test_group.js'; -export * from './util/index.js'; // Well-typed WebGPU constants - -import * as C from '../constants.js'; -export { C }; -//# sourceMappingURL=index.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/framework/params/combine.js b/tests/wpt/web-platform-tests/webgpu/framework/params/combine.js deleted file mode 100644 index 20b2be11352..00000000000 --- a/tests/wpt/web-platform-tests/webgpu/framework/params/combine.js +++ /dev/null @@ -1,57 +0,0 @@ -/** -* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts -**/ - -let _Symbol$iterator; - -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - -import { assert } from '../util/index.js'; -export function pcombine(...params) { - return new PCombine(params); -} - -function merge(a, b) { - for (const key of Object.keys(a)) { - assert(!b.hasOwnProperty(key), 'Duplicate key: ' + key); - } - - return { ...a, - ...b - }; -} - -function* cartesian(iters) { - if (iters.length === 0) { - return; - } - - if (iters.length === 1) { - yield* iters[0]; - return; - } - - const [as, ...rest] = iters; - - for (const a of as) { - for (const b of cartesian(rest)) { - yield merge(a, b); - } - } -} - -_Symbol$iterator = Symbol.iterator; - -class PCombine { - constructor(params) { - _defineProperty(this, "params", void 0); - - this.params = params; - } - - [_Symbol$iterator]() { - return cartesian(this.params); - } - -} -//# sourceMappingURL=combine.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/framework/params/exclude.js b/tests/wpt/web-platform-tests/webgpu/framework/params/exclude.js deleted file mode 100644 index 23bc6ee0f69..00000000000 --- a/tests/wpt/web-platform-tests/webgpu/framework/params/exclude.js +++ /dev/null @@ -1,34 +0,0 @@ -/** -* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts -**/ - -let _Symbol$iterator; - -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - -import { paramsEquals } from './index.js'; -export function pexclude(params, exclude) { - return new PExclude(params, exclude); -} -_Symbol$iterator = Symbol.iterator; - -class PExclude { - constructor(cases, exclude) { - _defineProperty(this, "cases", void 0); - - _defineProperty(this, "exclude", void 0); - - this.cases = cases; - this.exclude = Array.from(exclude); - } - - *[_Symbol$iterator]() { - for (const p of this.cases) { - if (this.exclude.every(e => !paramsEquals(p, e))) { - yield p; - } - } - } - -} -//# sourceMappingURL=exclude.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/framework/params/filter.js b/tests/wpt/web-platform-tests/webgpu/framework/params/filter.js deleted file mode 100644 index 6a5d99e765f..00000000000 --- a/tests/wpt/web-platform-tests/webgpu/framework/params/filter.js +++ /dev/null @@ -1,33 +0,0 @@ -/** -* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts -**/ - -let _Symbol$iterator; - -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - -export function pfilter(cases, pred) { - return new PFilter(cases, pred); -} -_Symbol$iterator = Symbol.iterator; - -class PFilter { - constructor(cases, pred) { - _defineProperty(this, "cases", void 0); - - _defineProperty(this, "pred", void 0); - - this.cases = cases; - this.pred = pred; - } - - *[_Symbol$iterator]() { - for (const p of this.cases) { - if (this.pred(p)) { - yield p; - } - } - } - -} -//# sourceMappingURL=filter.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/framework/params/options.js b/tests/wpt/web-platform-tests/webgpu/framework/params/options.js deleted file mode 100644 index 6906863880c..00000000000 --- a/tests/wpt/web-platform-tests/webgpu/framework/params/options.js +++ /dev/null @@ -1,36 +0,0 @@ -/** -* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts -**/ - -let _Symbol$iterator; - -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - -export function poptions(name, values) { - return new POptions(name, values); -} -export function pbool(name) { - return new POptions(name, [false, true]); -} -_Symbol$iterator = Symbol.iterator; - -class POptions { - constructor(name, values) { - _defineProperty(this, "name", void 0); - - _defineProperty(this, "values", void 0); - - this.name = name; - this.values = values; - } - - *[_Symbol$iterator]() { - for (const value of this.values) { - yield { - [this.name]: value - }; - } - } - -} -//# sourceMappingURL=options.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/framework/test_filter/index.js b/tests/wpt/web-platform-tests/webgpu/framework/test_filter/index.js deleted file mode 100644 index 743975e13d6..00000000000 --- a/tests/wpt/web-platform-tests/webgpu/framework/test_filter/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/** -* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts -**/ - -export { loadFilter, makeFilter } from './load_filter.js'; // Result of iterating a test filter. Contains a loaded spec (.spec.ts) file and its id. -//# sourceMappingURL=index.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/framework/version.js b/tests/wpt/web-platform-tests/webgpu/framework/version.js deleted file mode 100644 index 0b58dd9b3c4..00000000000 --- a/tests/wpt/web-platform-tests/webgpu/framework/version.js +++ /dev/null @@ -1,3 +0,0 @@ -// AUTO-GENERATED - DO NOT EDIT. See tools/gen_version. - -export const version = '84ee597cdeae08bb26e578fc66a35bcf35f633f4'; diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/compute/basic.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/compute/basic.spec.js deleted file mode 100644 index 536f7a9003e..00000000000 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/compute/basic.spec.js +++ /dev/null @@ -1,90 +0,0 @@ -/** -* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts -**/ - -export const description = ` -Basic command buffer compute tests. -`; -import { TestGroup } from '../../../../framework/index.js'; -import { GPUTest } from '../../gpu_test.js'; -export const g = new TestGroup(GPUTest); -g.test('memcpy', async t => { - const data = new Uint32Array([0x01020304]); - const src = t.device.createBuffer({ - size: 4, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE - }); - const dst = t.device.createBuffer({ - size: 4, - usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.STORAGE - }); - src.setSubData(0, data); - const bgl = t.device.createBindGroupLayout({ - bindings: [{ - binding: 0, - visibility: 4, - type: 'storage-buffer' - }, { - binding: 1, - visibility: 4, - type: 'storage-buffer' - }] - }); - const bg = t.device.createBindGroup({ - bindings: [{ - binding: 0, - resource: { - buffer: src, - offset: 0, - size: 4 - } - }, { - binding: 1, - resource: { - buffer: dst, - offset: 0, - size: 4 - } - }], - layout: bgl - }); - const module = t.createShaderModule({ - code: - /* GLSL( - * 'compute', - * `#version 310 es - * layout(std140, set = 0, binding = 0) buffer Src { - * int value; - * } src; - * layout(std140, set = 0, binding = 1) buffer Dst { - * int value; - * } dst; - * - * void main() { - * dst.value = src.value; - * } - * ` - * ) - */ - new Uint32Array([119734787, 65536, 524296, 18, 0, 131089, 1, 393227, 1, 1280527431, 1685353262, 808793134, 0, 196622, 0, 1, 327695, 5, 4, 1852399981, 0, 393232, 4, 17, 1, 1, 1, 196611, 1, 310, 262149, 4, 1852399981, 0, 196613, 7, 7631684, 327686, 7, 0, 1970037110, 101, 196613, 9, 7631716, 196613, 11, 6517331, 327686, 11, 0, 1970037110, 101, 196613, 13, 6517363, 327752, 7, 0, 35, 0, 196679, 7, 3, 262215, 9, 34, 0, 262215, 9, 33, 1, 327752, 11, 0, 35, 0, 196679, 11, 3, 262215, 13, 34, 0, 262215, 13, 33, 0, 131091, 2, 196641, 3, 2, 262165, 6, 32, 1, 196638, 7, 6, 262176, 8, 2, 7, 262203, 8, 9, 2, 262187, 6, 10, 0, 196638, 11, 6, 262176, 12, 2, 11, 262203, 12, 13, 2, 262176, 14, 2, 6, 327734, 2, 4, 0, 3, 131320, 5, 327745, 14, 15, 13, 10, 262205, 6, 16, 15, 327745, 14, 17, 9, 10, 196670, 17, 16, 65789, 65592]) - }); - const pl = t.device.createPipelineLayout({ - bindGroupLayouts: [bgl] - }); - const pipeline = t.device.createComputePipeline({ - computeStage: { - module, - entryPoint: 'main' - }, - layout: pl - }); - const encoder = t.device.createCommandEncoder(); - const pass = encoder.beginComputePass(); - pass.setPipeline(pipeline); - pass.setBindGroup(0, bg); - pass.dispatch(1, 1, 1); - pass.endPass(); - t.device.defaultQueue.submit([encoder.finish()]); - t.expectContents(dst, data); -}); -//# sourceMappingURL=basic.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/rendering.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/rendering.spec.js deleted file mode 100644 index b26b9fbc859..00000000000 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/rendering.spec.js +++ /dev/null @@ -1,117 +0,0 @@ -/** -* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts -**/ - -export const description = ``; -import { TestGroup } from '../../../../framework/index.js'; -import { GPUTest } from '../../gpu_test.js'; -export const g = new TestGroup(GPUTest); -g.test('fullscreen quad', async t => { - const dst = t.device.createBuffer({ - size: 4, - usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST - }); - const colorAttachment = t.device.createTexture({ - format: 'rgba8unorm', - size: { - width: 1, - height: 1, - depth: 1 - }, - usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.OUTPUT_ATTACHMENT - }); - const colorAttachmentView = colorAttachment.createView(); - const vertexModule = t.createShaderModule({ - code: - /* GLSL( - * 'vertex', - * `#version 310 es - * void main() { - * const vec2 pos[3] = vec2[3]( - * vec2(-1.f, -3.f), vec2(3.f, 1.f), vec2(-1.f, 1.f)); - * gl_Position = vec4(pos[gl_VertexIndex], 0.f, 1.f); - * } - * ` - * ) - */ - new Uint32Array([119734787, 65536, 524296, 39, 0, 131089, 1, 393227, 1, 1280527431, 1685353262, 808793134, 0, 196622, 0, 1, 458767, 0, 4, 1852399981, 0, 10, 26, 196611, 1, 310, 262149, 4, 1852399981, 0, 393221, 8, 1348430951, 1700164197, 2019914866, 0, 393222, 8, 0, 1348430951, 1953067887, 7237481, 458758, 8, 1, 1348430951, 1953393007, 1702521171, 0, 196613, 10, 0, 393221, 26, 1449094247, 1702130277, 1684949368, 30821, 327685, 29, 1701080681, 1818386808, 101, 327752, 8, 0, 11, 0, 327752, 8, 1, 11, 1, 196679, 8, 2, 262215, 26, 11, 42, 131091, 2, 196641, 3, 2, 196630, 6, 32, 262167, 7, 6, 4, 262174, 8, 7, 6, 262176, 9, 3, 8, 262203, 9, 10, 3, 262165, 11, 32, 1, 262187, 11, 12, 0, 262167, 13, 6, 2, 262165, 14, 32, 0, 262187, 14, 15, 3, 262172, 16, 13, 15, 262187, 6, 17, 3212836864, 262187, 6, 18, 3225419776, 327724, 13, 19, 17, 18, 262187, 6, 20, 1077936128, 262187, 6, 21, 1065353216, 327724, 13, 22, 20, 21, 327724, 13, 23, 17, 21, 393260, 16, 24, 19, 22, 23, 262176, 25, 1, 11, 262203, 25, 26, 1, 262176, 28, 7, 16, 262176, 30, 7, 13, 262187, 6, 33, 0, 262176, 37, 3, 7, 327734, 2, 4, 0, 3, 131320, 5, 262203, 28, 29, 7, 262205, 11, 27, 26, 196670, 29, 24, 327745, 30, 31, 29, 27, 262205, 13, 32, 31, 327761, 6, 34, 32, 0, 327761, 6, 35, 32, 1, 458832, 7, 36, 34, 35, 33, 21, 327745, 37, 38, 10, 12, 196670, 38, 36, 65789, 65592]) - }); - const fragmentModule = t.createShaderModule({ - code: - /* GLSL( - * 'fragment', - * `#version 310 es - * precision mediump float; - * layout(location = 0) out vec4 fragColor; - * void main() { - * fragColor = vec4(0.0, 1.0, 0.0, 1.0); - * } - * ` - * ) - */ - new Uint32Array([119734787, 65536, 524296, 13, 0, 131089, 1, 393227, 1, 1280527431, 1685353262, 808793134, 0, 196622, 0, 1, 393231, 4, 4, 1852399981, 0, 9, 196624, 4, 7, 196611, 1, 310, 262149, 4, 1852399981, 0, 327685, 9, 1734439526, 1869377347, 114, 196679, 9, 0, 262215, 9, 30, 0, 131091, 2, 196641, 3, 2, 196630, 6, 32, 262167, 7, 6, 4, 262176, 8, 3, 7, 262203, 8, 9, 3, 262187, 6, 10, 0, 262187, 6, 11, 1065353216, 458796, 7, 12, 10, 11, 10, 11, 327734, 2, 4, 0, 3, 131320, 5, 196670, 9, 12, 65789, 65592]) - }); - const pl = t.device.createPipelineLayout({ - bindGroupLayouts: [] - }); - const pipeline = t.device.createRenderPipeline({ - vertexStage: { - module: vertexModule, - entryPoint: 'main' - }, - fragmentStage: { - module: fragmentModule, - entryPoint: 'main' - }, - layout: pl, - primitiveTopology: 'triangle-list', - rasterizationState: { - frontFace: 'ccw' - }, - colorStates: [{ - format: 'rgba8unorm', - alphaBlend: {}, - colorBlend: {} - }], - vertexState: { - indexFormat: 'uint16', - vertexBuffers: [] - } - }); - const encoder = t.device.createCommandEncoder(); - const pass = encoder.beginRenderPass({ - colorAttachments: [{ - attachment: colorAttachmentView, - storeOp: 'store', - loadValue: { - r: 1.0, - g: 0.0, - b: 0.0, - a: 1.0 - } - }] - }); - pass.setPipeline(pipeline); - pass.draw(3, 1, 0, 0); - pass.endPass(); - encoder.copyTextureToBuffer({ - texture: colorAttachment, - mipLevel: 0, - origin: { - x: 0, - y: 0, - z: 0 - } - }, { - buffer: dst, - rowPitch: 256, - imageHeight: 1 - }, { - width: 1, - height: 1, - depth: 1 - }); - t.device.defaultQueue.submit([encoder.finish()]); - t.expectContents(dst, new Uint8Array([0x00, 0xff, 0x00, 0xff])); -}); -//# sourceMappingURL=rendering.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/storeop.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/storeop.spec.js deleted file mode 100644 index 1f758cc5c2e..00000000000 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/storeop.spec.js +++ /dev/null @@ -1,113 +0,0 @@ -/** -* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts -**/ - -export const description = ` -renderPass store op test that drawn quad is either stored or cleared based on storeop`; -import { TestGroup } from '../../../../framework/index.js'; -import { GPUTest } from '../../gpu_test.js'; -export const g = new TestGroup(GPUTest); -g.test('storeOp controls whether 1x1 drawn quad is stored', async t => { - const renderTexture = t.device.createTexture({ - size: { - width: 1, - height: 1, - depth: 1 - }, - format: 'r8unorm', - usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.OUTPUT_ATTACHMENT - }); // create render pipeline - - const vertexModule = t.createShaderModule({ - code: - /* GLSL( - * 'vertex', - * `#version 450 - * const vec2 pos[3] = vec2[3]( - * vec2( 1.0f, -1.0f), - * vec2( 1.0f, 1.0f), - * vec2(-1.0f, 1.0f) - * ); - * - * void main() { - * gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0); - * }` - * ) - */ - new Uint32Array([119734787, 65536, 524296, 39, 0, 131089, 1, 393227, 1, 1280527431, 1685353262, 808793134, 0, 196622, 0, 1, 458767, 0, 4, 1852399981, 0, 13, 26, 196611, 2, 450, 262149, 4, 1852399981, 0, 393221, 11, 1348430951, 1700164197, 2019914866, 0, 393222, 11, 0, 1348430951, 1953067887, 7237481, 458758, 11, 1, 1348430951, 1953393007, 1702521171, 0, 458758, 11, 2, 1130327143, 1148217708, 1635021673, 6644590, 458758, 11, 3, 1130327143, 1147956341, 1635021673, 6644590, 196613, 13, 0, 393221, 26, 1449094247, 1702130277, 1684949368, 30821, 327685, 29, 1701080681, 1818386808, 101, 327752, 11, 0, 11, 0, 327752, 11, 1, 11, 1, 327752, 11, 2, 11, 3, 327752, 11, 3, 11, 4, 196679, 11, 2, 262215, 26, 11, 42, 131091, 2, 196641, 3, 2, 196630, 6, 32, 262167, 7, 6, 4, 262165, 8, 32, 0, 262187, 8, 9, 1, 262172, 10, 6, 9, 393246, 11, 7, 6, 10, 10, 262176, 12, 3, 11, 262203, 12, 13, 3, 262165, 14, 32, 1, 262187, 14, 15, 0, 262167, 16, 6, 2, 262187, 8, 17, 3, 262172, 18, 16, 17, 262187, 6, 19, 1065353216, 262187, 6, 20, 3212836864, 327724, 16, 21, 19, 20, 327724, 16, 22, 19, 19, 327724, 16, 23, 20, 19, 393260, 18, 24, 21, 22, 23, 262176, 25, 1, 14, 262203, 25, 26, 1, 262176, 28, 7, 18, 262176, 30, 7, 16, 262187, 6, 33, 0, 262176, 37, 3, 7, 327734, 2, 4, 0, 3, 131320, 5, 262203, 28, 29, 7, 262205, 14, 27, 26, 196670, 29, 24, 327745, 30, 31, 29, 27, 262205, 16, 32, 31, 327761, 6, 34, 32, 0, 327761, 6, 35, 32, 1, 458832, 7, 36, 34, 35, 33, 19, 327745, 37, 38, 13, 15, 196670, 38, 36, 65789, 65592]) - }); - const fragmentModule = t.createShaderModule({ - code: - /* GLSL( - * 'fragment', - * `#version 450 - * layout(location = 0) out vec4 fragColor; - * void main() { - * fragColor = vec4(1.0, 0.0, 0.0, 1.0); - * }` - * ) - */ - new Uint32Array([119734787, 65536, 524296, 13, 0, 131089, 1, 393227, 1, 1280527431, 1685353262, 808793134, 0, 196622, 0, 1, 393231, 4, 4, 1852399981, 0, 9, 196624, 4, 7, 196611, 2, 450, 262149, 4, 1852399981, 0, 327685, 9, 1734439526, 1869377347, 114, 262215, 9, 30, 0, 131091, 2, 196641, 3, 2, 196630, 6, 32, 262167, 7, 6, 4, 262176, 8, 3, 7, 262203, 8, 9, 3, 262187, 6, 10, 1065353216, 262187, 6, 11, 0, 458796, 7, 12, 10, 11, 11, 10, 327734, 2, 4, 0, 3, 131320, 5, 196670, 9, 12, 65789, 65592]) - }); - const renderPipeline = t.device.createRenderPipeline({ - vertexStage: { - module: vertexModule, - entryPoint: 'main' - }, - fragmentStage: { - module: fragmentModule, - entryPoint: 'main' - }, - layout: t.device.createPipelineLayout({ - bindGroupLayouts: [] - }), - primitiveTopology: 'triangle-list', - colorStates: [{ - format: 'r8unorm' - }] - }); // encode pass and submit - - const encoder = t.device.createCommandEncoder(); - const pass = encoder.beginRenderPass({ - colorAttachments: [{ - attachment: renderTexture.createView(), - storeOp: t.params.storeOp, - loadValue: { - r: 0.0, - g: 0.0, - b: 0.0, - a: 0.0 - } - }] - }); - pass.setPipeline(renderPipeline); - pass.draw(3, 1, 0, 0); - pass.endPass(); - const dstBuffer = t.device.createBuffer({ - size: 4, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC - }); - encoder.copyTextureToBuffer({ - texture: renderTexture - }, { - buffer: dstBuffer, - rowPitch: 256, - imageHeight: 1 - }, { - width: 1, - height: 1, - depth: 1 - }); - t.device.defaultQueue.submit([encoder.finish()]); // expect the buffer to be clear - - const expectedContent = new Uint32Array([t.params._expected]); - t.expectContents(dstBuffer, expectedContent); -}).params([{ - storeOp: 'store', - _expected: 255 -}, // -{ - storeOp: 'clear', - _expected: 0 -}]); -//# sourceMappingURL=storeop.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/index.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/index.js deleted file mode 100644 index e566792357a..00000000000 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/index.js +++ /dev/null @@ -1,144 +0,0 @@ -// AUTO-GENERATED - DO NOT EDIT. See src/tools/gen_listings.ts. - -export const listing = [ - { - "path": "", - "description": "WebGPU conformance test suite." - }, - { - "path": "buffers/", - "description": "GPUBuffer tests." - }, - { - "path": "buffers/create_mapped", - "description": "" - }, - { - "path": "buffers/map", - "description": "" - }, - { - "path": "buffers/map_detach", - "description": "" - }, - { - "path": "buffers/map_oom", - "description": "" - }, - { - "path": "canvas/context_creation", - "description": "" - }, - { - "path": "command_buffer/basic", - "description": "Basic tests." - }, - { - "path": "command_buffer/compute/basic", - "description": "Basic command buffer compute tests." - }, - { - "path": "command_buffer/copies", - "description": "copy{Buffer,Texture}To{Buffer,Texture} tests." - }, - { - "path": "command_buffer/render/basic", - "description": "Basic command buffer rendering tests." - }, - { - "path": "command_buffer/render/rendering", - "description": "" - }, - { - "path": "command_buffer/render/storeop", - "description": "renderPass store op test that drawn quad is either stored or cleared based on storeop" - }, - { - "path": "copyImageBitmapToTexture", - "description": "copy imageBitmap To texture tests." - }, - { - "path": "examples", - "description": "Examples of writing CTS tests with various features.\n\nStart here when looking for examples of basic framework usage." - }, - { - "path": "fences", - "description": "" - }, - { - "path": "resource_init/sampled_texture_clear", - "description": "computePass test that sampled texture is cleared" - }, - { - "path": "validation/createBindGroup", - "description": "createBindGroup validation tests." - }, - { - "path": "validation/createBindGroupLayout", - "description": "createBindGroupLayout validation tests." - }, - { - "path": "validation/createPipelineLayout", - "description": "createPipelineLayout validation tests." - }, - { - "path": "validation/createRenderPipeline", - "description": "createRenderPipeline validation tests." - }, - { - "path": "validation/createTexture", - "description": "createTexture validation tests." - }, - { - "path": "validation/createView", - "description": "createView validation tests." - }, - { - "path": "validation/error_scope", - "description": "error scope validation tests." - }, - { - "path": "validation/fences", - "description": "fences validation tests." - }, - { - "path": "validation/queue_submit", - "description": "queue submit validation tests." - }, - { - "path": "validation/render_pass", - "description": "render pass validation tests." - }, - { - "path": "validation/render_pass_descriptor", - "description": "render pass descriptor validation tests." - }, - { - "path": "validation/setBindGroup", - "description": "setBindGroup validation tests." - }, - { - "path": "validation/setBlendColor", - "description": "setBlendColor validation tests." - }, - { - "path": "validation/setScissorRect", - "description": "setScissorRect validation tests." - }, - { - "path": "validation/setStencilReference", - "description": "setStencilReference validation tests." - }, - { - "path": "validation/setVertexBuffer", - "description": "setVertexBuffer validation tests." - }, - { - "path": "validation/setViewport", - "description": "setViewport validation tests." - }, - { - "path": "validation/vertex_state", - "description": "vertexState validation tests." - } -]; diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/resource_init/sampled_texture_clear.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/resource_init/sampled_texture_clear.spec.js deleted file mode 100644 index a8fb1ad71d1..00000000000 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/resource_init/sampled_texture_clear.spec.js +++ /dev/null @@ -1,98 +0,0 @@ -/** -* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts -**/ - -export const description = ` -computePass test that sampled texture is cleared`; -import { TestGroup } from '../../../framework/index.js'; -import { GPUTest } from '../gpu_test.js'; -export const g = new TestGroup(GPUTest); -g.test('compute pass test that sampled texture is cleared', async t => { - const texture = t.device.createTexture({ - size: { - width: 256, - height: 256, - depth: 1 - }, - format: 'r8unorm', - usage: GPUTextureUsage.SAMPLED - }); - const bufferTex = t.device.createBuffer({ - size: 4 * 256 * 256, - usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST - }); - const sampler = t.device.createSampler(); - const bindGroupLayout = t.device.createBindGroupLayout({ - bindings: [{ - binding: 0, - visibility: GPUShaderStage.COMPUTE, - type: 'sampled-texture' - }, { - binding: 1, - visibility: GPUShaderStage.COMPUTE, - type: 'storage-buffer' - }, { - binding: 2, - visibility: GPUShaderStage.COMPUTE, - type: 'sampler' - }] - }); // create compute pipeline - - const computeModule = t.device.createShaderModule({ - code: - /* GLSL( - * 'compute', - * `#version 450 - * layout(binding = 0) uniform texture2D sampleTex; - * layout(std430, binding = 1) buffer BufferTex { - * vec4 result; - * } bufferTex; - * layout(binding = 2) uniform sampler sampler0; - * void main() { - * bufferTex.result = - * texelFetch(sampler2D(sampleTex, sampler0), ivec2(0,0), 0); - * }` - * ) - */ - new Uint32Array([119734787, 65536, 524296, 29, 0, 131089, 1, 393227, 1, 1280527431, 1685353262, 808793134, 0, 196622, 0, 1, 327695, 5, 4, 1852399981, 0, 393232, 4, 17, 1, 1, 1, 196611, 2, 450, 262149, 4, 1852399981, 0, 327685, 8, 1717990722, 1700033125, 120, 327686, 8, 0, 1970496882, 29804, 327685, 10, 1717990754, 1700033125, 120, 327685, 15, 1886216563, 1700029804, 120, 327685, 19, 1886216563, 812803436, 0, 327752, 8, 0, 35, 0, 196679, 8, 3, 262215, 10, 34, 0, 262215, 10, 33, 1, 262215, 15, 34, 0, 262215, 15, 33, 0, 262215, 19, 34, 0, 262215, 19, 33, 2, 131091, 2, 196641, 3, 2, 196630, 6, 32, 262167, 7, 6, 4, 196638, 8, 7, 262176, 9, 2, 8, 262203, 9, 10, 2, 262165, 11, 32, 1, 262187, 11, 12, 0, 589849, 13, 6, 1, 0, 0, 0, 1, 0, 262176, 14, 0, 13, 262203, 14, 15, 0, 131098, 17, 262176, 18, 0, 17, 262203, 18, 19, 0, 196635, 21, 13, 262167, 23, 11, 2, 327724, 23, 24, 12, 12, 262176, 27, 2, 7, 327734, 2, 4, 0, 3, 131320, 5, 262205, 13, 16, 15, 262205, 17, 20, 19, 327766, 21, 22, 16, 20, 262244, 13, 25, 22, 458847, 7, 26, 25, 24, 2, 12, 327745, 27, 28, 10, 12, 196670, 28, 26, 65789, 65592]) - }); - const pipelineLayout = t.device.createPipelineLayout({ - bindGroupLayouts: [bindGroupLayout] - }); - const computePipeline = t.device.createComputePipeline({ - computeStage: { - module: computeModule, - entryPoint: 'main' - }, - layout: pipelineLayout - }); // create bindgroup - - const bindGroup = t.device.createBindGroup({ - layout: bindGroupLayout, - bindings: [{ - binding: 0, - resource: texture.createView() - }, { - binding: 1, - resource: { - buffer: bufferTex, - offset: 0, - size: 4 * 256 * 256 - } - }, { - binding: 2, - resource: sampler - }] - }); // encode the pass and submit - - const encoder = t.device.createCommandEncoder(); - const pass = encoder.beginComputePass(); - pass.setPipeline(computePipeline); - pass.setBindGroup(0, bindGroup); - pass.dispatch(256, 256, 1); - pass.endPass(); - const commands = encoder.finish(); - t.device.defaultQueue.submit([commands]); - await t.expectContents(bufferTex, new Uint32Array([0])); -}); -//# sourceMappingURL=sampled_texture_clear.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createRenderPipeline.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createRenderPipeline.spec.js deleted file mode 100644 index e4dd32af9e8..00000000000 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createRenderPipeline.spec.js +++ /dev/null @@ -1,268 +0,0 @@ -/** -* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts -**/ - -export const description = ` -createRenderPipeline validation tests. -`; -import { TestGroup, poptions } from '../../../framework/index.js'; -import { kTextureFormatInfo, kTextureFormats } from '../capability_info.js'; -import { ValidationTest } from './validation_test.js'; - -class F extends ValidationTest { - async init() { - await super.init(); - await this.initGLSL(); - } - - getDescriptor(options = {}) { - const defaultColorStates = [{ - format: 'rgba8unorm' - }]; - const { - primitiveTopology = 'triangle-list', - colorStates = defaultColorStates, - sampleCount = 1, - depthStencilState - } = options; - const format = colorStates.length ? colorStates[0].format : 'rgba8unorm'; - return { - vertexStage: this.getVertexStage(), - fragmentStage: this.getFragmentStage(format), - layout: this.getPipelineLayout(), - primitiveTopology, - colorStates, - sampleCount, - depthStencilState - }; - } - - getVertexStage() { - return { - module: this.createShaderModule({ - code: - /* GLSL( - * 'vertex', - * `#version 450 - * void main() { - * gl_Position = vec4(0.0, 0.0, 0.0, 1.0); - * } - * ` - * ) - */ - new Uint32Array([119734787, 65536, 524296, 21, 0, 131089, 1, 393227, 1, 1280527431, 1685353262, 808793134, 0, 196622, 0, 1, 393231, 0, 4, 1852399981, 0, 13, 196611, 2, 450, 262149, 4, 1852399981, 0, 393221, 11, 1348430951, 1700164197, 2019914866, 0, 393222, 11, 0, 1348430951, 1953067887, 7237481, 458758, 11, 1, 1348430951, 1953393007, 1702521171, 0, 458758, 11, 2, 1130327143, 1148217708, 1635021673, 6644590, 458758, 11, 3, 1130327143, 1147956341, 1635021673, 6644590, 196613, 13, 0, 327752, 11, 0, 11, 0, 327752, 11, 1, 11, 1, 327752, 11, 2, 11, 3, 327752, 11, 3, 11, 4, 196679, 11, 2, 131091, 2, 196641, 3, 2, 196630, 6, 32, 262167, 7, 6, 4, 262165, 8, 32, 0, 262187, 8, 9, 1, 262172, 10, 6, 9, 393246, 11, 7, 6, 10, 10, 262176, 12, 3, 11, 262203, 12, 13, 3, 262165, 14, 32, 1, 262187, 14, 15, 0, 262187, 6, 16, 0, 262187, 6, 17, 1065353216, 458796, 7, 18, 16, 16, 16, 17, 262176, 19, 3, 7, 327734, 2, 4, 0, 3, 131320, 5, 327745, 19, 20, 13, 15, 196670, 20, 18, 65789, 65592]) - }), - entryPoint: 'main' - }; - } - - getFragmentStage(format) { - let fragColorType; - - if (format.endsWith('sint')) { - fragColorType = 'ivec4'; - } else if (format.endsWith('uint')) { - fragColorType = 'uvec4'; - } else { - fragColorType = 'vec4'; - } - - const code = ` - #version 450 - layout(location = 0) out ${fragColorType} fragColor; - void main() { - fragColor = ${fragColorType}(0.0, 1.0, 0.0, 1.0); - } - `; - return { - module: this.makeShaderModuleFromGLSL('fragment', code), - entryPoint: 'main' - }; - } - - getPipelineLayout() { - return this.device.createPipelineLayout({ - bindGroupLayouts: [] - }); - } - - createTexture(params) { - const { - format, - sampleCount - } = params; - return this.device.createTexture({ - size: { - width: 4, - height: 4, - depth: 1 - }, - usage: GPUTextureUsage.OUTPUT_ATTACHMENT, - format, - sampleCount - }); - } - -} - -export const g = new TestGroup(F); -g.test('basic use of createRenderPipeline', t => { - const descriptor = t.getDescriptor(); - t.device.createRenderPipeline(descriptor); -}); -g.test('at least one color state is required', async t => { - const goodDescriptor = t.getDescriptor({ - colorStates: [{ - format: 'rgba8unorm' - }] - }); // Control case - - t.device.createRenderPipeline(goodDescriptor); // Fail because lack of color states - - const badDescriptor = t.getDescriptor({ - colorStates: [] - }); - t.expectValidationError(() => { - t.device.createRenderPipeline(badDescriptor); - }); -}); -g.test('color formats must be renderable', async t => { - const format = t.params.format; - const info = kTextureFormatInfo[format]; - const descriptor = t.getDescriptor({ - colorStates: [{ - format - }] - }); - - if (info.renderable && info.color) { - // Succeeds when color format is renderable - t.device.createRenderPipeline(descriptor); - } else { - // Fails because when format is non-renderable - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}).params(poptions('format', kTextureFormats)); -g.test('sample count must be valid', async t => { - const { - sampleCount, - _success - } = t.params; - const descriptor = t.getDescriptor({ - sampleCount - }); - - if (_success) { - // Succeeds when sample count is valid - t.device.createRenderPipeline(descriptor); - } else { - // Fails when sample count is not 4 or 1 - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}).params([{ - sampleCount: 0, - _success: false -}, { - sampleCount: 1, - _success: true -}, { - sampleCount: 2, - _success: false -}, { - sampleCount: 3, - _success: false -}, { - sampleCount: 4, - _success: true -}, { - sampleCount: 8, - _success: false -}, { - sampleCount: 16, - _success: false -}]); -g.test('sample count must be equal to the one of every attachment in the render pass', async t => { - const { - attachmentSamples, - pipelineSamples, - _success - } = t.params; - const colorTexture = t.createTexture({ - format: 'rgba8unorm', - sampleCount: attachmentSamples - }); - const depthStencilTexture = t.createTexture({ - format: 'depth24plus-stencil8', - sampleCount: attachmentSamples - }); - const renderPassDescriptorWithoutDepthStencil = { - colorAttachments: [{ - attachment: colorTexture.createView(), - loadValue: { - r: 1.0, - g: 0.0, - b: 0.0, - a: 1.0 - } - }] - }; - const renderPassDescriptorWithDepthStencilOnly = { - colorAttachments: [], - depthStencilAttachment: { - attachment: depthStencilTexture.createView(), - depthLoadValue: 1.0, - depthStoreOp: 'store', - stencilLoadValue: 0, - stencilStoreOp: 'store' - } - }; - const pipelineWithoutDepthStencil = t.device.createRenderPipeline(t.getDescriptor({ - sampleCount: pipelineSamples - })); - const pipelineWithDepthStencilOnly = t.device.createRenderPipeline(t.getDescriptor({ - colorStates: [], - depthStencilState: { - format: 'depth24plus-stencil8' - }, - sampleCount: pipelineSamples - })); - - for (const { - renderPassDescriptor, - pipeline - } of [{ - renderPassDescriptor: renderPassDescriptorWithoutDepthStencil, - pipeline: pipelineWithoutDepthStencil - }, { - renderPassDescriptor: renderPassDescriptorWithDepthStencilOnly, - pipeline: pipelineWithDepthStencilOnly - }]) { - const commandEncoder = t.device.createCommandEncoder(); - const renderPass = commandEncoder.beginRenderPass(renderPassDescriptor); - renderPass.setPipeline(pipeline); - renderPass.endPass(); - t.expectValidationError(() => { - commandEncoder.finish(); - }, !_success); - } -}).params([{ - attachmentSamples: 4, - pipelineSamples: 4, - _success: true -}, // It is allowed to use multisampled render pass and multisampled render pipeline. -{ - attachmentSamples: 4, - pipelineSamples: 1, - _success: false -}, // It is not allowed to use multisampled render pass and non-multisampled render pipeline. -{ - attachmentSamples: 1, - pipelineSamples: 4, - _success: false -} // It is not allowed to use non-multisampled render pass and multisampled render pipeline. -]); -//# sourceMappingURL=createRenderPipeline.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/render_pass.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/render_pass.spec.js deleted file mode 100644 index 67f7bec6d66..00000000000 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/render_pass.spec.js +++ /dev/null @@ -1,174 +0,0 @@ -/** -* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts -**/ - -export const description = ` -render pass validation tests. -`; -import { TestGroup } from '../../../framework/index.js'; -import { ValidationTest } from './validation_test.js'; - -class F extends ValidationTest { - getUniformBuffer() { - return this.device.createBuffer({ - size: 4 * Float32Array.BYTES_PER_ELEMENT, - usage: GPUBufferUsage.UNIFORM - }); - } - - createRenderPipeline(pipelineLayout) { - const vertexModule = this.createShaderModule({ - code: - /* GLSL( - * 'vertex', - * `#version 450 - * layout (set = 0, binding = 0) uniform vertexUniformBuffer { - * mat2 transform; - * }; - * void main() { - * const vec2 pos[3] = vec2[3](vec2(-1.f, -1.f), vec2(1.f, -1.f), vec2(-1.f, 1.f)); - * gl_Position = vec4(transform * pos[gl_VertexIndex], 0.f, 1.f); - * } - * ` - * ) - */ - new Uint32Array([119734787, 65536, 524296, 47, 0, 131089, 1, 393227, 1, 1280527431, 1685353262, 808793134, 0, 196622, 0, 1, 458767, 0, 4, 1852399981, 0, 13, 33, 196611, 2, 450, 262149, 4, 1852399981, 0, 393221, 11, 1348430951, 1700164197, 2019914866, 0, 393222, 11, 0, 1348430951, 1953067887, 7237481, 458758, 11, 1, 1348430951, 1953393007, 1702521171, 0, 458758, 11, 2, 1130327143, 1148217708, 1635021673, 6644590, 458758, 11, 3, 1130327143, 1147956341, 1635021673, 6644590, 196613, 13, 0, 458757, 18, 1953654134, 1851095141, 1919903337, 1718960749, 7497062, 393222, 18, 0, 1851880052, 1919903347, 109, 196613, 20, 0, 393221, 33, 1449094247, 1702130277, 1684949368, 30821, 327685, 36, 1701080681, 1818386808, 101, 327752, 11, 0, 11, 0, 327752, 11, 1, 11, 1, 327752, 11, 2, 11, 3, 327752, 11, 3, 11, 4, 196679, 11, 2, 262216, 18, 0, 5, 327752, 18, 0, 35, 0, 327752, 18, 0, 7, 16, 196679, 18, 2, 262215, 20, 34, 0, 262215, 20, 33, 0, 262215, 33, 11, 42, 131091, 2, 196641, 3, 2, 196630, 6, 32, 262167, 7, 6, 4, 262165, 8, 32, 0, 262187, 8, 9, 1, 262172, 10, 6, 9, 393246, 11, 7, 6, 10, 10, 262176, 12, 3, 11, 262203, 12, 13, 3, 262165, 14, 32, 1, 262187, 14, 15, 0, 262167, 16, 6, 2, 262168, 17, 16, 2, 196638, 18, 17, 262176, 19, 2, 18, 262203, 19, 20, 2, 262176, 21, 2, 17, 262187, 8, 24, 3, 262172, 25, 16, 24, 262187, 6, 26, 3212836864, 327724, 16, 27, 26, 26, 262187, 6, 28, 1065353216, 327724, 16, 29, 28, 26, 327724, 16, 30, 26, 28, 393260, 25, 31, 27, 29, 30, 262176, 32, 1, 14, 262203, 32, 33, 1, 262176, 35, 7, 25, 262176, 37, 7, 16, 262187, 6, 41, 0, 262176, 45, 3, 7, 327734, 2, 4, 0, 3, 131320, 5, 262203, 35, 36, 7, 327745, 21, 22, 20, 15, 262205, 17, 23, 22, 262205, 14, 34, 33, 196670, 36, 31, 327745, 37, 38, 36, 34, 262205, 16, 39, 38, 327825, 16, 40, 23, 39, 327761, 6, 42, 40, 0, 327761, 6, 43, 40, 1, 458832, 7, 44, 42, 43, 41, 28, 327745, 45, 46, 13, 15, 196670, 46, 44, 65789, 65592]) - }); - const fragmentModule = this.createShaderModule({ - code: - /* GLSL( - * 'fragment', - * `#version 450 - * layout (set = 1, binding = 0) uniform fragmentUniformBuffer { - * vec4 color; - * }; - * layout(location = 0) out vec4 fragColor; - * void main() { - * } - * ` - * ) - */ - new Uint32Array([119734787, 65536, 524296, 13, 0, 131089, 1, 393227, 1, 1280527431, 1685353262, 808793134, 0, 196622, 0, 1, 393231, 4, 4, 1852399981, 0, 12, 196624, 4, 7, 196611, 2, 450, 262149, 4, 1852399981, 0, 524293, 8, 1734439526, 1953391981, 1718185557, 1114468975, 1701209717, 114, 327686, 8, 0, 1869377379, 114, 196613, 10, 0, 327685, 12, 1734439526, 1869377347, 114, 327752, 8, 0, 35, 0, 196679, 8, 2, 262215, 10, 34, 1, 262215, 10, 33, 0, 262215, 12, 30, 0, 131091, 2, 196641, 3, 2, 196630, 6, 32, 262167, 7, 6, 4, 196638, 8, 7, 262176, 9, 2, 8, 262203, 9, 10, 2, 262176, 11, 3, 7, 262203, 11, 12, 3, 327734, 2, 4, 0, 3, 131320, 5, 65789, 65592]) - }); - const pipeline = this.device.createRenderPipeline({ - vertexStage: { - module: vertexModule, - entryPoint: 'main' - }, - fragmentStage: { - module: fragmentModule, - entryPoint: 'main' - }, - layout: pipelineLayout, - primitiveTopology: 'triangle-list', - colorStates: [{ - format: 'rgba8unorm' - }] - }); - return pipeline; - } - - beginRenderPass(commandEncoder) { - const attachmentTexture = this.device.createTexture({ - format: 'rgba8unorm', - size: { - width: 16, - height: 16, - depth: 1 - }, - usage: GPUTextureUsage.OUTPUT_ATTACHMENT - }); - return commandEncoder.beginRenderPass({ - colorAttachments: [{ - attachment: attachmentTexture.createView(), - loadValue: { - r: 1.0, - g: 0.0, - b: 0.0, - a: 1.0 - } - }] - }); - } - -} - -export const g = new TestGroup(F); -g.test('it is invalid to draw in a render pass with missing bind groups', async t => { - const { - setBindGroup1, - setBindGroup2, - _success - } = t.params; - const uniformBuffer = t.getUniformBuffer(); - const bindGroupLayout1 = t.device.createBindGroupLayout({ - bindings: [{ - binding: 0, - visibility: GPUShaderStage.VERTEX, - type: 'uniform-buffer' - }] - }); - const bindGroup1 = t.device.createBindGroup({ - bindings: [{ - binding: 0, - resource: { - buffer: uniformBuffer - } - }], - layout: bindGroupLayout1 - }); - const bindGroupLayout2 = t.device.createBindGroupLayout({ - bindings: [{ - binding: 0, - visibility: GPUShaderStage.FRAGMENT, - type: 'uniform-buffer' - }] - }); - const bindGroup2 = t.device.createBindGroup({ - bindings: [{ - binding: 0, - resource: { - buffer: uniformBuffer - } - }], - layout: bindGroupLayout2 - }); - const pipelineLayout = t.device.createPipelineLayout({ - bindGroupLayouts: [bindGroupLayout1, bindGroupLayout2] - }); - const pipeline = t.createRenderPipeline(pipelineLayout); - const commandEncoder = t.device.createCommandEncoder(); - const renderPass = t.beginRenderPass(commandEncoder); - renderPass.setPipeline(pipeline); - - if (setBindGroup1) { - renderPass.setBindGroup(0, bindGroup1); - } - - if (setBindGroup2) { - renderPass.setBindGroup(1, bindGroup2); - } - - renderPass.draw(3, 1, 0, 0); - renderPass.endPass(); - t.expectValidationError(() => { - commandEncoder.finish(); - }, !_success); -}).params([{ - setBindGroup1: true, - setBindGroup2: true, - _success: true -}, { - setBindGroup1: true, - setBindGroup2: false, - _success: false -}, { - setBindGroup1: false, - setBindGroup2: true, - _success: false -}, { - setBindGroup1: false, - setBindGroup2: false, - _success: false -}]); -//# sourceMappingURL=render_pass.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setVertexBuffer.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setVertexBuffer.spec.js deleted file mode 100644 index 47b86150129..00000000000 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setVertexBuffer.spec.js +++ /dev/null @@ -1,184 +0,0 @@ -/** -* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts -**/ - -export const description = ` -setVertexBuffer validation tests. -`; -import { TestGroup, range } from '../../../framework/index.js'; -import { ValidationTest } from './validation_test.js'; - -class F extends ValidationTest { - async init() { - await super.init(); - await this.initGLSL(); - } - - getVertexBuffer() { - return this.device.createBuffer({ - size: 256, - usage: GPUBufferUsage.VERTEX - }); - } - - createRenderPipeline(bufferCount) { - const descriptor = { - vertexStage: this.getVertexStage(bufferCount), - fragmentStage: this.getFragmentStage(), - layout: this.getPipelineLayout(), - primitiveTopology: 'triangle-list', - colorStates: [{ - format: 'rgba8unorm' - }], - vertexState: { - vertexBuffers: [{ - arrayStride: 3 * 4, - attributes: range(bufferCount, i => ({ - format: 'float3', - offset: 0, - shaderLocation: i - })) - }] - } - }; - return this.device.createRenderPipeline(descriptor); - } - - getVertexStage(bufferCount) { - const code = ` - #version 450 - ${range(bufferCount, i => `\nlayout(location = ${i}) in vec3 a_position${i};`).join('')} - void main() { - gl_Position = vec4(0.0, 0.0, 0.0, 1.0); - } - `; - return { - module: this.makeShaderModuleFromGLSL('vertex', code), - entryPoint: 'main' - }; - } - - getFragmentStage() { - const code = ` - #version 450 - layout(location = 0) out vec4 fragColor; - void main() { - fragColor = vec4(0.0, 1.0, 0.0, 1.0); - } - `; - return { - module: this.makeShaderModuleFromGLSL('fragment', code), - entryPoint: 'main' - }; - } - - getPipelineLayout() { - return this.device.createPipelineLayout({ - bindGroupLayouts: [] - }); - } - - beginRenderPass(commandEncoder) { - const attachmentTexture = this.device.createTexture({ - format: 'rgba8unorm', - size: { - width: 16, - height: 16, - depth: 1 - }, - usage: GPUTextureUsage.OUTPUT_ATTACHMENT - }); - return commandEncoder.beginRenderPass({ - colorAttachments: [{ - attachment: attachmentTexture.createView(), - loadValue: { - r: 1.0, - g: 0.0, - b: 0.0, - a: 1.0 - } - }] - }); - } - -} - -export const g = new TestGroup(F); -g.test('vertex buffers inherit from previous pipeline', async t => { - const pipeline1 = t.createRenderPipeline(1); - const pipeline2 = t.createRenderPipeline(2); - const vertexBuffer1 = t.getVertexBuffer(); - const vertexBuffer2 = t.getVertexBuffer(); - { - // Check failure when vertex buffer is not set - const commandEncoder = t.device.createCommandEncoder(); - const renderPass = t.beginRenderPass(commandEncoder); - renderPass.setPipeline(pipeline1); - renderPass.draw(3, 1, 0, 0); - renderPass.endPass(); - t.expectValidationError(() => { - commandEncoder.finish(); - }); - } - { - // Check success when vertex buffer is inherited from previous pipeline - const commandEncoder = t.device.createCommandEncoder(); - const renderPass = t.beginRenderPass(commandEncoder); - renderPass.setPipeline(pipeline2); - renderPass.setVertexBuffer(0, vertexBuffer1); - renderPass.setVertexBuffer(1, vertexBuffer2); - renderPass.draw(3, 1, 0, 0); - renderPass.setPipeline(pipeline1); - renderPass.draw(3, 1, 0, 0); - renderPass.endPass(); - commandEncoder.finish(); - } -}); -g.test('vertex buffers do not inherit between render passes', async t => { - const pipeline1 = t.createRenderPipeline(1); - const pipeline2 = t.createRenderPipeline(2); - const vertexBuffer1 = t.getVertexBuffer(); - const vertexBuffer2 = t.getVertexBuffer(); - { - // Check success when vertex buffer is set for each render pass - const commandEncoder = t.device.createCommandEncoder(); - { - const renderPass = t.beginRenderPass(commandEncoder); - renderPass.setPipeline(pipeline2); - renderPass.setVertexBuffer(0, vertexBuffer1); - renderPass.setVertexBuffer(1, vertexBuffer2); - renderPass.draw(3, 1, 0, 0); - renderPass.endPass(); - } - { - const renderPass = t.beginRenderPass(commandEncoder); - renderPass.setPipeline(pipeline1); - renderPass.setVertexBuffer(0, vertexBuffer1); - renderPass.draw(3, 1, 0, 0); - renderPass.endPass(); - } - commandEncoder.finish(); - } - { - // Check failure because vertex buffer is not inherited in second subpass - const commandEncoder = t.device.createCommandEncoder(); - { - const renderPass = t.beginRenderPass(commandEncoder); - renderPass.setPipeline(pipeline2); - renderPass.setVertexBuffer(0, vertexBuffer1); - renderPass.setVertexBuffer(1, vertexBuffer2); - renderPass.draw(3, 1, 0, 0); - renderPass.endPass(); - } - { - const renderPass = t.beginRenderPass(commandEncoder); - renderPass.setPipeline(pipeline1); - renderPass.draw(3, 1, 0, 0); - renderPass.endPass(); - } - t.expectValidationError(() => { - commandEncoder.finish(); - }); - } -}); -//# sourceMappingURL=setVertexBuffer.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/vertex_state.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/vertex_state.spec.js deleted file mode 100644 index 103a11265c5..00000000000 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/vertex_state.spec.js +++ /dev/null @@ -1,646 +0,0 @@ -/** -* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts -**/ - -export const description = ` -vertexState validation tests. -`; -import { C, TestGroup } from '../../../framework/index.js'; -import { ValidationTest } from './validation_test.js'; -const MAX_VERTEX_ATTRIBUTES = 16; -const MAX_VERTEX_BUFFER_END = 2048; -const MAX_VERTEX_BUFFER_ARRAY_STRIDE = 2048; -const MAX_VERTEX_BUFFERS = 16; -const SIZEOF_FLOAT = Float32Array.BYTES_PER_ELEMENT; -const VERTEX_SHADER_CODE_WITH_NO_INPUT = ` - #version 450 - void main() { - gl_Position = vec4(0.0); - } -`; - -function clone(descriptor) { - return JSON.parse(JSON.stringify(descriptor)); -} - -class F extends ValidationTest { - async init() { - await super.init(); - await this.initGLSL(); - } - - getDescriptor(vertexState, vertexShaderCode) { - const descriptor = { - vertexStage: this.getVertexStage(vertexShaderCode), - fragmentStage: this.getFragmentStage(), - layout: this.getPipelineLayout(), - primitiveTopology: 'triangle-list', - colorStates: [{ - format: 'rgba8unorm' - }], - vertexState - }; - return descriptor; - } - - getVertexStage(code) { - return { - module: this.makeShaderModuleFromGLSL('vertex', code), - entryPoint: 'main' - }; - } - - getFragmentStage() { - const code = ` - #version 450 - layout(location = 0) out vec4 fragColor; - void main() { - fragColor = vec4(0.0, 1.0, 0.0, 1.0); - } - `; - return { - module: this.makeShaderModuleFromGLSL('fragment', code), - entryPoint: 'main' - }; - } - - getPipelineLayout() { - return this.device.createPipelineLayout({ - bindGroupLayouts: [] - }); - } - -} - -export const g = new TestGroup(F); -g.test('an empty vertex input is valid', t => { - const vertexState = {}; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); -}); -g.test('a null buffer is valid', t => { - { - // One null buffer is OK - const vertexState = { - vertexBuffers: [{ - arrayStride: 0, - attributes: [] - }] - }; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // One null buffer followed by a buffer is OK - const vertexState = { - vertexBuffers: [{ - arrayStride: 0, - attributes: [] - }, { - arrayStride: 0, - attributes: [{ - format: 'float', - offset: 0, - shaderLocation: 0 - }] - }] - }; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // One null buffer sitting between buffers is OK - const vertexState = { - vertexBuffers: [{ - arrayStride: 0, - attributes: [{ - format: 'float', - offset: 0, - shaderLocation: 0 - }] - }, { - arrayStride: 0, - attributes: [] - }, { - arrayStride: 0, - attributes: [{ - format: 'float', - offset: 0, - shaderLocation: 1 - }] - }] - }; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } -}); -g.test('pipeline vertex buffers are backed by attributes in vertex input', async t => { - const vertexState = { - vertexBuffers: [{ - arrayStride: 2 * SIZEOF_FLOAT, - attributes: [{ - format: 'float', - offset: 0, - shaderLocation: 0 - }, { - format: 'float', - offset: 0, - shaderLocation: 1 - }] - }] - }; - { - // Control case: pipeline with one input per attribute - const code = ` - #version 450 - layout(location = 0) in vec4 a; - layout(location = 1) in vec4 b; - void main() { - gl_Position = vec4(0.0); - } - `; - const descriptor = t.getDescriptor(vertexState, code); - t.device.createRenderPipeline(descriptor); - } - { - // Check it is valid for the pipeline to use a subset of the VertexState - const code = ` - #version 450 - layout(location = 0) in vec4 a; - void main() { - gl_Position = vec4(0.0); - } - `; - const descriptor = t.getDescriptor(vertexState, code); - t.device.createRenderPipeline(descriptor); - } - { - // Check for an error when the pipeline uses an attribute not in the vertex input - const code = ` - #version 450 - layout(location = 2) in vec4 a; - void main() { - gl_Position = vec4(0.0); - } - `; - const descriptor = t.getDescriptor(vertexState, code); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('an arrayStride of 0 is valid', t => { - const vertexState = { - vertexBuffers: [{ - arrayStride: 0, - attributes: [{ - format: C.VertexFormat.Float, - offset: 0, - shaderLocation: 0 - }] - }] - }; - { - // Works ok without attributes - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Works ok with attributes at a large-ish offset - vertexState.vertexBuffers[0].attributes[0].offset = 128; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } -}); -g.test('offset should be within vertex buffer arrayStride if arrayStride is not zero', async t => { - const vertexState = { - vertexBuffers: [{ - arrayStride: 2 * SIZEOF_FLOAT, - attributes: [{ - format: C.VertexFormat.Float, - offset: 0, - shaderLocation: 0 - }, { - format: C.VertexFormat.Float, - offset: SIZEOF_FLOAT, - shaderLocation: 1 - }] - }] - }; - { - // Control case, setting correct arrayStride and offset - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test vertex attribute offset exceed vertex buffer arrayStride range - const badVertexState = clone(vertexState); - badVertexState.vertexBuffers[0].attributes[1].format = C.VertexFormat.Float2; - const descriptor = t.getDescriptor(badVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } - { - // Test vertex attribute offset exceed vertex buffer arrayStride range - const badVertexState = clone(vertexState); - badVertexState.vertexBuffers[0].arrayStride = SIZEOF_FLOAT; - const descriptor = t.getDescriptor(badVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } - { - // It's OK if arrayStride is zero - const goodVertexState = clone(vertexState); - goodVertexState.vertexBuffers[0].arrayStride = 0; - const descriptor = t.getDescriptor(goodVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } -}); -g.test('check two attributes overlapping', async t => { - const vertexState = { - vertexBuffers: [{ - arrayStride: 2 * SIZEOF_FLOAT, - attributes: [{ - format: C.VertexFormat.Float, - offset: 0, - shaderLocation: 0 - }, { - format: C.VertexFormat.Float, - offset: SIZEOF_FLOAT, - shaderLocation: 1 - }] - }] - }; - { - // Control case, setting correct arrayStride and offset - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test two attributes overlapping - const badVertexState = clone(vertexState); - badVertexState.vertexBuffers[0].attributes[0].format = C.VertexFormat.Int2; - const descriptor = t.getDescriptor(badVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('check out of bounds condition on total number of vertex buffers', async t => { - const vertexBuffers = []; - - for (let i = 0; i < MAX_VERTEX_BUFFERS; i++) { - vertexBuffers.push({ - arrayStride: 0, - attributes: [{ - format: 'float', - offset: 0, - shaderLocation: i - }] - }); - } - - { - // Control case, setting max vertex buffer number - const vertexState = { - vertexBuffers - }; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test vertex buffer number exceed the limit - const vertexState = { - vertexBuffers: [...vertexBuffers, { - arrayStride: 0, - attributes: [{ - format: 'float', - offset: 0, - shaderLocation: MAX_VERTEX_BUFFERS - }] - }] - }; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('check out of bounds on number of vertex attributes on a single vertex buffer', async t => { - const vertexAttributes = []; - - for (let i = 0; i < MAX_VERTEX_ATTRIBUTES; i++) { - vertexAttributes.push({ - format: 'float', - offset: 0, - shaderLocation: i - }); - } - - { - // Control case, setting max vertex buffer number - const vertexState = { - vertexBuffers: [{ - arrayStride: 0, - attributes: vertexAttributes - }] - }; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test vertex attribute number exceed the limit - const vertexState = { - vertexBuffers: [{ - arrayStride: 0, - attributes: [...vertexAttributes, { - format: 'float', - offset: 0, - shaderLocation: MAX_VERTEX_ATTRIBUTES - }] - }] - }; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('check out of bounds on number of vertex attributes across vertex buffers', async t => { - const vertexBuffers = []; - - for (let i = 0; i < MAX_VERTEX_ATTRIBUTES; i++) { - vertexBuffers.push({ - arrayStride: 0, - attributes: [{ - format: 'float', - offset: 0, - shaderLocation: i - }] - }); - } - - { - // Control case, setting max vertex buffer number - const vertexState = { - vertexBuffers - }; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test vertex attribute number exceed the limit - vertexBuffers[MAX_VERTEX_ATTRIBUTES - 1].attributes.push({ - format: 'float', - offset: 0, - shaderLocation: MAX_VERTEX_ATTRIBUTES - }); - const vertexState = { - vertexBuffers - }; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('check out of bounds condition on input strides', async t => { - const vertexState = { - vertexBuffers: [{ - arrayStride: MAX_VERTEX_BUFFER_ARRAY_STRIDE, - attributes: [] - }] - }; - { - // Control case, setting max input arrayStride - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test input arrayStride OOB - vertexState.vertexBuffers[0].arrayStride = MAX_VERTEX_BUFFER_ARRAY_STRIDE + 4; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('check multiple of 4 bytes constraint on input arrayStride', async t => { - const vertexState = { - vertexBuffers: [{ - arrayStride: 4, - attributes: [{ - format: C.VertexFormat.Uchar2, - offset: 0, - shaderLocation: 0 - }] - }] - }; - { - // Control case, setting input arrayStride 4 bytes - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test input arrayStride not multiple of 4 bytes - vertexState.vertexBuffers[0].arrayStride = 2; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('identical duplicate attributes are invalid', async t => { - const vertexState = { - vertexBuffers: [{ - arrayStride: 0, - attributes: [{ - format: C.VertexFormat.Float, - offset: 0, - shaderLocation: 0 - }] - }] - }; - { - // Control case, setting attribute 0 - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Oh no, attribute 0 is set twice - vertexState.vertexBuffers[0].attributes.push({ - format: C.VertexFormat.Float, - offset: 0, - shaderLocation: 0 - }); - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('we cannot set same shader location', async t => { - { - const vertexState = { - vertexBuffers: [{ - arrayStride: 0, - attributes: [{ - format: C.VertexFormat.Float, - offset: 0, - shaderLocation: 0 - }, { - format: C.VertexFormat.Float, - offset: SIZEOF_FLOAT, - shaderLocation: 1 - }] - }] - }; - { - // Control case, setting different shader locations in two attributes - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test same shader location in two attributes in the same buffer - vertexState.vertexBuffers[0].attributes[1].shaderLocation = 0; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } - } - { - const vertexState = { - vertexBuffers: [{ - arrayStride: 0, - attributes: [{ - format: 'float', - offset: 0, - shaderLocation: 0 - }] - }, { - arrayStride: 0, - attributes: [{ - format: 'float', - offset: 0, - shaderLocation: 0 - }] - }] - }; // Test same shader location in two attributes in different buffers - - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('check out of bounds condition on attribute shader location', async t => { - const vertexState = { - vertexBuffers: [{ - arrayStride: 0, - attributes: [{ - format: C.VertexFormat.Float, - offset: 0, - shaderLocation: MAX_VERTEX_ATTRIBUTES - 1 - }] - }] - }; - { - // Control case, setting last attribute shader location - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test attribute location OOB - vertexState.vertexBuffers[0].attributes[0].shaderLocation = MAX_VERTEX_ATTRIBUTES; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('check attribute offset out of bounds', async t => { - const vertexState = { - vertexBuffers: [{ - arrayStride: 0, - attributes: [{ - format: C.VertexFormat.Float2, - offset: MAX_VERTEX_BUFFER_END - 2 * SIZEOF_FLOAT, - shaderLocation: 0 - }] - }] - }; - { - // Control case, setting max attribute offset to MAX_VERTEX_BUFFER_END - 8 - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Control case, setting attribute offset to 8 - vertexState.vertexBuffers[0].attributes[0].offset = 8; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test attribute offset out of bounds - vertexState.vertexBuffers[0].attributes[0].offset = MAX_VERTEX_BUFFER_END - 4; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('check multiple of 4 bytes constraint on offset', async t => { - const vertexState = { - vertexBuffers: [{ - arrayStride: 0, - attributes: [{ - format: C.VertexFormat.Float, - offset: SIZEOF_FLOAT, - shaderLocation: 0 - }] - }] - }; - { - // Control case, setting offset 4 bytes - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test offset of 2 bytes with uchar2 format - vertexState.vertexBuffers[0].attributes[0].offset = 2; - vertexState.vertexBuffers[0].attributes[0].format = C.VertexFormat.Uchar2; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } - { - // Test offset of 2 bytes with float format - vertexState.vertexBuffers[0].attributes[0].offset = 2; - vertexState.vertexBuffers[0].attributes[0].format = C.VertexFormat.Float; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('check attribute offset overflow', async t => { - const vertexState = { - vertexBuffers: [{ - arrayStride: 0, - attributes: [{ - format: 'float', - offset: Number.MAX_SAFE_INTEGER, - shaderLocation: 0 - }] - }] - }; - const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); -}); -//# sourceMappingURL=vertex_state.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/buffers/create_mapped.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/operation/buffers/create_mapped.spec.js index 0231c95dab2..7b2bc39aa3d 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/buffers/create_mapped.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/operation/buffers/create_mapped.spec.js @@ -3,7 +3,8 @@ **/ export const description = ``; -import { TestGroup, pbool, pcombine, poptions } from '../../../framework/index.js'; +import { pbool, pcombine, poptions } from '../../../../common/framework/params.js'; +import { TestGroup } from '../../../../common/framework/test_group.js'; import { MappingTest } from './mapping_test.js'; export const g = new TestGroup(MappingTest); g.test('createBufferMapped', async t => { diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/buffers/map.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/operation/buffers/map.spec.js index ecbe7f9c340..1c73d62a95f 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/buffers/map.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/operation/buffers/map.spec.js @@ -3,7 +3,8 @@ **/ export const description = ``; -import { TestGroup, pbool, pcombine, poptions } from '../../../framework/index.js'; +import { pbool, pcombine, poptions } from '../../../../common/framework/params.js'; +import { TestGroup } from '../../../../common/framework/test_group.js'; import { MappingTest } from './mapping_test.js'; export const g = new TestGroup(MappingTest); g.test('mapWriteAsync', async t => { diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/buffers/map_detach.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/operation/buffers/map_detach.spec.js index 9174efca59c..14d5be5a631 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/buffers/map_detach.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/operation/buffers/map_detach.spec.js @@ -3,8 +3,8 @@ **/ export const description = ``; -import { TestGroup } from '../../../framework/index.js'; -import { GPUTest } from '../gpu_test.js'; +import { TestGroup } from '../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../gpu_test.js'; class F extends GPUTest { checkDetach(buffer, arrayBuffer, unmap, destroy) { diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/buffers/map_oom.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/operation/buffers/map_oom.spec.js index 24adf67fd6a..ee642a5c3b3 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/buffers/map_oom.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/operation/buffers/map_oom.spec.js @@ -3,8 +3,8 @@ **/ export const description = ``; -import { TestGroup } from '../../../framework/index.js'; -import { GPUTest } from '../gpu_test.js'; +import { TestGroup } from '../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../gpu_test.js'; function getBufferDesc() { return { diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/buffers/mapping_test.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/operation/buffers/mapping_test.js index 20d6c96ffa2..b7349059035 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/buffers/mapping_test.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/operation/buffers/mapping_test.js @@ -2,7 +2,7 @@ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts **/ -import { GPUTest } from '../gpu_test.js'; +import { GPUTest } from '../../../gpu_test.js'; export class MappingTest extends GPUTest { checkMapWrite(buffer, mappedContents, size) { this.checkMapWriteZeroed(mappedContents, size); diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/basic.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/operation/command_buffer/basic.spec.js index 6762a563c56..bc4020bfeb5 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/basic.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/operation/command_buffer/basic.spec.js @@ -5,12 +5,12 @@ export const description = ` Basic tests. `; -import { TestGroup } from '../../../framework/index.js'; -import { GPUTest } from '../gpu_test.js'; +import { TestGroup } from '../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../gpu_test.js'; export const g = new TestGroup(GPUTest); g.test('empty', async t => { const encoder = t.device.createCommandEncoder(); const cmd = encoder.finish(); - t.device.defaultQueue.submit([cmd]); // TODO: test that submit() succeeded. + t.device.defaultQueue.submit([cmd]); }); //# sourceMappingURL=basic.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/copies.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/operation/command_buffer/copies.spec.js index c5bae2ada80..c330415d851 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/copies.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/operation/command_buffer/copies.spec.js @@ -5,8 +5,8 @@ export const description = ` copy{Buffer,Texture}To{Buffer,Texture} tests. `; -import { TestGroup } from '../../../framework/index.js'; -import { GPUTest } from '../gpu_test.js'; +import { TestGroup } from '../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../gpu_test.js'; export const g = new TestGroup(GPUTest); g.test('b2b', async t => { const data = new Uint32Array([0x01020304]); @@ -49,8 +49,7 @@ g.test('b2t2b', async t => { const encoder = t.device.createCommandEncoder(); encoder.copyBufferToTexture({ buffer: src, - rowPitch: 256, - imageHeight: 1 + bytesPerRow: 256 }, { texture: mid, mipLevel: 0, @@ -74,8 +73,7 @@ g.test('b2t2b', async t => { } }, { buffer: dst, - rowPitch: 256, - imageHeight: 1 + bytesPerRow: 256 }, { width: 1, height: 1, @@ -110,8 +108,7 @@ g.test('b2t2t2b', async t => { const encoder = t.device.createCommandEncoder(); encoder.copyBufferToTexture({ buffer: src, - rowPitch: 256, - imageHeight: 1 + bytesPerRow: 256 }, { texture: mid1, mipLevel: 0, @@ -156,8 +153,7 @@ g.test('b2t2t2b', async t => { } }, { buffer: dst, - rowPitch: 256, - imageHeight: 1 + bytesPerRow: 256 }, { width: 1, height: 1, diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/basic.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/operation/command_buffer/render/basic.spec.js index 46b5c7a27c9..88710e8aa09 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/basic.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/operation/command_buffer/render/basic.spec.js @@ -5,8 +5,8 @@ export const description = ` Basic command buffer rendering tests. `; -import { TestGroup } from '../../../../framework/index.js'; -import { GPUTest } from '../../gpu_test.js'; +import { TestGroup } from '../../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../../gpu_test.js'; export const g = new TestGroup(GPUTest); g.test('clear', async t => { const dst = t.device.createBuffer({ @@ -47,8 +47,7 @@ g.test('clear', async t => { } }, { buffer: dst, - rowPitch: 256, - imageHeight: 1 + bytesPerRow: 256 }, { width: 1, height: 1, diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/fences.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/operation/fences.spec.js index af6482fcab5..386530e0852 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/fences.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/operation/fences.spec.js @@ -3,9 +3,10 @@ **/ export const description = ``; -import { attemptGarbageCollection } from '../../framework/collect_garbage.js'; -import { TestGroup, raceWithRejectOnTimeout } from '../../framework/index.js'; -import { GPUTest } from './gpu_test.js'; +import { attemptGarbageCollection } from '../../../common/framework/collect_garbage.js'; +import { TestGroup } from '../../../common/framework/test_group.js'; +import { raceWithRejectOnTimeout } from '../../../common/framework/util/util.js'; +import { GPUTest } from '../../gpu_test.js'; export const g = new TestGroup(GPUTest); g.test('initial/no descriptor', t => { const fence = t.queue.createFence(); diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createBindGroup.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/createBindGroup.spec.js index 2f42a8b643d..97683cf75a9 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createBindGroup.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/createBindGroup.spec.js @@ -5,8 +5,11 @@ export const description = ` createBindGroup validation tests. `; -import { C, TestGroup, pcombine, poptions, unreachable } from '../../../framework/index.js'; -import { kBindingTypes } from '../capability_info.js'; +import * as C from '../../../common/constants.js'; +import { pcombine, poptions } from '../../../common/framework/params.js'; +import { TestGroup } from '../../../common/framework/test_group.js'; +import { unreachable } from '../../../common/framework/util/util.js'; +import { kBindingTypes } from '../../capability_info.js'; import { BindingResourceType, ValidationTest, resourceBindingMatches } from './validation_test.js'; function clone(descriptor) { @@ -16,14 +19,14 @@ function clone(descriptor) { export const g = new TestGroup(ValidationTest); g.test('binding count mismatch', async t => { const bindGroupLayout = t.device.createBindGroupLayout({ - bindings: [{ + entries: [{ binding: 0, visibility: GPUShaderStage.COMPUTE, type: 'storage-buffer' }] }); const goodDescriptor = { - bindings: [{ + entries: [{ binding: 0, resource: { buffer: t.getStorageBuffer() @@ -35,7 +38,7 @@ g.test('binding count mismatch', async t => { t.device.createBindGroup(goodDescriptor); // Another binding is not expected. const badDescriptor = { - bindings: [{ + entries: [{ binding: 0, resource: { buffer: t.getStorageBuffer() @@ -55,14 +58,14 @@ g.test('binding count mismatch', async t => { }); g.test('binding must be present in layout', async t => { const bindGroupLayout = t.device.createBindGroupLayout({ - bindings: [{ + entries: [{ binding: 0, visibility: GPUShaderStage.COMPUTE, type: 'storage-buffer' }] }); const goodDescriptor = { - bindings: [{ + entries: [{ binding: 0, resource: { buffer: t.getStorageBuffer() @@ -74,7 +77,7 @@ g.test('binding must be present in layout', async t => { t.device.createBindGroup(goodDescriptor); // Binding index 0 must be present. const badDescriptor = { - bindings: [{ + entries: [{ binding: 1, resource: { buffer: t.getStorageBuffer() @@ -90,7 +93,7 @@ g.test('buffer binding must contain exactly one buffer of its type', t => { const bindingType = t.params.bindingType; const resourceType = t.params.resourceType; const layout = t.device.createBindGroupLayout({ - bindings: [{ + entries: [{ binding: 0, visibility: GPUShaderStage.COMPUTE, type: bindingType @@ -101,7 +104,7 @@ g.test('buffer binding must contain exactly one buffer of its type', t => { t.expectValidationError(() => { t.device.createBindGroup({ layout, - bindings: [{ + entries: [{ binding: 0, resource }] @@ -112,7 +115,7 @@ g.test('texture binding must have correct usage', async t => { const type = t.params.type; const usage = t.params._usage; const bindGroupLayout = t.device.createBindGroupLayout({ - bindings: [{ + entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, type @@ -129,7 +132,7 @@ g.test('texture binding must have correct usage', async t => { }; // Control case t.device.createBindGroup({ - bindings: [{ + entries: [{ binding: 0, resource: t.device.createTexture(goodDescriptor).createView() }], @@ -144,7 +147,7 @@ g.test('texture binding must have correct usage', async t => { yield GPUTextureUsage.SAMPLED; } - if (type !== 'storage-texture') { + if (type !== 'readonly-storage-texture' && type !== 'writeonly-storage-texture') { yield GPUTextureUsage.STORAGE; } @@ -157,7 +160,7 @@ g.test('texture binding must have correct usage', async t => { badDescriptor.usage = mismatchedTextureUsage; t.expectValidationError(() => { t.device.createBindGroup({ - bindings: [{ + entries: [{ binding: 0, resource: t.device.createTexture(badDescriptor).createView() }], @@ -177,7 +180,7 @@ g.test('texture must have correct component type', async t => { textureComponentType } = t.params; const bindGroupLayout = t.device.createBindGroupLayout({ - bindings: [{ + entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, type: 'sampled-texture', @@ -208,7 +211,7 @@ g.test('texture must have correct component type', async t => { }; // Control case t.device.createBindGroup({ - bindings: [{ + entries: [{ binding: 0, resource: t.device.createTexture(goodDescriptor).createView() }], @@ -235,7 +238,7 @@ g.test('texture must have correct component type', async t => { badDescriptor.format = mismatchedTextureFormat; t.expectValidationError(() => { t.device.createBindGroup({ - bindings: [{ + entries: [{ binding: 0, resource: t.device.createTexture(badDescriptor).createView() }], @@ -247,11 +250,11 @@ g.test('texture must have correct component type', async t => { g.test('texture must have correct dimension', async t => { const bindGroupLayout = t.device.createBindGroupLayout({ - bindings: [{ + entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, type: 'sampled-texture', - textureDimension: '2d' + viewDimension: '2d' }] }); const goodDescriptor = { @@ -260,13 +263,12 @@ g.test('texture must have correct dimension', async t => { height: 16, depth: 1 }, - arrayLayerCount: 1, format: C.TextureFormat.RGBA8Unorm, usage: GPUTextureUsage.SAMPLED }; // Control case t.device.createBindGroup({ - bindings: [{ + entries: [{ binding: 0, resource: t.device.createTexture(goodDescriptor).createView() }], @@ -274,10 +276,10 @@ g.test('texture must have correct dimension', async t => { }); // Mismatched texture binding formats are not valid. const badDescriptor = clone(goodDescriptor); - badDescriptor.arrayLayerCount = 2; + badDescriptor.size.depth = 2; t.expectValidationError(() => { t.device.createBindGroup({ - bindings: [{ + entries: [{ binding: 0, resource: t.device.createTexture(badDescriptor).createView() }], @@ -292,7 +294,7 @@ g.test('buffer offset and size for bind groups match', async t => { _success } = t.params; const bindGroupLayout = t.device.createBindGroupLayout({ - bindings: [{ + entries: [{ binding: 0, visibility: GPUShaderStage.COMPUTE, type: 'storage-buffer' @@ -303,7 +305,7 @@ g.test('buffer offset and size for bind groups match', async t => { usage: GPUBufferUsage.STORAGE }); const descriptor = { - bindings: [{ + entries: [{ binding: 0, resource: { buffer, @@ -333,7 +335,41 @@ g.test('buffer offset and size for bind groups match', async t => { size: 256, _success: true }, // offset 256 (aligned) is valid -// unaligned buffer offset is invalid +// Touching the end of the buffer +{ + offset: 0, + size: 1024, + _success: true +}, { + offset: 0, + size: undefined, + _success: true +}, { + offset: 256 * 3, + size: 256, + _success: true +}, { + offset: 256 * 3, + size: undefined, + _success: true +}, // Zero-sized bindings +{ + offset: 0, + size: 0, + _success: true +}, { + offset: 256, + size: 0, + _success: true +}, { + offset: 1024, + size: 0, + _success: true +}, { + offset: 1024, + size: undefined, + _success: true +}, // Unaligned buffer offset is invalid { offset: 1, size: 256, @@ -350,31 +386,7 @@ g.test('buffer offset and size for bind groups match', async t => { offset: 255, size: 256, _success: false -}, { - offset: 0, - size: 256, - _success: true -}, // touching the start of the buffer works -{ - offset: 256 * 3, - size: 256, - _success: true -}, // touching the end of the buffer works -{ - offset: 1024, - size: 0, - _success: true -}, // touching the end of the buffer works -{ - offset: 0, - size: 1024, - _success: true -}, // touching the full buffer works -{ - offset: 0, - size: undefined, - _success: true -}, // touching the full buffer works +}, // Out-of-bounds { offset: 256 * 5, size: 0, diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createBindGroupLayout.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/createBindGroupLayout.spec.js index b48db9598dd..b03e0159113 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createBindGroupLayout.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/createBindGroupLayout.spec.js @@ -5,8 +5,10 @@ export const description = ` createBindGroupLayout validation tests. `; -import { C, TestGroup, poptions } from '../../../framework/index.js'; -import { kBindingTypeInfo, kBindingTypes, kMaxBindingsPerBindGroup, kPerStageBindingLimits, kShaderStages } from '../capability_info.js'; +import * as C from '../../../common/constants.js'; +import { poptions } from '../../../common/framework/params.js'; +import { TestGroup } from '../../../common/framework/test_group.js'; +import { kBindingTypeInfo, kBindingTypes, kMaxBindingsPerBindGroup, kPerStageBindingLimits, kShaderStages } from '../../capability_info.js'; import { ValidationTest } from './validation_test.js'; function clone(descriptor) { @@ -16,7 +18,7 @@ function clone(descriptor) { export const g = new TestGroup(ValidationTest); g.test('some binding index was specified more than once', async t => { const goodDescriptor = { - bindings: [{ + entries: [{ binding: 0, visibility: GPUShaderStage.COMPUTE, type: C.BindingType.StorageBuffer @@ -29,7 +31,7 @@ g.test('some binding index was specified more than once', async t => { t.device.createBindGroupLayout(goodDescriptor); const badDescriptor = clone(goodDescriptor); - badDescriptor.bindings[1].binding = 0; // Binding index 0 can't be specified twice. + badDescriptor.entries[1].binding = 0; // Binding index 0 can't be specified twice. t.expectValidationError(() => { t.device.createBindGroupLayout(badDescriptor); @@ -37,7 +39,7 @@ g.test('some binding index was specified more than once', async t => { }); g.test('Visibility of bindings can be 0', async t => { t.device.createBindGroupLayout({ - bindings: [{ + entries: [{ binding: 0, visibility: 0, type: 'storage-buffer' @@ -61,7 +63,7 @@ g.test('number of dynamic buffers exceeds the maximum value', async t => { } const goodDescriptor = { - bindings: [...maxDynamicBufferBindings, { + entries: [...maxDynamicBufferBindings, { binding: maxDynamicBufferBindings.length, visibility: GPUShaderStage.COMPUTE, type, @@ -72,7 +74,7 @@ g.test('number of dynamic buffers exceeds the maximum value', async t => { t.device.createBindGroupLayout(goodDescriptor); // Dynamic buffers exceed maximum in a bind group layout. const badDescriptor = clone(goodDescriptor); - badDescriptor.bindings[maxDynamicBufferCount].hasDynamicOffset = true; + badDescriptor.entries[maxDynamicBufferCount].hasDynamicOffset = true; t.expectValidationError(() => { t.device.createBindGroupLayout(badDescriptor); }); @@ -87,7 +89,7 @@ g.test('dynamic set to true is allowed only for buffers', async t => { const type = t.params.type; const success = kBindingTypeInfo[type].type === 'buffer'; const descriptor = { - bindings: [{ + entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, type, @@ -107,18 +109,17 @@ let kCasesForMaxResourcesPerStageTests; // - If extraTypeSame, any of the binding types which counts toward the same limit as |type|. // (i.e. 'storage-buffer' <-> 'readonly-storage-buffer'). // - Otherwise, an arbitrary other type. - function pickExtraBindingTypes(type, extraTypeSame) { - if (extraTypeSame) { - switch (type) { - case 'storage-buffer': - case 'readonly-storage-buffer': - return ['storage-buffer', 'readonly-storage-buffer']; + function* pickExtraBindingTypes(bindingType, extraTypeSame) { + const info = kBindingTypeInfo[bindingType]; - default: - return [type]; + if (extraTypeSame) { + for (const extraBindingType of kBindingTypes) { + if (info.perStageLimitType === kBindingTypeInfo[extraBindingType].perStageLimitType) { + yield extraBindingType; + } } } else { - return type === 'sampler' ? ['sampled-texture'] : ['sampler']; + yield info.perStageLimitType === 'sampler' ? 'sampled-texture' : 'sampler'; } } @@ -167,12 +168,12 @@ g.test('max resources per stage/in bind group layout', async t => { } const goodDescriptor = { - bindings: maxResourceBindings + entries: maxResourceBindings }; // Control t.device.createBindGroupLayout(goodDescriptor); const newDescriptor = clone(goodDescriptor); - newDescriptor.bindings.push({ + newDescriptor.entries.push({ binding: maxedCount, visibility: extraVisibility, type: extraType @@ -204,14 +205,14 @@ g.test('max resources per stage/in pipeline layout', async t => { } const goodLayout = t.device.createBindGroupLayout({ - bindings: maxResourceBindings + entries: maxResourceBindings }); // Control t.device.createPipelineLayout({ bindGroupLayouts: [goodLayout] }); const extraLayout = t.device.createBindGroupLayout({ - bindings: [{ + entries: [{ binding: 0, visibility: extraVisibility, type: extraType diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createPipelineLayout.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/createPipelineLayout.spec.js index 0018c24e540..f1582c4478a 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createPipelineLayout.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/createPipelineLayout.spec.js @@ -5,8 +5,9 @@ export const description = ` createPipelineLayout validation tests. `; -import { TestGroup, pbool, pcombine, poptions } from '../../../framework/index.js'; -import { kBindingTypeInfo, kBindingTypes, kShaderStageCombinations } from '../capability_info.js'; +import { pbool, pcombine, poptions } from '../../../common/framework/params.js'; +import { TestGroup } from '../../../common/framework/test_group.js'; +import { kBindingTypeInfo, kBindingTypes, kShaderStageCombinations } from '../../capability_info.js'; import { ValidationTest } from './validation_test.js'; function clone(descriptor) { @@ -32,10 +33,10 @@ g.test('number of dynamic buffers exceeds the maximum value', async t => { } const maxDynamicBufferBindGroupLayout = t.device.createBindGroupLayout({ - bindings: maxDynamicBufferBindings + entries: maxDynamicBufferBindings }); const goodDescriptor = { - bindings: [{ + entries: [{ binding: 0, visibility, type, @@ -49,7 +50,7 @@ g.test('number of dynamic buffers exceeds the maximum value', async t => { t.device.createPipelineLayout(goodPipelineLayoutDescriptor); // Check dynamic buffers exceed maximum in pipeline layout. const badDescriptor = clone(goodDescriptor); - badDescriptor.bindings[0].hasDynamicOffset = true; + badDescriptor.entries[0].hasDynamicOffset = true; const badPipelineLayoutDescriptor = { bindGroupLayouts: [maxDynamicBufferBindGroupLayout, t.device.createBindGroupLayout(badDescriptor)] }; @@ -64,7 +65,7 @@ g.test('visibility and dynamic offsets', t => { const visibility = t.params.visibility; const info = kBindingTypeInfo[type]; const descriptor = { - bindings: [{ + entries: [{ binding: 0, visibility, type, @@ -83,7 +84,7 @@ g.test('visibility and dynamic offsets', t => { pbool('hasDynamicOffset'), poptions('visibility', kShaderStageCombinations))); g.test('number of bind group layouts exceeds the maximum value', async t => { const bindGroupLayoutDescriptor = { - bindings: [] + entries: [] }; // 4 is the maximum number of bind group layouts. const maxBindGroupLayouts = [1, 2, 3, 4].map(() => t.device.createBindGroupLayout(bindGroupLayoutDescriptor)); diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createTexture.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/createTexture.spec.js index a7317a88f5b..ab4c6f866b4 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createTexture.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/createTexture.spec.js @@ -5,8 +5,9 @@ export const description = ` createTexture validation tests. `; -import { TestGroup, poptions } from '../../../framework/index.js'; -import { kTextureFormatInfo, kTextureFormats } from '../capability_info.js'; +import { poptions } from '../../../common/framework/params.js'; +import { TestGroup } from '../../../common/framework/test_group.js'; +import { kTextureFormatInfo, kTextureFormats } from '../../capability_info.js'; import { ValidationTest } from './validation_test.js'; class F extends ValidationTest { @@ -23,9 +24,8 @@ class F extends ValidationTest { size: { width, height, - depth: 1 + depth: arrayLayerCount }, - arrayLayerCount, mipLevelCount, sampleCount, dimension: '2d', diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createView.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/createView.spec.js index a4fe7ac2a93..d23af583874 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createView.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/createView.spec.js @@ -5,7 +5,7 @@ export const description = ` createView validation tests. `; -import { TestGroup } from '../../../framework/index.js'; +import { TestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; const ARRAY_LAYER_COUNT_2D = 6; const MIP_LEVEL_COUNT = 6; @@ -24,9 +24,8 @@ class F extends ValidationTest { size: { width, height, - depth: 1 + depth: arrayLayerCount }, - arrayLayerCount, mipLevelCount, sampleCount, dimension: '2d', diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/error_scope.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/error_scope.spec.js index 6c6cfd73ae0..fd69c4e13c0 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/error_scope.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/error_scope.spec.js @@ -7,21 +7,28 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope export const description = ` error scope validation tests. `; -import { getGPU } from '../../../framework/gpu/implementation.js'; -import { Fixture, TestGroup, raceWithRejectOnTimeout } from '../../../framework/index.js'; +import { Fixture } from '../../../common/framework/fixture.js'; +import { getGPU } from '../../../common/framework/gpu/implementation.js'; +import { TestGroup } from '../../../common/framework/test_group.js'; +import { assert, raceWithRejectOnTimeout } from '../../../common/framework/util/util.js'; class F extends Fixture { constructor(...args) { super(...args); - _defineProperty(this, "device", undefined); + _defineProperty(this, "_device", undefined); + } + + get device() { + assert(this._device !== undefined); + return this._device; } async init() { super.init(); const gpu = getGPU(); const adapter = await gpu.requestAdapter(); - this.device = await adapter.requestDevice(); + this._device = await adapter.requestDevice(); } createErrorBuffer() { diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/fences.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/fences.spec.js index 2bc85261d3d..7747b5e9dc8 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/fences.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/fences.spec.js @@ -5,7 +5,7 @@ export const description = ` fences validation tests. `; -import { TestGroup } from '../../../framework/index.js'; +import { TestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; export const g = new TestGroup(ValidationTest); // TODO: Remove if https://github.com/gpuweb/gpuweb/issues/377 is decided diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/queue_submit.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/queue_submit.spec.js index 410e3c26e82..dbe0bb4d31e 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/queue_submit.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/queue_submit.spec.js @@ -5,7 +5,7 @@ export const description = ` queue submit validation tests. `; -import { TestGroup } from '../../../framework/index.js'; +import { TestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; export const g = new TestGroup(ValidationTest); g.test('submitting with a mapped buffer is disallowed', async t => { diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/render_pass_descriptor.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/render_pass_descriptor.spec.js index 59caf533e6c..7c887a1c0fd 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/render_pass_descriptor.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/render_pass_descriptor.spec.js @@ -5,7 +5,7 @@ export const description = ` render pass descriptor validation tests. `; -import { TestGroup } from '../../../framework/index.js'; +import { TestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; class F extends ValidationTest { @@ -23,10 +23,9 @@ class F extends ValidationTest { size: { width, height, - depth: 1 + depth: arrayLayerCount }, format, - arrayLayerCount, mipLevelCount, sampleCount, usage diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setBindGroup.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/setBindGroup.spec.js index 73ae4ba502e..baf590746c3 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setBindGroup.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/setBindGroup.spec.js @@ -5,7 +5,8 @@ export const description = ` setBindGroup validation tests. `; -import { TestGroup, pcombine, poptions } from '../../../framework/index.js'; +import { pcombine, poptions } from '../../../common/framework/params.js'; +import { TestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; class F extends ValidationTest { @@ -60,11 +61,11 @@ class F extends ValidationTest { export const g = new TestGroup(F); g.test('dynamic offsets passed but not expected/compute pass', async t => { const bindGroupLayout = t.device.createBindGroupLayout({ - bindings: [] + entries: [] }); const bindGroup = t.device.createBindGroup({ layout: bindGroupLayout, - bindings: [] + entries: [] }); const { type @@ -109,7 +110,7 @@ g.test('dynamic offsets match expectations in pass encoder', async t => { const MIN_DYNAMIC_BUFFER_OFFSET_ALIGNMENT = 256; const BINDING_SIZE = 9; const bindGroupLayout = t.device.createBindGroupLayout({ - bindings: [{ + entries: [{ binding: 0, visibility: GPUShaderStage.COMPUTE | GPUShaderStage.FRAGMENT, type: 'uniform-buffer', @@ -131,7 +132,7 @@ g.test('dynamic offsets match expectations in pass encoder', async t => { }); const bindGroup = t.device.createBindGroup({ layout: bindGroupLayout, - bindings: [{ + entries: [{ binding: 0, resource: { buffer: uniformBuffer, diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setBlendColor.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/setBlendColor.spec.js index a04bcd038ee..b8905453ac9 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setBlendColor.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/setBlendColor.spec.js @@ -5,7 +5,7 @@ export const description = ` setBlendColor validation tests. `; -import { TestGroup } from '../../../framework/index.js'; +import { TestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; // TODO: Move beginRenderPass to a Fixture class. class F extends ValidationTest { diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setScissorRect.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/setScissorRect.spec.js index aec75f536a1..e12c90d7cda 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setScissorRect.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/setScissorRect.spec.js @@ -5,7 +5,7 @@ export const description = ` setScissorRect validation tests. `; -import { TestGroup } from '../../../framework/index.js'; +import { TestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; const TEXTURE_WIDTH = 16; const TEXTURE_HEIGHT = 16; // TODO: Move this fixture class to a common file. diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setStencilReference.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/setStencilReference.spec.js index 3db37a4908e..cbd48aeaad5 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setStencilReference.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/setStencilReference.spec.js @@ -5,7 +5,8 @@ export const description = ` setStencilReference validation tests. `; -import { TestGroup, poptions } from '../../../framework/index.js'; +import { poptions } from '../../../common/framework/params.js'; +import { TestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; // TODO: Move this fixture class to a common file. class F extends ValidationTest { diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setViewport.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/setViewport.spec.js index 715a236b18d..9a3009f38ac 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setViewport.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/setViewport.spec.js @@ -5,7 +5,7 @@ export const description = ` setViewport validation tests. `; -import { TestGroup } from '../../../framework/index.js'; +import { TestGroup } from '../../../common/framework/test_group.js'; import { ValidationTest } from './validation_test.js'; const TEXTURE_WIDTH = 16; const TEXTURE_HEIGHT = 16; // TODO: Move this fixture class to a common file. diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/validation_test.js b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/validation_test.js index c275f94a80e..92d8a0699c4 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/validation_test.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/api/validation/validation_test.js @@ -2,8 +2,8 @@ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts **/ -import { unreachable } from '../../../framework/index.js'; -import { GPUTest } from '../gpu_test.js'; +import { unreachable } from '../../../common/framework/util/util.js'; +import { GPUTest } from '../../gpu_test.js'; export let BindingResourceType; (function (BindingResourceType) { @@ -29,7 +29,8 @@ export function resourceBindingMatches(b, r) { case 'sampler': return r === 'sampler'; - case 'storage-texture': + case 'readonly-storage-texture': + case 'writeonly-storage-texture': return r === 'storage-textureview'; case 'uniform-buffer': diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/capability_info.js b/tests/wpt/web-platform-tests/webgpu/webgpu/capability_info.js index 10947ee1367..0e336b979f8 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/capability_info.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/capability_info.js @@ -2,7 +2,7 @@ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts **/ -import { C } from '../../framework/index.js'; // Textures +import * as C from '../common/constants.js'; // Textures export const kTextureFormatInfo = /* prettier-ignore */ @@ -182,7 +182,7 @@ export const kPerStageBindingLimits = 'storage-texture': 4 }; const kStagesAll = C.ShaderStage.Vertex | C.ShaderStage.Fragment | C.ShaderStage.Compute; -const kStagesNonVertex = C.ShaderStage.Fragment | C.ShaderStage.Compute; +const kStagesCompute = C.ShaderStage.Compute; export const kBindingTypeInfo = /* prettier-ignore */ { @@ -194,7 +194,7 @@ export const kBindingTypeInfo = }, 'storage-buffer': { type: 'buffer', - validStages: kStagesNonVertex, + validStages: kStagesCompute, perStageLimitType: 'storage-buffer', maxDynamicCount: 4 }, @@ -210,13 +210,25 @@ export const kBindingTypeInfo = perStageLimitType: 'sampler', maxDynamicCount: 0 }, + 'comparison-sampler': { + type: 'sampler', + validStages: kStagesAll, + perStageLimitType: 'sampler', + maxDynamicCount: 0 + }, 'sampled-texture': { type: 'texture', validStages: kStagesAll, perStageLimitType: 'sampled-texture', maxDynamicCount: 0 }, - 'storage-texture': { + 'writeonly-storage-texture': { + type: 'texture', + validStages: kStagesCompute, + perStageLimitType: 'storage-texture', + maxDynamicCount: 0 + }, + 'readonly-storage-texture': { type: 'texture', validStages: kStagesAll, perStageLimitType: 'storage-texture', diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/examples.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/examples.spec.js index e57de1bfc8d..add23f7250e 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/examples.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/examples.spec.js @@ -7,18 +7,18 @@ Examples of writing CTS tests with various features. Start here when looking for examples of basic framework usage. `; -import { TestGroup } from '../../framework/index.js'; +import { TestGroup } from '../common/framework/test_group.js'; import { GPUTest } from './gpu_test.js'; // To run these tests in the standalone runner, run `grunt build` or `grunt pre` then open: -// - http://localhost:8080/?runnow=1&q=cts:examples: +// - http://localhost:8080/?runnow=1&q=webgpu:examples: // To run in WPT, copy/symlink the out-wpt/ directory as the webgpu/ directory in WPT, then open: -// - (wpt server url)/webgpu/cts.html?q=cts:examples: +// - (wpt server url)/webgpu/cts.html?q=webgpu:examples: // // Tests here can be run individually or in groups: -// - ?q=cts:examples:basic/async= -// - ?q=cts:examples:basic/ -// - ?q=cts:examples: +// - ?q=webgpu:examples:basic/async= +// - ?q=webgpu:examples:basic/ +// - ?q=webgpu:examples: -export const g = new TestGroup(GPUTest); // Note: spaces in test names are replaced with underscores: cts:examples:test_name= +export const g = new TestGroup(GPUTest); // Note: spaces in test names are replaced with underscores: webgpu:examples:test_name= g.test('test name', t => {}); g.test('basic', t => { @@ -47,8 +47,8 @@ g.test('basic/async', async t => { // They can also be private by starting with an underscore (_result), which passes // them into the test but does not make them part of the case name: // -// - cts:examples:basic/params={"x":2,"y":4} runs with t.params = {x: 2, y: 5, _result: 6}. -// - cts:examples:basic/params={"x":-10,"y":18} runs with t.params = {x: -10, y: 18, _result: 8}. +// - webgpu:examples:basic/params={"x":2,"y":4} runs with t.params = {x: 2, y: 5, _result: 6}. +// - webgpu:examples:basic/params={"x":-10,"y":18} runs with t.params = {x: -10, y: 18, _result: 8}. g.test('basic/params', t => { t.expect(t.params.x + t.params.y === t.params._result); diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/gpu_test.js b/tests/wpt/web-platform-tests/webgpu/webgpu/gpu_test.js index 7ab5320d6e9..0202f34fcf7 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/gpu_test.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/gpu_test.js @@ -4,9 +4,9 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } -import { getGPU } from '../../framework/gpu/implementation.js'; -import { Fixture, assert, unreachable } from '../../framework/index.js'; -let glslangInstance; +import { Fixture } from '../common/framework/fixture.js'; +import { getGPU } from '../common/framework/gpu/implementation.js'; +import { assert, unreachable } from '../common/framework/util/util.js'; class DevicePool { constructor() { @@ -53,36 +53,42 @@ export class GPUTest extends Fixture { constructor(...args) { super(...args); - _defineProperty(this, "device", undefined); - - _defineProperty(this, "queue", undefined); + _defineProperty(this, "objects", undefined); _defineProperty(this, "initialized", false); + } + + get device() { + assert(this.objects !== undefined); + return this.objects.device; + } - _defineProperty(this, "supportsSPIRV", true); + get queue() { + assert(this.objects !== undefined); + return this.objects.queue; } async init() { await super.init(); - this.device = await devicePool.acquire(); - this.queue = this.device.defaultQueue; - const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); - - if (isSafari) { - this.supportsSPIRV = false; - } + const device = await devicePool.acquire(); + const queue = device.defaultQueue; + this.objects = { + device, + queue + }; try { - await this.device.popErrorScope(); + await device.popErrorScope(); unreachable('There was an error scope on the stack at the beginning of the test'); } catch (ex) {} - this.device.pushErrorScope('out-of-memory'); - this.device.pushErrorScope('validation'); + device.pushErrorScope('out-of-memory'); + device.pushErrorScope('validation'); this.initialized = true; } async finalize() { + // Note: finalize is called even if init was unsuccessful. await super.finalize(); if (this.initialized) { @@ -101,45 +107,9 @@ export class GPUTest extends Fixture { } } - if (this.device) { - devicePool.release(this.device); - } - } - - async initGLSL() { - if (!glslangInstance) { - const glslangPath = '../../glslang.js'; - let glslangModule; - - try { - glslangModule = (await import(glslangPath)).default; - } catch (ex) { - this.skip('glslang is not available'); - } - - await new Promise(resolve => { - glslangModule().then(glslang => { - glslangInstance = glslang; - resolve(); - }); - }); - } - } - - createShaderModule(desc) { - if (!this.supportsSPIRV) { - this.skip('SPIR-V not available'); + if (this.objects) { + devicePool.release(this.objects.device); } - - return this.device.createShaderModule(desc); - } - - makeShaderModuleFromGLSL(stage, glsl) { - assert(glslangInstance !== undefined, 'GLSL compiler is not instantiated. Run `await t.initGLSL()` first'); - const code = glslangInstance.compileGLSL(glsl, stage, false); - return this.device.createShaderModule({ - code - }); } createCopyForMapRead(src, size) { diff --git a/tests/wpt/web-platform-tests/webgpu/webgpu/listing.js b/tests/wpt/web-platform-tests/webgpu/webgpu/listing.js new file mode 100644 index 00000000000..5b9ef1afb01 --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/listing.js @@ -0,0 +1,152 @@ +// AUTO-GENERATED - DO NOT EDIT. See src/common/tools/gen_listings.ts. + +export const listing = [ + { + "path": "", + "description": "WebGPU conformance test suite." + }, + { + "path": "api/", + "description": "Tests for full coverage of the Javascript API surface of WebGPU." + }, + { + "path": "api/operation/", + "description": "Tests that check the result of performing valid WebGPU operations, taking advantage of\nparameterization to exercise interactions between features." + }, + { + "path": "api/operation/buffers/", + "description": "GPUBuffer tests." + }, + { + "path": "api/operation/buffers/create_mapped", + "description": "" + }, + { + "path": "api/operation/buffers/map", + "description": "" + }, + { + "path": "api/operation/buffers/map_detach", + "description": "" + }, + { + "path": "api/operation/buffers/map_oom", + "description": "" + }, + { + "path": "api/operation/command_buffer/basic", + "description": "Basic tests." + }, + { + "path": "api/operation/command_buffer/copies", + "description": "copy{Buffer,Texture}To{Buffer,Texture} tests." + }, + { + "path": "api/operation/command_buffer/render/basic", + "description": "Basic command buffer rendering tests." + }, + { + "path": "api/operation/fences", + "description": "" + }, + { + "path": "api/regression/", + "description": "One-off tests that reproduce API bugs found in implementations to prevent the bugs from\nappearing again." + }, + { + "path": "api/validation/", + "description": "Positive and negative tests for all the validation rules of the API." + }, + { + "path": "api/validation/createBindGroup", + "description": "createBindGroup validation tests." + }, + { + "path": "api/validation/createBindGroupLayout", + "description": "createBindGroupLayout validation tests." + }, + { + "path": "api/validation/createPipelineLayout", + "description": "createPipelineLayout validation tests." + }, + { + "path": "api/validation/createTexture", + "description": "createTexture validation tests." + }, + { + "path": "api/validation/createView", + "description": "createView validation tests." + }, + { + "path": "api/validation/error_scope", + "description": "error scope validation tests." + }, + { + "path": "api/validation/fences", + "description": "fences validation tests." + }, + { + "path": "api/validation/queue_submit", + "description": "queue submit validation tests." + }, + { + "path": "api/validation/render_pass_descriptor", + "description": "render pass descriptor validation tests." + }, + { + "path": "api/validation/setBindGroup", + "description": "setBindGroup validation tests." + }, + { + "path": "api/validation/setBlendColor", + "description": "setBlendColor validation tests." + }, + { + "path": "api/validation/setScissorRect", + "description": "setScissorRect validation tests." + }, + { + "path": "api/validation/setStencilReference", + "description": "setStencilReference validation tests." + }, + { + "path": "api/validation/setViewport", + "description": "setViewport validation tests." + }, + { + "path": "examples", + "description": "Examples of writing CTS tests with various features.\n\nStart here when looking for examples of basic framework usage." + }, + { + "path": "idl/", + "description": "Tests to check that the WebGPU IDL is correctly implemented, for examples that objects exposed\nexactly the correct members, and that methods throw when passed incomplete dictionaries." + }, + { + "path": "shader/", + "description": "Tests for full coverage of the shaders that can be passed to WebGPU." + }, + { + "path": "shader/execution/", + "description": "Tests that check the result of valid shader execution." + }, + { + "path": "shader/regression/", + "description": "One-off tests that reproduce shader bugs found in implementations to prevent the bugs from\nappearing again." + }, + { + "path": "shader/validation/", + "description": "Positive and negative tests for all the validation rules of the shading language." + }, + { + "path": "web-platform/", + "description": "Tests for Web platform-specific interactions like GPUSwapChain and canvas, WebXR,\nImageBitmaps, and video APIs." + }, + { + "path": "web-platform/canvas/context_creation", + "description": "" + }, + { + "path": "web-platform/copyImageBitmapToTexture", + "description": "copy imageBitmap To texture tests." + } +]; diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/canvas/context_creation.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/web-platform/canvas/context_creation.spec.js index a693b002769..fd8593b642e 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/canvas/context_creation.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/web-platform/canvas/context_creation.spec.js @@ -3,7 +3,8 @@ **/ export const description = ``; -import { Fixture, TestGroup } from '../../../framework/index.js'; +import { Fixture } from '../../../common/framework/fixture.js'; +import { TestGroup } from '../../../common/framework/test_group.js'; export const g = new TestGroup(Fixture); g.test('canvas element getContext returns GPUCanvasContext', async t => { if (typeof document === 'undefined') { diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/copyImageBitmapToTexture.spec.js b/tests/wpt/web-platform-tests/webgpu/webgpu/web-platform/copyImageBitmapToTexture.spec.js index 42ad8507ec9..5e84113b95a 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/copyImageBitmapToTexture.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/webgpu/web-platform/copyImageBitmapToTexture.spec.js @@ -5,8 +5,9 @@ export const description = ` copy imageBitmap To texture tests. `; -import { TestGroup, pcombine, poptions } from '../../framework/index.js'; -import { GPUTest } from './gpu_test.js'; +import { pcombine, poptions } from '../../common/framework/params.js'; +import { TestGroup } from '../../common/framework/test_group.js'; +import { GPUTest } from '../gpu_test.js'; function calculateRowPitch(width, bytesPerPixel) { const bytesPerRow = width * bytesPerPixel; // Rounds up to a multiple of 256 according to WebGPU requirements. @@ -66,9 +67,9 @@ class F extends GPUTest { this.device.defaultQueue.copyImageBitmapToTexture(imageBitmapCopyView, dstTextureCopyView, copySize); const imageBitmap = imageBitmapCopyView.imageBitmap; const dstTexture = dstTextureCopyView.texture; - const rowPitchValue = calculateRowPitch(imageBitmap.width, bytesPerPixel); + const bytesPerRow = calculateRowPitch(imageBitmap.width, bytesPerPixel); const testBuffer = this.device.createBuffer({ - size: rowPitchValue * imageBitmap.height, + size: bytesPerRow * imageBitmap.height, usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST }); const encoder = this.device.createCommandEncoder(); @@ -82,8 +83,7 @@ class F extends GPUTest { } }, { buffer: testBuffer, - rowPitch: rowPitchValue, - imageHeight: 0 + bytesPerRow }, { width: imageBitmap.width, height: imageBitmap.height, @@ -100,7 +100,7 @@ g.test('from ImageData', async t => { const { width, height - } = t.params; // The texture format is rgba8uint, so the bytes per pixel is 4. + } = t.params; // The texture format is rgba8unorm, so the bytes per pixel is 4. const bytesPerPixel = 4; const imagePixels = new Uint8ClampedArray(bytesPerPixel * width * height); @@ -163,7 +163,7 @@ g.test('from canvas', async t => { if (imageCanvasContext === null) { t.skip('OffscreenCanvas "2d" context not available'); return; - } // The texture format is rgba8uint, so the bytes per pixel is 4. + } // The texture format is rgba8unorm, so the bytes per pixel is 4. const bytesPerPixel = 4; // Generate original data. diff --git a/tests/wpt/web-platform-tests/webxr/resources/webxr_test_constants.js b/tests/wpt/web-platform-tests/webxr/resources/webxr_test_constants.js index d92da3d8f34..959859cba21 100644 --- a/tests/wpt/web-platform-tests/webxr/resources/webxr_test_constants.js +++ b/tests/wpt/web-platform-tests/webxr/resources/webxr_test_constants.js @@ -128,6 +128,7 @@ const ALL_FEATURES = [ 'unbounded', 'hit-test', 'dom-overlay', + 'light-estimation', ]; const TRACKED_IMMERSIVE_DEVICE = { diff --git a/tests/wpt/web-platform-tests/workers/modules/shared-worker-parse-error-failure.html b/tests/wpt/web-platform-tests/workers/modules/shared-worker-parse-error-failure.html index 0d8e390382f..8f63d5f37aa 100644 --- a/tests/wpt/web-platform-tests/workers/modules/shared-worker-parse-error-failure.html +++ b/tests/wpt/web-platform-tests/workers/modules/shared-worker-parse-error-failure.html @@ -22,7 +22,7 @@ promise_setup(async () => { }; worker.onerror = () => resolve(false); }); - assert_precondition( + assert_implements( supportsModuleWorkers, "Static import must be supported on module shared worker to run this test." ); |