From 003ddfc9454a7761fb66aaf0a37640218906e27c Mon Sep 17 00:00:00 2001 From: CYBAI Date: Wed, 29 Nov 2017 00:17:45 +0800 Subject: [PATCH] style: Move grid-template-areas outside of mako --- components/style/properties/gecko.mako.rs | 6 +- .../properties/longhand/position.mako.rs | 186 +----------------- .../properties/shorthand/position.mako.rs | 2 +- components/style/values/computed/mod.rs | 2 +- components/style/values/computed/position.rs | 2 +- components/style/values/specified/mod.rs | 2 +- components/style/values/specified/position.rs | 180 +++++++++++++++++ 7 files changed, 195 insertions(+), 185 deletions(-) diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index f4bdd136f61..85e8c9b48c5 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -2252,7 +2252,7 @@ fn static_assert() { ${impl_simple_type_with_conversion("grid_auto_flow")} - pub fn set_grid_template_areas(&mut self, v: longhands::grid_template_areas::computed_value::T) { + pub fn set_grid_template_areas(&mut self, v: values::computed::position::GridTemplateAreas) { use gecko_bindings::bindings::Gecko_NewGridTemplateAreasValue; use gecko_bindings::sugar::refptr::UniqueRefPtr; @@ -2292,10 +2292,10 @@ fn static_assert() { self.copy_grid_template_areas_from(other) } - pub fn clone_grid_template_areas(&self) -> longhands::grid_template_areas::computed_value::T { - use properties::longhands::grid_template_areas::{NamedArea, TemplateAreas}; + pub fn clone_grid_template_areas(&self) -> values::computed::position::GridTemplateAreas { use std::ops::Range; use values::None_; + use values::specified::position::{NamedArea, TemplateAreas}; if self.gecko.mGridTemplateAreas.mRawPtr.is_null() { return Either::Second(None_); diff --git a/components/style/properties/longhand/position.mako.rs b/components/style/properties/longhand/position.mako.rs index 00a8fd56ce3..3692ddb0ac0 100644 --- a/components/style/properties/longhand/position.mako.rs +++ b/components/style/properties/longhand/position.mako.rs @@ -301,181 +301,11 @@ ${helpers.predefined_type("grid-auto-flow", gecko_pref="layout.css.grid.enabled", spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-flow")} -<%helpers:longhand name="grid-template-areas" - spec="https://drafts.csswg.org/css-grid/#propdef-grid-template-areas" - products="gecko" - animation_value_type="discrete" - gecko_pref="layout.css.grid.enabled" - boxed="True"> - use hash::FnvHashMap; - use std::fmt; - use std::ops::Range; - use str::HTML_SPACE_CHARACTERS; - use style_traits::ToCss; - - pub mod computed_value { - pub use super::SpecifiedValue as T; - } - - pub type SpecifiedValue = Either; - - #[inline] - pub fn get_initial_value() -> computed_value::T { - Either::Second(None_) - } - - pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) - -> Result> { - SpecifiedValue::parse(context, input) - } - - #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] - #[derive(Clone, Debug, PartialEq)] - pub struct TemplateAreas { - pub areas: Box<[NamedArea]>, - pub strings: Box<[Box]>, - pub width: u32, - } - - #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] - #[derive(Clone, Debug, PartialEq)] - pub struct NamedArea { - pub name: Box, - pub rows: Range, - pub columns: Range, - } - - trivial_to_computed_value!(TemplateAreas); - - impl Parse for TemplateAreas { - fn parse<'i, 't>( - _context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - let mut strings = vec![]; - while let Ok(string) = input.try(|i| i.expect_string().map(|s| s.as_ref().into())) { - strings.push(string); - } - - TemplateAreas::from_vec(strings) - .map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) - } - } - - impl TemplateAreas { - pub fn from_vec(strings: Vec>) -> Result { - if strings.is_empty() { - return Err(()); - } - let mut areas: Vec = vec![]; - let mut width = 0; - { - let mut row = 0u32; - let mut area_indices = FnvHashMap::<(&str), usize>::default(); - for string in &strings { - let mut current_area_index: Option = None; - row += 1; - let mut column = 0u32; - for token in Tokenizer(string) { - column += 1; - let token = if let Some(token) = token? { - token - } else { - if let Some(index) = current_area_index.take() { - if areas[index].columns.end != column { - return Err(()); - } - } - continue; - }; - if let Some(index) = current_area_index { - if &*areas[index].name == token { - if areas[index].rows.start == row { - areas[index].columns.end += 1; - } - continue; - } - if areas[index].columns.end != column { - return Err(()); - } - } - if let Some(index) = area_indices.get(token).cloned() { - if areas[index].columns.start != column || areas[index].rows.end != row { - return Err(()); - } - areas[index].rows.end += 1; - current_area_index = Some(index); - continue; - } - let index = areas.len(); - areas.push(NamedArea { - name: token.to_owned().into_boxed_str(), - columns: column..(column + 1), - rows: row..(row + 1), - }); - assert!(area_indices.insert(token, index).is_none()); - current_area_index = Some(index); - } - if let Some(index) = current_area_index { - if areas[index].columns.end != column + 1 { - assert!(areas[index].rows.start != row); - return Err(()); - } - } - if row == 1 { - width = column; - } else if width != column { - return Err(()); - } - } - } - Ok(TemplateAreas { - areas: areas.into_boxed_slice(), - strings: strings.into_boxed_slice(), - width: width, - }) - } - } - - impl ToCss for TemplateAreas { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - for (i, string) in self.strings.iter().enumerate() { - if i != 0 { - dest.write_str(" ")?; - } - string.to_css(dest)?; - } - Ok(()) - } - } - - struct Tokenizer<'a>(&'a str); - - impl<'a> Iterator for Tokenizer<'a> { - type Item = Result, ()>; - - fn next(&mut self) -> Option { - let rest = self.0.trim_left_matches(HTML_SPACE_CHARACTERS); - if rest.is_empty() { - return None; - } - if rest.starts_with('.') { - self.0 = &rest[rest.find(|c| c != '.').unwrap_or(rest.len())..]; - return Some(Ok(None)); - } - if !rest.starts_with(is_name_code_point) { - return Some(Err(())); - } - let token_len = rest.find(|c| !is_name_code_point(c)).unwrap_or(rest.len()); - let token = &rest[..token_len]; - self.0 = &rest[token_len..]; - Some(Ok(Some(token))) - } - } - - fn is_name_code_point(c: char) -> bool { - c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || - c >= '\u{80}' || c == '_' || - c >= '0' && c <= '9' || c == '-' - } - +${helpers.predefined_type("grid-template-areas", + "GridTemplateAreas", + initial_value="computed::GridTemplateAreas::none()", + products="gecko", + animation_value_type="discrete", + gecko_pref="layout.css.grid.enabled", + boxed=True, + spec="https://drafts.csswg.org/css-grid/#propdef-grid-template-areas")} diff --git a/components/style/properties/shorthand/position.mako.rs b/components/style/properties/shorthand/position.mako.rs index bb0900f27f8..36f2db78236 100644 --- a/components/style/properties/shorthand/position.mako.rs +++ b/components/style/properties/shorthand/position.mako.rs @@ -246,12 +246,12 @@ spec="https://drafts.csswg.org/css-grid/#propdef-grid-template" products="gecko"> use parser::Parse; - use properties::longhands::grid_template_areas::TemplateAreas; use values::{Either, None_}; use values::generics::grid::{LineNameList, TrackSize, TrackList, TrackListType}; use values::generics::grid::{TrackListValue, concat_serialize_idents}; use values::specified::{GridTemplateComponent, GenericGridTemplateComponent}; use values::specified::grid::parse_line_names; + use values::specified::position::TemplateAreas; /// Parsing for `` shorthand (also used by `grid` shorthand). pub fn parse_grid_template<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index d792007bf7c..b898884489f 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -54,7 +54,7 @@ pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNone, LengthOrNum pub use self::length::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone, MaxLength, MozLength}; pub use self::length::{CSSPixelLength, NonNegativeLength, NonNegativeLengthOrPercentage}; pub use self::percentage::Percentage; -pub use self::position::{Position, GridAutoFlow}; +pub use self::position::{Position, GridAutoFlow, GridTemplateAreas}; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray, SVGWidth}; pub use self::table::XSpan; pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextOverflow, WordSpacing}; diff --git a/components/style/values/computed/position.rs b/components/style/values/computed/position.rs index 6416104e8e7..ed6a308151f 100644 --- a/components/style/values/computed/position.rs +++ b/components/style/values/computed/position.rs @@ -11,7 +11,7 @@ use std::fmt; use style_traits::ToCss; use values::computed::{LengthOrPercentage, Percentage}; use values::generics::position::Position as GenericPosition; -pub use values::specified::position::GridAutoFlow; +pub use values::specified::position::{GridAutoFlow, GridTemplateAreas}; /// The computed value of a CSS `` pub type Position = GenericPosition; diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index b43e6926a6e..16401f4ddc0 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -50,7 +50,7 @@ pub use self::length::{NoCalcLength, ViewportPercentageLength}; pub use self::length::NonNegativeLengthOrPercentage; pub use self::rect::LengthOrNumberRect; pub use self::percentage::Percentage; -pub use self::position::{Position, PositionComponent, GridAutoFlow}; +pub use self::position::{Position, PositionComponent, GridAutoFlow, GridTemplateAreas}; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray, SVGWidth}; pub use self::table::XSpan; pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextDecorationLine, TextOverflow, WordSpacing}; diff --git a/components/style/values/specified/position.rs b/components/style/values/specified/position.rs index f48923f4f37..15c09e05b0a 100644 --- a/components/style/values/specified/position.rs +++ b/components/style/values/specified/position.rs @@ -8,10 +8,14 @@ //! [position]: https://drafts.csswg.org/css-backgrounds-3/#position use cssparser::Parser; +use hash::FnvHashMap; use parser::{Parse, ParserContext}; use selectors::parser::SelectorParseErrorKind; use std::fmt; +use std::ops::Range; +use str::HTML_SPACE_CHARACTERS; use style_traits::{ToCss, StyleParseErrorKind, ParseError}; +use values::{Either, None_}; use values::computed::{CalcLengthOrPercentage, LengthOrPercentage as ComputedLengthOrPercentage}; use values::computed::{Context, Percentage, ToComputedValue}; use values::generics::position::Position as GenericPosition; @@ -486,3 +490,179 @@ impl From for u8 { result } } + +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] +#[derive(Clone, Debug, PartialEq)] +/// https://drafts.csswg.org/css-grid/#named-grid-area +pub struct TemplateAreas { + /// `named area` containing for each template area + pub areas: Box<[NamedArea]>, + /// The original CSS string value of each template area + pub strings: Box<[Box]>, + /// The number of columns of the grid. + pub width: u32, +} + +impl TemplateAreas { + /// Transform `vector` of str into `template area` + pub fn from_vec(strings: Vec>) -> Result { + if strings.is_empty() { + return Err(()); + } + let mut areas: Vec = vec![]; + let mut width = 0; + { + let mut row = 0u32; + let mut area_indices = FnvHashMap::<&str, usize>::default(); + for string in &strings { + let mut current_area_index: Option = None; + row += 1; + let mut column = 0u32; + for token in TemplateAreasTokenizer(string) { + column += 1; + let token = if let Some(token) = token? { + token + } else { + if let Some(index) = current_area_index.take() { + if areas[index].columns.end != column { + return Err(()); + } + } + continue; + }; + if let Some(index) = current_area_index { + if &*areas[index].name == token { + if areas[index].rows.start == row { + areas[index].columns.end += 1; + } + continue; + } + if areas[index].columns.end != column { + return Err(()); + } + } + if let Some(index) = area_indices.get(token).cloned() { + if areas[index].columns.start != column || areas[index].rows.end != row { + return Err(()); + } + areas[index].rows.end += 1; + current_area_index = Some(index); + continue; + } + let index = areas.len(); + areas.push(NamedArea { + name: token.to_owned().into_boxed_str(), + columns: column..(column + 1), + rows: row..(row + 1), + }); + assert!(area_indices.insert(token, index).is_none()); + current_area_index = Some(index); + } + if let Some(index) = current_area_index { + if areas[index].columns.end != column + 1 { + assert_ne!(areas[index].rows.start, row); + return Err(()); + } + } + if row == 1 { + width = column; + } else if width != column { + return Err(()); + } + } + } + Ok(TemplateAreas { + areas: areas.into_boxed_slice(), + strings: strings.into_boxed_slice(), + width: width, + }) + } +} + +impl ToCss for TemplateAreas { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + for (i, string) in self.strings.iter().enumerate() { + if i != 0 { + dest.write_str(" ")?; + } + string.to_css(dest)?; + } + Ok(()) + } +} + +impl Parse for TemplateAreas { + fn parse<'i, 't>( + _context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + let mut strings = vec![]; + while let Ok(string) = input.try(|i| i.expect_string().map(|s| s.as_ref().into())) { + strings.push(string); + } + + TemplateAreas::from_vec(strings) + .map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + } +} + +trivial_to_computed_value!(TemplateAreas); + +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] +#[derive(Clone, Debug, PartialEq)] +/// Not associated with any particular grid item, but can +/// be referenced from the grid-placement properties. +pub struct NamedArea { + /// Name of the `named area` + pub name: Box, + /// Rows of the `named area` + pub rows: Range, + /// Columns of the `named area` + pub columns: Range, +} + +/// Tokenize the string into a list of the tokens, +/// using longest-match semantics +struct TemplateAreasTokenizer<'a>(&'a str); + +impl<'a> Iterator for TemplateAreasTokenizer<'a> { + type Item = Result, ()>; + + fn next(&mut self) -> Option { + let rest = self.0.trim_left_matches(HTML_SPACE_CHARACTERS); + if rest.is_empty() { + return None; + } + if rest.starts_with('.') { + self.0 = &rest[rest.find(|c| c != '.').unwrap_or(rest.len())..]; + return Some(Ok(None)); + } + if !rest.starts_with(is_name_code_point) { + return Some(Err(())); + } + let token_len = rest.find(|c| !is_name_code_point(c)).unwrap_or(rest.len()); + let token = &rest[..token_len]; + self.0 = &rest[token_len..]; + Some(Ok(Some(token))) + } +} + +fn is_name_code_point(c: char) -> bool { + c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || + c >= '\u{80}' || c == '_' || + c >= '0' && c <= '9' || c == '-' +} + +/// This property specifies named grid areas. +/// The syntax of this property also provides a visualization of +/// the structure of the grid, making the overall layout of +/// the grid container easier to understand. +pub type GridTemplateAreas = Either; + +impl GridTemplateAreas { + #[inline] + /// Get default value as `none` + pub fn none() -> GridTemplateAreas { + Either::Second(None_) + } +}