зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #17021 - Stylo: Wrap up grid (from servo:grid); r=nox
Adds the final piece for grid (`grid-template` and `grid` shorthands), fixes #15307 Source-Repo: https://github.com/servo/servo Source-Revision: 9e7f02ba77f09b1ca6bb090dfb7beebe15c5dc62 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : e76d3649d2a3195a32106f99a05f594c91c00512
This commit is contained in:
Родитель
9c5a5ac364
Коммит
e008ecdf2f
|
@ -223,6 +223,7 @@ ${helpers.predefined_type("object-position",
|
|||
${helpers.predefined_type("grid-%s-gap" % kind,
|
||||
"LengthOrPercentage",
|
||||
"computed::LengthOrPercentage::Length(Au(0))",
|
||||
"parse_non_negative",
|
||||
spec="https://drafts.csswg.org/css-grid/#propdef-grid-%s-gap" % kind,
|
||||
animation_value_type="ComputedValue",
|
||||
products="gecko")}
|
||||
|
@ -396,6 +397,13 @@ ${helpers.predefined_type("object-position",
|
|||
while let Ok(string) = input.try(Parser::expect_string) {
|
||||
strings.push(string.into_owned().into_boxed_str());
|
||||
}
|
||||
|
||||
TemplateAreas::from_vec(strings)
|
||||
}
|
||||
}
|
||||
|
||||
impl TemplateAreas {
|
||||
pub fn from_vec(strings: Vec<Box<str>>) -> Result<TemplateAreas, ()> {
|
||||
if strings.is_empty() {
|
||||
return Err(());
|
||||
}
|
||||
|
|
|
@ -241,6 +241,262 @@
|
|||
}
|
||||
</%helpers:shorthand>
|
||||
|
||||
<%helpers:shorthand name="grid-template"
|
||||
sub_properties="grid-template-rows grid-template-columns grid-template-areas"
|
||||
spec="https://drafts.csswg.org/css-grid/#propdef-grid-template"
|
||||
disable_when_testing="True"
|
||||
products="gecko">
|
||||
use cssparser::serialize_string;
|
||||
use parser::Parse;
|
||||
use properties::longhands::grid_template_rows;
|
||||
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::grid::parse_line_names;
|
||||
|
||||
/// Parsing for `<grid-template>` shorthand (also used by `grid` shorthand).
|
||||
pub fn parse_grid_template(context: &ParserContext, input: &mut Parser)
|
||||
-> Result<(TrackListOrNone, TrackListOrNone, Either<TemplateAreas, None_>), ()> {
|
||||
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
return Ok((Either::Second(None_), Either::Second(None_), Either::Second(None_)))
|
||||
}
|
||||
|
||||
let first_line_names = input.try(parse_line_names).unwrap_or(vec![]);
|
||||
if let Ok(s) = input.try(Parser::expect_string) {
|
||||
let mut strings = vec![];
|
||||
let mut values = vec![];
|
||||
let mut line_names = vec![];
|
||||
let mut names = first_line_names;
|
||||
let mut string = s.into_owned().into_boxed_str();
|
||||
loop {
|
||||
line_names.push(names);
|
||||
strings.push(string);
|
||||
let size = input.try(|i| TrackSize::parse(context, i)).unwrap_or_default();
|
||||
values.push(Either::First(size));
|
||||
names = input.try(parse_line_names).unwrap_or(vec![]);
|
||||
if let Ok(v) = input.try(parse_line_names) {
|
||||
names.extend(v);
|
||||
}
|
||||
|
||||
string = match input.try(Parser::expect_string) {
|
||||
Ok(s) => s.into_owned().into_boxed_str(),
|
||||
_ => { // only the named area determines whether we should bail out
|
||||
line_names.push(names);
|
||||
break
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if line_names.len() == values.len() {
|
||||
line_names.push(vec![]); // should be one longer than track sizes
|
||||
}
|
||||
|
||||
let template_areas = TemplateAreas::from_vec(strings)?;
|
||||
let template_rows = TrackList {
|
||||
list_type: TrackListType::Normal,
|
||||
values: values,
|
||||
line_names: line_names,
|
||||
auto_repeat: None,
|
||||
};
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
Either::First(track_list)
|
||||
} else {
|
||||
Either::Second(None_)
|
||||
};
|
||||
|
||||
Ok((Either::First(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 {
|
||||
list.line_names[0] = first_line_names; // won't panic
|
||||
}
|
||||
|
||||
Ok((template_rows, grid_template_rows::parse(context, input)?, Either::Second(None_)))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
|
||||
let (rows, columns, areas) = parse_grid_template(context, input)?;
|
||||
Ok(expanded! {
|
||||
grid_template_rows: rows,
|
||||
grid_template_columns: columns,
|
||||
grid_template_areas: areas,
|
||||
})
|
||||
}
|
||||
|
||||
/// Serialization for `<grid-template>` shorthand (also used by `grid` shorthand).
|
||||
pub fn serialize_grid_template<W>(template_rows: &TrackListOrNone,
|
||||
template_columns: &TrackListOrNone,
|
||||
template_areas: &Either<TemplateAreas, None_>,
|
||||
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_) {
|
||||
dest.write_str("none")
|
||||
} else {
|
||||
template_rows.to_css(dest)?;
|
||||
dest.write_str(" / ")?;
|
||||
template_columns.to_css(dest)
|
||||
}
|
||||
},
|
||||
Either::First(ref areas) => {
|
||||
let track_list = match *template_rows {
|
||||
Either::First(ref list) => list,
|
||||
Either::Second(_none) => unreachable!(), // should exist!
|
||||
};
|
||||
|
||||
let mut names_iter = track_list.line_names.iter();
|
||||
for (((i, string), names), size) in areas.strings.iter().enumerate()
|
||||
.zip(&mut names_iter)
|
||||
.zip(track_list.values.iter()) {
|
||||
if i > 0 {
|
||||
dest.write_str(" ")?;
|
||||
}
|
||||
|
||||
if !names.is_empty() {
|
||||
concat_serialize_idents("[", "] ", names, " ", dest)?;
|
||||
}
|
||||
|
||||
serialize_string(string, dest)?;
|
||||
dest.write_str(" ")?;
|
||||
size.to_css(dest)?;
|
||||
}
|
||||
|
||||
if let Some(names) = names_iter.next() {
|
||||
concat_serialize_idents(" [", "]", names, " ", dest)?;
|
||||
}
|
||||
|
||||
if let Either::First(ref list) = *template_columns {
|
||||
dest.write_str(" / ")?;
|
||||
list.to_css(dest)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
#[inline]
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
serialize_grid_template(self.grid_template_rows, self.grid_template_columns,
|
||||
self.grid_template_areas, dest)
|
||||
}
|
||||
}
|
||||
</%helpers:shorthand>
|
||||
|
||||
<%helpers:shorthand name="grid"
|
||||
sub_properties="grid-template-rows grid-template-columns grid-template-areas
|
||||
grid-auto-rows grid-auto-columns grid-row-gap grid-column-gap
|
||||
grid-auto-flow"
|
||||
spec="https://drafts.csswg.org/css-grid/#propdef-grid"
|
||||
disable_when_testing="True"
|
||||
products="gecko">
|
||||
use properties::longhands::{grid_auto_columns, grid_auto_rows, grid_auto_flow};
|
||||
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::specified::{LengthOrPercentage, TrackSize};
|
||||
|
||||
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
|
||||
let mut temp_rows = Either::Second(None_);
|
||||
let mut temp_cols = Either::Second(None_);
|
||||
let mut temp_areas = Either::Second(None_);
|
||||
let mut auto_rows = TrackSize::default();
|
||||
let mut auto_cols = TrackSize::default();
|
||||
let mut flow = grid_auto_flow::get_initial_value();
|
||||
|
||||
fn parse_auto_flow(input: &mut Parser, is_row: bool) -> Result<SpecifiedAutoFlow, ()> {
|
||||
let mut auto_flow = None;
|
||||
let mut dense = false;
|
||||
for _ in 0..2 {
|
||||
if input.try(|i| i.expect_ident_matching("auto-flow")).is_ok() {
|
||||
auto_flow = if is_row {
|
||||
Some(AutoFlow::Row)
|
||||
} else {
|
||||
Some(AutoFlow::Column)
|
||||
};
|
||||
} else if input.try(|i| i.expect_ident_matching("dense")).is_ok() {
|
||||
dense = true;
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
auto_flow.map(|flow| {
|
||||
SpecifiedAutoFlow {
|
||||
autoflow: flow,
|
||||
dense: dense,
|
||||
}
|
||||
}).ok_or(())
|
||||
}
|
||||
|
||||
if let Ok((rows, cols, areas)) = input.try(|i| super::grid_template::parse_grid_template(context, i)) {
|
||||
temp_rows = rows;
|
||||
temp_cols = cols;
|
||||
temp_areas = areas;
|
||||
} else if let Ok(rows) = input.try(|i| grid_template_rows::parse(context, i)) {
|
||||
temp_rows = rows;
|
||||
input.expect_delim('/')?;
|
||||
flow = parse_auto_flow(input, false)?;
|
||||
auto_cols = grid_auto_columns::parse(context, input).unwrap_or_default();
|
||||
} else {
|
||||
flow = parse_auto_flow(input, true)?;
|
||||
auto_rows = input.try(|i| grid_auto_rows::parse(context, i)).unwrap_or_default();
|
||||
input.expect_delim('/')?;
|
||||
temp_cols = grid_template_columns::parse(context, input)?;
|
||||
}
|
||||
|
||||
Ok(expanded! {
|
||||
grid_template_rows: temp_rows,
|
||||
grid_template_columns: temp_cols,
|
||||
grid_template_areas: temp_areas,
|
||||
grid_auto_rows: auto_rows,
|
||||
grid_auto_columns: auto_cols,
|
||||
grid_auto_flow: flow,
|
||||
// This shorthand also resets grid gap
|
||||
grid_row_gap: LengthOrPercentage::zero(),
|
||||
grid_column_gap: LengthOrPercentage::zero(),
|
||||
})
|
||||
}
|
||||
|
||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
if let Either::First(_) = *self.grid_template_areas {
|
||||
super::grid_template::serialize_grid_template(self.grid_template_rows,
|
||||
self.grid_template_columns,
|
||||
self.grid_template_areas, dest)
|
||||
} else if self.grid_auto_flow.autoflow == AutoFlow::Row {
|
||||
self.grid_template_rows.to_css(dest)?;
|
||||
dest.write_str(" / auto-flow")?;
|
||||
if self.grid_auto_flow.dense {
|
||||
dest.write_str(" dense")?;
|
||||
}
|
||||
|
||||
self.grid_auto_columns.to_css(dest)
|
||||
} else {
|
||||
dest.write_str("auto-flow ")?;
|
||||
if self.grid_auto_flow.dense {
|
||||
dest.write_str("dense ")?;
|
||||
}
|
||||
|
||||
self.grid_auto_rows.to_css(dest)?;
|
||||
dest.write_str(" / ")?;
|
||||
self.grid_template_columns.to_css(dest)
|
||||
}
|
||||
}
|
||||
}
|
||||
</%helpers:shorthand>
|
||||
|
||||
<%helpers:shorthand name="place-content" sub_properties="align-content justify-content"
|
||||
spec="https://drafts.csswg.org/css-align/#propdef-place-content"
|
||||
products="gecko" disable_when_testing="True">
|
||||
|
|
|
@ -76,21 +76,35 @@ impl Parse for GridLine {
|
|||
return Ok(grid_line)
|
||||
}
|
||||
|
||||
// <custom-ident> | [ <integer> && <custom-ident>? ] | [ span && [ <integer> || <custom-ident> ] ]
|
||||
// This <grid-line> horror is simply,
|
||||
// [ span? && [ <custom-ident> || <integer> ] ]
|
||||
// And, for some magical reason, "span" should be the first or last value and not in-between.
|
||||
let mut val_before_span = false;
|
||||
|
||||
for _ in 0..3 { // Maximum possible entities for <grid-line>
|
||||
if input.try(|i| i.expect_ident_matching("span")).is_ok() {
|
||||
if grid_line.is_span || grid_line.line_num.is_some() || grid_line.ident.is_some() {
|
||||
return Err(()) // span (if specified) should be first
|
||||
}
|
||||
grid_line.is_span = true; // span (if specified) should be first
|
||||
} else if let Ok(i) = input.try(|i| Integer::parse(context, i)) {
|
||||
if i.value() == 0 || grid_line.line_num.is_some() {
|
||||
if grid_line.is_span {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
if grid_line.line_num.is_some() || grid_line.ident.is_some() {
|
||||
val_before_span = true;
|
||||
}
|
||||
|
||||
grid_line.is_span = true;
|
||||
} else if let Ok(i) = input.try(|i| Integer::parse(context, i)) {
|
||||
if i.value() == 0 || val_before_span || grid_line.line_num.is_some() {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
grid_line.line_num = Some(i);
|
||||
} else if let Ok(name) = input.try(|i| i.expect_ident()) {
|
||||
if grid_line.ident.is_some() || CustomIdent::from_ident((&*name).into(), &[]).is_err() {
|
||||
if val_before_span || grid_line.ident.is_some() ||
|
||||
CustomIdent::from_ident((&*name).into(), &[]).is_err() {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
grid_line.ident = Some(name.into_owned());
|
||||
} else {
|
||||
break
|
||||
|
@ -292,8 +306,10 @@ impl<L: ToComputedValue> ToComputedValue for TrackSize<L> {
|
|||
}
|
||||
}
|
||||
|
||||
fn concat_serialize_idents<W>(prefix: &str, suffix: &str,
|
||||
slice: &[String], sep: &str, dest: &mut W) -> fmt::Result
|
||||
/// Helper function for serializing identifiers with a prefix and suffix, used
|
||||
/// for serializing <line-names> (in grid).
|
||||
pub fn concat_serialize_idents<W>(prefix: &str, suffix: &str,
|
||||
slice: &[String], sep: &str, dest: &mut W) -> fmt::Result
|
||||
where W: fmt::Write
|
||||
{
|
||||
if let Some((ref first, rest)) = slice.split_first() {
|
||||
|
|
Загрузка…
Ссылка в новой задаче