mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
style: Move grid-template-areas outside of mako
This commit is contained in:
parent
2eb266b314
commit
003ddfc945
7 changed files with 195 additions and 185 deletions
|
@ -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_);
|
||||
|
|
|
@ -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<TemplateAreas, None_>;
|
||||
|
||||
#[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, ParseError<'i>> {
|
||||
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<str>]>,
|
||||
pub width: u32,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct NamedArea {
|
||||
pub name: Box<str>,
|
||||
pub rows: Range<u32>,
|
||||
pub columns: Range<u32>,
|
||||
}
|
||||
|
||||
trivial_to_computed_value!(TemplateAreas);
|
||||
|
||||
impl Parse for TemplateAreas {
|
||||
fn parse<'i, 't>(
|
||||
_context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
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<Box<str>>) -> Result<TemplateAreas, ()> {
|
||||
if strings.is_empty() {
|
||||
return Err(());
|
||||
}
|
||||
let mut areas: Vec<NamedArea> = 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<usize> = 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<W>(&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<Option<(&'a str)>, ()>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
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:longhand>
|
||||
${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")}
|
||||
|
|
|
@ -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 `<grid-template>` shorthand (also used by `grid` shorthand).
|
||||
pub fn parse_grid_template<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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 `<position>`
|
||||
pub type Position = GenericPosition<HorizontalPosition, VerticalPosition>;
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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<GridAutoFlow> 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<str>]>,
|
||||
/// 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<Box<str>>) -> Result<TemplateAreas, ()> {
|
||||
if strings.is_empty() {
|
||||
return Err(());
|
||||
}
|
||||
let mut areas: Vec<NamedArea> = 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<usize> = 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<W>(&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<Self, ParseError<'i>> {
|
||||
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<str>,
|
||||
/// Rows of the `named area`
|
||||
pub rows: Range<u32>,
|
||||
/// Columns of the `named area`
|
||||
pub columns: Range<u32>,
|
||||
}
|
||||
|
||||
/// 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<Option<&'a str>, ()>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
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<TemplateAreas, None_>;
|
||||
|
||||
impl GridTemplateAreas {
|
||||
#[inline]
|
||||
/// Get default value as `none`
|
||||
pub fn none() -> GridTemplateAreas {
|
||||
Either::Second(None_)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue