diff --git a/components/style/gecko/generated/bindings.rs b/components/style/gecko/generated/bindings.rs index 8ccd98dd2ccf..92ddd525c9f2 100644 --- a/components/style/gecko/generated/bindings.rs +++ b/components/style/gecko/generated/bindings.rs @@ -1041,6 +1041,11 @@ extern "C" { *mut nsStyleGridTemplate, track_sizes: u32); } +extern "C" { + pub fn Gecko_SetGridTemplateLineNamesLength(grid_template: + *mut nsStyleGridTemplate, + track_sizes: u32); +} extern "C" { pub fn Gecko_CopyStyleGridTemplateValues(grid_template: *mut nsStyleGridTemplate, diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 1a6e0995fe06..f3085cec790d 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -1244,7 +1244,7 @@ fn static_assert() { use std::usize; use values::CustomIdent; use values::generics::grid::TrackListType::Auto; - use values::generics::grid::{RepeatCount, TrackSize}; + use values::generics::grid::{GridTemplateComponent, RepeatCount, TrackSize}; #[inline] fn set_line_names(servo_names: &[CustomIdent], gecko_names: &mut nsTArray) { @@ -1280,10 +1280,11 @@ fn static_assert() { ${self_grid}.mRepeatAutoIndex = -1; ${self_grid}.set_mIsAutoFill(false); ${self_grid}.set_mIsSubgrid(false); - // FIXME: mIsSubgrid is false only for , but we don't support subgrid name lists at the moment. + + let max_lines = nsStyleGridLine_kMaxLine as usize - 1; // for accounting the final match v { - Either::First(track) => { + GridTemplateComponent::TrackList(track) => { let mut auto_idx = usize::MAX; let mut auto_track_size = None; if let Auto(idx) = track.list_type { @@ -1314,7 +1315,6 @@ fn static_assert() { num_values += 1; } - let max_lines = nsStyleGridLine_kMaxLine as usize - 1; // for accounting the final num_values = cmp::min(num_values, max_lines); unsafe { bindings::Gecko_SetStyleGridTemplateArrayLengths(&mut ${self_grid}, num_values as u32); @@ -1341,7 +1341,7 @@ fn static_assert() { let final_names = line_names.next().unwrap(); set_line_names(&final_names, ${self_grid}.mLineNameLists.last_mut().unwrap()); }, - Either::Second(_none) => { + GridTemplateComponent::None => { unsafe { bindings::Gecko_SetStyleGridTemplateArrayLengths(&mut ${self_grid}, 0); bindings::Gecko_ResizeTArrayForStrings( @@ -1350,6 +1350,27 @@ fn static_assert() { &mut ${self_grid}.mRepeatAutoLineNameListAfter, 0); } }, + GridTemplateComponent::Subgrid(list) => { + ${self_grid}.set_mIsSubgrid(true); + let num_values = cmp::min(list.names.len(), max_lines + 1); + unsafe { + bindings::Gecko_SetStyleGridTemplateArrayLengths(&mut ${self_grid}, 0); + bindings::Gecko_SetGridTemplateLineNamesLength(&mut ${self_grid}, num_values as u32); + bindings::Gecko_ResizeTArrayForStrings( + &mut ${self_grid}.mRepeatAutoLineNameListBefore, 0); + bindings::Gecko_ResizeTArrayForStrings( + &mut ${self_grid}.mRepeatAutoLineNameListAfter, 0); + } + + if let Some(idx) = list.fill_idx { + ${self_grid}.set_mIsAutoFill(true); + ${self_grid}.mRepeatAutoIndex = idx as i16; + } + + for (servo_names, gecko_names) in list.names.iter().zip(${self_grid}.mLineNameLists.iter_mut()) { + set_line_names(servo_names, gecko_names); + } + }, } } diff --git a/components/style/properties/longhand/position.mako.rs b/components/style/properties/longhand/position.mako.rs index 609573b44af6..c39a75852153 100644 --- a/components/style/properties/longhand/position.mako.rs +++ b/components/style/properties/longhand/position.mako.rs @@ -276,11 +276,9 @@ ${helpers.predefined_type("object-position", products="gecko", boxed=True)} - // NOTE: The spec lists only `none | | `, but gecko seems to support - // `subgrid ?` in addition to this (probably old spec). We should support it soon. ${helpers.predefined_type("grid-template-%ss" % kind, - "TrackListOrNone", - "Either::Second(None_)", + "GridTemplateComponent", + "specified::GenericGridTemplateComponent::None", products="gecko", spec="https://drafts.csswg.org/css-grid/#propdef-grid-template-%ss" % kind, boxed=True, diff --git a/components/style/properties/shorthand/position.mako.rs b/components/style/properties/shorthand/position.mako.rs index c13a53eb8850..4207a07ca031 100644 --- a/components/style/properties/shorthand/position.mako.rs +++ b/components/style/properties/shorthand/position.mako.rs @@ -245,15 +245,16 @@ use properties::longhands::grid_template_areas::TemplateAreas; use values::{Either, None_}; use values::generics::grid::{TrackSize, TrackList, TrackListType, concat_serialize_idents}; - use values::specified::TrackListOrNone; + use values::specified::{GridTemplateComponent, GenericGridTemplateComponent}; use values::specified::grid::parse_line_names; /// Parsing for `` shorthand (also used by `grid` shorthand). pub fn parse_grid_template<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) - -> Result<(TrackListOrNone, TrackListOrNone, Either), - ParseError<'i>> { + -> Result<(GridTemplateComponent, + GridTemplateComponent, + Either), ParseError<'i>> { if input.try(|i| i.expect_ident_matching("none")).is_ok() { - return Ok((Either::Second(None_), Either::Second(None_), Either::Second(None_))) + return Ok((GenericGridTemplateComponent::None, GenericGridTemplateComponent::None, Either::Second(None_))) } let first_line_names = input.try(parse_line_names).unwrap_or(vec![]); @@ -296,20 +297,23 @@ }; let template_cols = if input.try(|i| i.expect_delim('/')).is_ok() { - let track_list = TrackList::parse(context, input)?; - if track_list.list_type != TrackListType::Explicit { - return Err(StyleParseError::UnspecifiedError.into()) + let value = GridTemplateComponent::parse(context, input)?; + if let GenericGridTemplateComponent::TrackList(ref list) = value { + if list.list_type != TrackListType::Explicit { + return Err(StyleParseError::UnspecifiedError.into()) + } } - Either::First(track_list) + value } else { - Either::Second(None_) + GenericGridTemplateComponent::None }; - Ok((Either::First(template_rows), template_cols, Either::First(template_areas))) + Ok((GenericGridTemplateComponent::TrackList(template_rows), + template_cols, Either::First(template_areas))) } else { let mut template_rows = grid_template_rows::parse(context, input)?; - if let Either::First(ref mut list) = template_rows { + if let GenericGridTemplateComponent::TrackList(ref mut list) = template_rows { list.line_names[0] = first_line_names; // won't panic } @@ -329,14 +333,14 @@ } /// Serialization for `` shorthand (also used by `grid` shorthand). - pub fn serialize_grid_template(template_rows: &TrackListOrNone, - template_columns: &TrackListOrNone, + pub fn serialize_grid_template(template_rows: &GridTemplateComponent, + template_columns: &GridTemplateComponent, template_areas: &Either, dest: &mut W) -> fmt::Result where W: fmt::Write { match *template_areas { Either::Second(_none) => { - if template_rows == &Either::Second(None_) && - template_columns == &Either::Second(None_) { + if template_rows == &GenericGridTemplateComponent::None && + template_columns == &GenericGridTemplateComponent::None { dest.write_str("none") } else { template_rows.to_css(dest)?; @@ -346,8 +350,8 @@ }, Either::First(ref areas) => { let track_list = match *template_rows { - Either::First(ref list) => list, - Either::Second(_none) => unreachable!(), // should exist! + GenericGridTemplateComponent::TrackList(ref list) => list, + _ => unreachable!(), // should exist! }; let mut names_iter = track_list.line_names.iter(); @@ -371,7 +375,7 @@ concat_serialize_idents(" [", "]", names, " ", dest)?; } - if let Either::First(ref list) = *template_columns { + if let GenericGridTemplateComponent::TrackList(ref list) = *template_columns { dest.write_str(" / ")?; list.to_css(dest)?; } @@ -401,12 +405,13 @@ use properties::longhands::{grid_template_columns, grid_template_rows}; use properties::longhands::grid_auto_flow::computed_value::{AutoFlow, T as SpecifiedAutoFlow}; use values::{Either, None_}; + use values::generics::grid::GridTemplateComponent; use values::specified::{LengthOrPercentage, TrackSize}; pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { - let mut temp_rows = Either::Second(None_); - let mut temp_cols = Either::Second(None_); + let mut temp_rows = GridTemplateComponent::None; + let mut temp_cols = GridTemplateComponent::None; let mut temp_areas = Either::Second(None_); let mut auto_rows = TrackSize::default(); let mut auto_cols = TrackSize::default(); diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 4930e25a0508..7a115179e885 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -19,6 +19,7 @@ use std::fmt; use style_traits::ToCss; use super::{CSSFloat, CSSInteger, RGBA}; use super::generics::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize}; +use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent; use super::generics::grid::TrackList as GenericTrackList; use super::specified; @@ -565,8 +566,8 @@ pub type TrackSize = GenericTrackSize; /// (could also be `` or ``) pub type TrackList = GenericTrackList; -/// ` | none` -pub type TrackListOrNone = Either; +/// ` | ` +pub type GridTemplateComponent = GenericGridTemplateComponent; impl ClipRectOrAuto { /// Return an auto (default for clip-rect and image-region) value diff --git a/components/style/values/generics/grid.rs b/components/style/values/generics/grid.rs index 42516cda6b1c..a7b0de061a76 100644 --- a/components/style/values/generics/grid.rs +++ b/components/style/values/generics/grid.rs @@ -650,3 +650,17 @@ impl ToCss for LineNameList { impl ComputedValueAsSpecified for LineNameList {} no_viewport_percentage!(LineNameList); + +/// Variants for ` | ` +/// Subgrid deferred to Level 2 spec due to lack of implementation. +/// But it's implemented in gecko, so we have to as well. +#[derive(Clone, PartialEq, Debug, ToCss)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum GridTemplateComponent { + /// `none` value. + None, + /// The grid `` + TrackList(TrackList), + /// A `subgrid ?` + Subgrid(LineNameList), +} diff --git a/components/style/values/specified/grid.rs b/components/style/values/specified/grid.rs index 436b2d5f1b4c..af2f4a70c226 100644 --- a/components/style/values/specified/grid.rs +++ b/components/style/values/specified/grid.rs @@ -12,8 +12,8 @@ use std::ascii::AsciiExt; use style_traits::{HasViewportPercentage, ParseError, StyleParseError}; use values::{CSSFloat, CustomIdent, Either}; use values::computed::{self, Context, ToComputedValue}; -use values::generics::grid::{RepeatCount, TrackBreadth, TrackKeyword, TrackRepeat}; -use values::generics::grid::{TrackSize, TrackList, TrackListType}; +use values::generics::grid::{GridTemplateComponent, RepeatCount, TrackBreadth, TrackKeyword, TrackRepeat}; +use values::generics::grid::{LineNameList, TrackSize, TrackList, TrackListType}; use values::specified::LengthOrPercentage; /// Parse a single flexible length. @@ -349,3 +349,51 @@ impl ToComputedValue for TrackList { } } } + +impl Parse for GridTemplateComponent { // FIXME: Derive Parse (probably with None_) + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { + if input.try(|i| i.expect_ident_matching("none")).is_ok() { + return Ok(GridTemplateComponent::None) + } + + if let Ok(t) = input.try(|i| TrackList::parse(context, i)) { + return Ok(GridTemplateComponent::TrackList(t)) + } + + LineNameList::parse(context, input).map(GridTemplateComponent::Subgrid) + } +} + +impl HasViewportPercentage for GridTemplateComponent { + #[inline] + fn has_viewport_percentage(&self) -> bool { + match *self { + GridTemplateComponent::TrackList(ref l) => l.has_viewport_percentage(), + _ => false, + } + } +} + +impl ToComputedValue for GridTemplateComponent { + type ComputedValue = GridTemplateComponent>; + + #[inline] + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + match *self { + GridTemplateComponent::None => GridTemplateComponent::None, + GridTemplateComponent::TrackList(ref l) => GridTemplateComponent::TrackList(l.to_computed_value(context)), + GridTemplateComponent::Subgrid(ref n) => GridTemplateComponent::Subgrid(n.to_computed_value(context)), + } + } + + #[inline] + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + match *computed { + GridTemplateComponent::None => GridTemplateComponent::None, + GridTemplateComponent::TrackList(ref l) => + GridTemplateComponent::TrackList(ToComputedValue::from_computed_value(l)), + GridTemplateComponent::Subgrid(ref n) => + GridTemplateComponent::Subgrid(ToComputedValue::from_computed_value(n)), + } + } +} diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index d429376c1f68..c05085d71370 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -48,6 +48,7 @@ pub use self::position::{Position, PositionComponent}; pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing}; pub use self::transform::{TimingFunction, TransformOrigin}; pub use super::generics::grid::GridLine; +pub use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent; #[cfg(feature = "gecko")] pub mod align; @@ -685,8 +686,8 @@ pub type TrackSize = GenericTrackSize; /// (could also be `` or ``) pub type TrackList = GenericTrackList; -/// ` | none` -pub type TrackListOrNone = Either; +/// ` | ` +pub type GridTemplateComponent = GenericGridTemplateComponent; #[derive(Clone, Debug, HasViewportPercentage, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] diff --git a/tests/unit/style/parsing/position.rs b/tests/unit/style/parsing/position.rs index c1527c2f2332..9029e4013554 100644 --- a/tests/unit/style/parsing/position.rs +++ b/tests/unit/style/parsing/position.rs @@ -191,12 +191,18 @@ fn test_grid_template_rows_columns() { // with as assert_roundtrip_with_context!(grid_template_rows::parse, "calc(4em + 5px)"); // with followed by with `{3}` (, auto, minmax) - assert_roundtrip_with_context!(grid_template_rows::parse, "10px repeat(2, 1fr auto minmax(200px, 1fr))"); + assert_roundtrip_with_context!(grid_template_rows::parse, + "10px repeat(2, 1fr auto minmax(200px, 1fr))", + "10px 1fr auto minmax(200px, 1fr) 1fr auto minmax(200px, 1fr)"); // with ` ` followed by - assert_roundtrip_with_context!(grid_template_rows::parse, "repeat(4, 10px [col-start] 250px [col-end]) 10px"); + assert_roundtrip_with_context!(grid_template_rows::parse, + "repeat(2, 10px [col-start] 250px [col-end]) 10px", + "10px [col-start] 250px [col-end] 10px [col-start] 250px [col-end] 10px"); // mixture of , and assert_roundtrip_with_context!(grid_template_rows::parse, - "[a] auto [b] minmax(min-content, 1fr) [b c d] repeat(2, [e] 40px) repeat(5, [f g] auto [h]) [i]"); + "[a] auto [b] minmax(min-content, 1fr) [b c d] repeat(2, 40px [e] 30px) [i]", + "[a] auto [b] minmax(min-content, 1fr) [b c d] 40px [e] 30px 40px [e] 30px [i]"); + assert!(parse(grid_template_rows::parse, "subgrid").is_ok()); // no span allowed in assert!(parse(grid_template_rows::parse, "[a span] 10px").is_err()); @@ -232,4 +238,11 @@ fn test_computed_grid_template_rows_colums() { assert_computed_serialization(grid_template_rows::parse, "10px repeat(2, 1fr auto minmax(200px, 1fr))", "10px minmax(auto, 1fr) auto minmax(200px, 1fr) minmax(auto, 1fr) auto minmax(200px, 1fr)"); + + assert_computed_serialization(grid_template_rows::parse, + "subgrid [a] [] repeat(auto-fill, [])", "subgrid [a] [] repeat(auto-fill, [])"); + + assert_computed_serialization(grid_template_rows::parse, + "subgrid [a] [b] repeat(2, [c d] [] [e]) [] repeat(auto-fill, [])", + "subgrid [a] [b] [c d] [] [e] [c d] [] [e] [] repeat(auto-fill, [])"); }