Add 'range' descriptor to @counter-style

This commit is contained in:
Simon Sapin 2017-04-14 09:45:44 +02:00
parent 29bcb5b636
commit 6f79684468
2 changed files with 93 additions and 0 deletions

View file

@ -12,7 +12,9 @@ use cssparser::{serialize_string, serialize_identifier};
#[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSCounterDesc;
use parser::{ParserContext, log_css_error, Parse};
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use std::ascii::AsciiExt;
use std::fmt;
use std::ops::Range;
use style_traits::ToCss;
use values::CustomIdent;
@ -139,6 +141,10 @@ counter_style_descriptors! {
/// https://drafts.csswg.org/css-counter-styles/#counter-style-suffix
"suffix" suffix / eCSSCounterDesc_Suffix: Symbol = Symbol::String(". ".to_owned());
/// https://drafts.csswg.org/css-counter-styles/#counter-style-range
"range" range / eCSSCounterDesc_Range: Ranges =
Ranges(Vec::new()); // Empty Vec represents 'auto'
}
/// https://drafts.csswg.org/css-counter-styles/#counter-style-system
@ -261,3 +267,67 @@ impl ToCss for Negative {
Ok(())
}
}
/// https://drafts.csswg.org/css-counter-styles/#counter-style-range
///
/// Empty Vec represents 'auto'
#[derive(Debug)]
pub struct Ranges(pub Vec<Range<Option<i32>>>);
impl Parse for Ranges {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
Ok(Ranges(Vec::new()))
} else {
input.parse_comma_separated(|input| {
let opt_start = parse_bound(input)?;
let opt_end = parse_bound(input)?;
if let (Some(start), Some(end)) = (opt_start, opt_end) {
if start > end {
return Err(())
}
}
Ok(opt_start..opt_end)
}).map(Ranges)
}
}
}
fn parse_bound(input: &mut Parser) -> Result<Option<i32>, ()> {
match input.next() {
Ok(Token::Number(ref v)) if v.int_value.is_some() => Ok(Some(v.int_value.unwrap())),
Ok(Token::Ident(ref ident)) if ident.eq_ignore_ascii_case("infinite") => Ok(None),
_ => Err(())
}
}
impl ToCss for Ranges {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
let mut iter = self.0.iter();
if let Some(first) = iter.next() {
range_to_css(first, dest)?;
for item in iter {
dest.write_str(", ")?;
range_to_css(item, dest)?;
}
Ok(())
} else {
dest.write_str("auto")
}
}
}
fn range_to_css<W>(range: &Range<Option<i32>>, dest: &mut W) -> fmt::Result
where W: fmt::Write {
bound_to_css(range.start, dest)?;
dest.write_char(' ')?;
bound_to_css(range.end, dest)
}
fn bound_to_css<W>(range: Option<i32>, dest: &mut W) -> fmt::Result where W: fmt::Write {
if let Some(finite) = range {
write!(dest, "{}", finite)
} else {
dest.write_str("infinite")
}
}

View file

@ -187,3 +187,26 @@ impl ToNsCssValue for counter_style::Symbol {
}
}
}
impl ToNsCssValue for counter_style::Ranges {
fn convert(&self, _nscssvalue: &mut nsCSSValue) {
if self.0.is_empty() {
//nscssvalue.set_auto(); // FIXME: add bindings for nsCSSValue::SetAutoValue
} else {
for range in &self.0 {
fn set_bound(bound: Option<i32>, nscssvalue: &mut nsCSSValue) {
if let Some(finite) = bound {
nscssvalue.set_integer(finite)
} else {
nscssvalue.set_enum(structs::NS_STYLE_COUNTER_RANGE_INFINITE as i32)
}
}
let mut start = nsCSSValue::null();
let mut end = nsCSSValue::null();
set_bound(range.start, &mut start);
set_bound(range.end, &mut end);
// FIXME: add bindings for nsCSSValuePairList
}
}
}
}