mirror of
https://github.com/servo/servo.git
synced 2025-08-04 05:00:08 +01:00
Add parsing/serialization for repeat() function
This commit is contained in:
parent
d3e394c68a
commit
81b4e64dfc
2 changed files with 143 additions and 2 deletions
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
//! Necessary types for [grid](https://drafts.csswg.org/css-grid/).
|
//! Necessary types for [grid](https://drafts.csswg.org/css-grid/).
|
||||||
|
|
||||||
use cssparser::{Parser, Token};
|
use cssparser::{Parser, Token, serialize_identifier};
|
||||||
use parser::{Parse, ParserContext};
|
use parser::{Parse, ParserContext};
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -294,7 +294,7 @@ impl<L: ToCss> ToCss for TrackSize<L> {
|
||||||
TrackSize::MinMax(ref infexible, ref flexible) => {
|
TrackSize::MinMax(ref infexible, ref flexible) => {
|
||||||
try!(dest.write_str("minmax("));
|
try!(dest.write_str("minmax("));
|
||||||
try!(infexible.to_css(dest));
|
try!(infexible.to_css(dest));
|
||||||
try!(dest.write_str(","));
|
try!(dest.write_str(", "));
|
||||||
try!(flexible.to_css(dest));
|
try!(flexible.to_css(dest));
|
||||||
dest.write_str(")")
|
dest.write_str(")")
|
||||||
},
|
},
|
||||||
|
@ -364,6 +364,24 @@ pub fn parse_line_names(input: &mut Parser) -> Result<Vec<String>, ()> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
dest.write_str(prefix)?;
|
||||||
|
serialize_identifier(first, dest)?;
|
||||||
|
for thing in rest {
|
||||||
|
dest.write_str(sep)?;
|
||||||
|
serialize_identifier(thing, dest)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest.write_str(suffix)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// The initial argument of the `repeat` function.
|
/// The initial argument of the `repeat` function.
|
||||||
///
|
///
|
||||||
/// https://drafts.csswg.org/css-grid/#typedef-track-repeat
|
/// https://drafts.csswg.org/css-grid/#typedef-track-repeat
|
||||||
|
@ -408,3 +426,125 @@ impl ToCss for RepeatCount {
|
||||||
|
|
||||||
impl ComputedValueAsSpecified for RepeatCount {}
|
impl ComputedValueAsSpecified for RepeatCount {}
|
||||||
no_viewport_percentage!(RepeatCount);
|
no_viewport_percentage!(RepeatCount);
|
||||||
|
|
||||||
|
/// The type of `repeat` function (only used in parsing).
|
||||||
|
///
|
||||||
|
/// https://drafts.csswg.org/css-grid/#typedef-track-repeat
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
enum RepeatType {
|
||||||
|
/// [`<auto-repeat>`](https://drafts.csswg.org/css-grid/#typedef-auto-repeat)
|
||||||
|
Auto,
|
||||||
|
/// [`<track-repeat>`](https://drafts.csswg.org/css-grid/#typedef-track-repeat)
|
||||||
|
Normal,
|
||||||
|
/// [`<fixed-repeat>`](https://drafts.csswg.org/css-grid/#typedef-fixed-repeat)
|
||||||
|
Fixed,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The structure containing `<line-names>` and `<track-size>` values.
|
||||||
|
///
|
||||||
|
/// It can also hold `repeat()` function parameters, which expands into the respective
|
||||||
|
/// values in its computed form.
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub struct TrackRepeat<L> {
|
||||||
|
/// The number of times for the value to be repeated (could also be `auto-fit` or `auto-fill`)
|
||||||
|
pub count: RepeatCount,
|
||||||
|
/// `<line-names>` accompanying `<track_size>` values.
|
||||||
|
///
|
||||||
|
/// If there's no `<line-names>`, then it's represented by an empty vector.
|
||||||
|
/// For N `<track-size>` values, there will be N+1 `<line-names>`, and so this vector's
|
||||||
|
/// length is always one value more than that of the `<track-size>`.
|
||||||
|
pub line_names: Vec<Vec<String>>,
|
||||||
|
/// `<track-size>` values.
|
||||||
|
pub track_sizes: Vec<TrackSize<L>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TrackRepeat<LengthOrPercentage> {
|
||||||
|
fn parse_with_repeat_type(context: &ParserContext, input: &mut Parser)
|
||||||
|
-> Result<(TrackRepeat<LengthOrPercentage>, RepeatType), ()> {
|
||||||
|
input.try(|i| i.expect_function_matching("repeat")).and_then(|_| {
|
||||||
|
input.parse_nested_block(|input| {
|
||||||
|
let count = RepeatCount::parse(context, input)?;
|
||||||
|
input.expect_comma()?;
|
||||||
|
|
||||||
|
let is_auto = count == RepeatCount::AutoFit || count == RepeatCount::AutoFill;
|
||||||
|
let mut repeat_type = if is_auto {
|
||||||
|
RepeatType::Auto
|
||||||
|
} else { // <fixed-size> is a subset of <track_size>, so it should work for both
|
||||||
|
RepeatType::Fixed
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut names = vec![];
|
||||||
|
let mut values = vec![];
|
||||||
|
let mut current_names;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
current_names = input.try(parse_line_names).unwrap_or(vec![]);
|
||||||
|
if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) {
|
||||||
|
if !track_size.is_fixed() {
|
||||||
|
if is_auto {
|
||||||
|
return Err(()) // should be <fixed-size> for <auto-repeat>
|
||||||
|
}
|
||||||
|
|
||||||
|
if repeat_type == RepeatType::Fixed {
|
||||||
|
repeat_type = RepeatType::Normal // <track-size> for sure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
values.push(track_size);
|
||||||
|
names.push(current_names);
|
||||||
|
} else {
|
||||||
|
if values.is_empty() {
|
||||||
|
return Err(()) // expecting at least one <track-size>
|
||||||
|
}
|
||||||
|
|
||||||
|
names.push(current_names); // final `<line-names>`
|
||||||
|
break // no more <track-size>, breaking
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let repeat = TrackRepeat {
|
||||||
|
count: count,
|
||||||
|
track_sizes: values,
|
||||||
|
line_names: names,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((repeat, repeat_type))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: ToCss> ToCss for TrackRepeat<L> {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
dest.write_str("repeat(")?;
|
||||||
|
self.count.to_css(dest)?;
|
||||||
|
dest.write_str(", ")?;
|
||||||
|
|
||||||
|
let mut line_names_iter = self.line_names.iter();
|
||||||
|
for (i, (ref size, ref names)) in self.track_sizes.iter()
|
||||||
|
.zip(&mut line_names_iter).enumerate() {
|
||||||
|
if i > 0 {
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
concat_serialize_idents("[", "] ", names, " ", dest)?;
|
||||||
|
size.to_css(dest)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(line_names_last) = line_names_iter.next() {
|
||||||
|
concat_serialize_idents(" [", "]", line_names_last, " ", dest)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest.write_str(")")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasViewportPercentage for TrackRepeat<LengthOrPercentage> {
|
||||||
|
#[inline]
|
||||||
|
fn has_viewport_percentage(&self) -> bool {
|
||||||
|
self.track_sizes.iter().any(|ref v| v.has_viewport_percentage())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -74,6 +74,7 @@ macro_rules! impl_to_css_for_predefined_type {
|
||||||
|
|
||||||
impl_to_css_for_predefined_type!(f32);
|
impl_to_css_for_predefined_type!(f32);
|
||||||
impl_to_css_for_predefined_type!(i32);
|
impl_to_css_for_predefined_type!(i32);
|
||||||
|
impl_to_css_for_predefined_type!(u16);
|
||||||
impl_to_css_for_predefined_type!(u32);
|
impl_to_css_for_predefined_type!(u32);
|
||||||
impl_to_css_for_predefined_type!(::cssparser::Token<'a>);
|
impl_to_css_for_predefined_type!(::cssparser::Token<'a>);
|
||||||
impl_to_css_for_predefined_type!(::cssparser::RGBA);
|
impl_to_css_for_predefined_type!(::cssparser::RGBA);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue