diff --git a/components/style/properties/longhands/counters.mako.rs b/components/style/properties/longhands/counters.mako.rs index db035568c71..2ad0f72cd4a 100644 --- a/components/style/properties/longhands/counters.mako.rs +++ b/components/style/properties/longhands/counters.mako.rs @@ -29,7 +29,7 @@ ${helpers.predefined_type( ${helpers.predefined_type( "counter-reset", - "CounterSetOrReset", + "CounterReset", engines="gecko servo-2013", initial_value="Default::default()", animation_value_type="discrete", @@ -39,7 +39,7 @@ ${helpers.predefined_type( ${helpers.predefined_type( "counter-set", - "CounterSetOrReset", + "CounterSet", engines="gecko", initial_value="Default::default()", animation_value_type="discrete", diff --git a/components/style/values/computed/counters.rs b/components/style/values/computed/counters.rs index 1ae46c772ab..fd5e915c4a8 100644 --- a/components/style/values/computed/counters.rs +++ b/components/style/values/computed/counters.rs @@ -7,13 +7,17 @@ use crate::values::computed::image::Image; use crate::values::generics::counters as generics; use crate::values::generics::counters::CounterIncrement as GenericCounterIncrement; -use crate::values::generics::counters::CounterSetOrReset as GenericCounterSetOrReset; +use crate::values::generics::counters::CounterReset as GenericCounterReset; +use crate::values::generics::counters::CounterSet as GenericCounterSet; /// A computed value for the `counter-increment` property. pub type CounterIncrement = GenericCounterIncrement; -/// A computed value for the `counter-set` and `counter-reset` properties. -pub type CounterSetOrReset = GenericCounterSetOrReset; +/// A computed value for the `counter-reset` property. +pub type CounterReset = GenericCounterReset; + +/// A computed value for the `counter-set` property. +pub type CounterSet = GenericCounterSet; /// A computed value for the `content` property. pub type Content = generics::GenericContent; diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 955a1b93877..25103b34772 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -52,7 +52,7 @@ pub use self::box_::{ScrollSnapAlign, ScrollSnapAxis, ScrollSnapStrictness, Scro pub use self::box_::{TouchAction, VerticalAlign, WillChange}; pub use self::color::{Color, ColorOrAuto, ColorPropertyValue, ColorScheme}; pub use self::column::ColumnCount; -pub use self::counters::{Content, ContentItem, CounterIncrement, CounterSetOrReset}; +pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset, CounterSet}; pub use self::easing::TimingFunction; pub use self::effects::{BoxShadow, Filter, SimpleShadow}; pub use self::flex::FlexBasis; diff --git a/components/style/values/generics/counters.rs b/components/style/values/generics/counters.rs index 2a8f70c8f44..e5656faea56 100644 --- a/components/style/values/generics/counters.rs +++ b/components/style/values/generics/counters.rs @@ -12,6 +12,8 @@ use crate::values::generics::CounterStyle; use crate::values::specified::Attr; use crate::values::CustomIdent; use std::ops::Deref; +use std::fmt::{self, Write}; +use style_traits::{CssWriter, ToCss}; /// A name / value pair for counters. #[derive( @@ -21,7 +23,6 @@ use std::ops::Deref; PartialEq, SpecifiedValueInfo, ToComputedValue, - ToCss, ToResolvedValue, ToShmem, )] @@ -31,9 +32,35 @@ pub struct GenericCounterPair { pub name: CustomIdent, /// The value of the counter / increment / etc. pub value: Integer, + /// If true, then this represents `reversed(name)`. + /// NOTE: It can only be true on `counter-reset` values. + pub is_reversed: bool, } pub use self::GenericCounterPair as CounterPair; +impl ToCss for CounterPair +where + Integer: ToCss + PartialEq, +{ + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: Write, + { + if self.is_reversed { + dest.write_str("reversed(")?; + } + self.name.to_css(dest)?; + if self.is_reversed { + dest.write_str(")")?; + if self.value == i32::min_value() { + return Ok(()); + } + } + dest.write_str(" ")?; + self.value.to_css(dest) + } +} + /// A generic value for the `counter-increment` property. #[derive( Clone, @@ -48,7 +75,7 @@ pub use self::GenericCounterPair as CounterPair; ToShmem, )] #[repr(transparent)] -pub struct GenericCounterIncrement(pub GenericCounters); +pub struct GenericCounterIncrement(#[css(field_bound)] pub GenericCounters); pub use self::GenericCounterIncrement as CounterIncrement; impl CounterIncrement { @@ -68,7 +95,7 @@ impl Deref for CounterIncrement { } } -/// A generic value for the `counter-set` and `counter-reset` properties. +/// A generic value for the `counter-set` property. #[derive( Clone, Debug, @@ -82,18 +109,52 @@ impl Deref for CounterIncrement { ToShmem, )] #[repr(transparent)] -pub struct GenericCounterSetOrReset(pub GenericCounters); -pub use self::GenericCounterSetOrReset as CounterSetOrReset; +pub struct GenericCounterSet(#[css(field_bound)] pub GenericCounters); +pub use self::GenericCounterSet as CounterSet; -impl CounterSetOrReset { - /// Returns a new value for `counter-set` / `counter-reset`. +impl CounterSet { + /// Returns a new value for `counter-set`. #[inline] pub fn new(counters: Vec>) -> Self { - CounterSetOrReset(Counters(counters.into())) + CounterSet(Counters(counters.into())) } } -impl Deref for CounterSetOrReset { +impl Deref for CounterSet { + type Target = [CounterPair]; + + #[inline] + fn deref(&self) -> &Self::Target { + &(self.0).0 + } +} + +/// A generic value for the `counter-reset` property. +#[derive( + Clone, + Debug, + Default, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] +#[repr(transparent)] +pub struct GenericCounterReset(#[css(field_bound)] pub GenericCounters); +pub use self::GenericCounterReset as CounterReset; + +impl CounterReset { + /// Returns a new value for `counter-reset`. + #[inline] + pub fn new(counters: Vec>) -> Self { + CounterReset(Counters(counters.into())) + } +} + +impl Deref for CounterReset { type Target = [CounterPair]; #[inline] @@ -119,7 +180,9 @@ impl Deref for CounterSetOrReset { )] #[repr(transparent)] pub struct GenericCounters( - #[css(iterable, if_empty = "none")] crate::OwnedSlice>, + #[css(field_bound)] + #[css(iterable, if_empty = "none")] + crate::OwnedSlice>, ); pub use self::GenericCounters as Counters; diff --git a/components/style/values/specified/counters.rs b/components/style/values/specified/counters.rs index aa442549fa5..c9507ce8383 100644 --- a/components/style/values/specified/counters.rs +++ b/components/style/values/specified/counters.rs @@ -21,6 +21,18 @@ use cssparser::{Parser, Token}; use selectors::parser::SelectorParseErrorKind; use style_traits::{KeywordsCollectFn, ParseError, SpecifiedValueInfo, StyleParseErrorKind}; +#[derive(PartialEq)] +enum CounterType { Increment, Set, Reset, } + +impl CounterType { + fn default_value(&self) -> i32 { + match *self { + Self::Increment => 1, + Self::Reset | Self::Set => 0, + } + } +} + /// A specified value for the `counter-increment` property. pub type CounterIncrement = generics::GenericCounterIncrement; @@ -29,26 +41,38 @@ impl Parse for CounterIncrement { context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { - Ok(Self::new(parse_counters(context, input, 1)?)) + Ok(Self::new(parse_counters(context, input, CounterType::Increment)?)) } } -/// A specified value for the `counter-set` and `counter-reset` properties. -pub type CounterSetOrReset = generics::GenericCounterSetOrReset; +/// A specified value for the `counter-set` property. +pub type CounterSet = generics::GenericCounterSet; -impl Parse for CounterSetOrReset { +impl Parse for CounterSet { fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { - Ok(Self::new(parse_counters(context, input, 0)?)) + Ok(Self::new(parse_counters(context, input, CounterType::Set)?)) + } +} + +/// A specified value for the `counter-reset` property. +pub type CounterReset = generics::GenericCounterReset; + +impl Parse for CounterReset { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + Ok(Self::new(parse_counters(context, input, CounterType::Reset)?)) } } fn parse_counters<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, - default_value: i32, + counter_type: CounterType, ) -> Result>, ParseError<'i>> { if input .try_parse(|input| input.expect_ident_matching("none")) @@ -60,8 +84,14 @@ fn parse_counters<'i, 't>( let mut counters = Vec::new(); loop { let location = input.current_source_location(); - let name = match input.next() { - Ok(&Token::Ident(ref ident)) => CustomIdent::from_ident(location, ident, &["none"])?, + let (name, is_reversed) = match input.next() { + Ok(&Token::Ident(ref ident)) => (CustomIdent::from_ident(location, ident, &["none"])?, false), + Ok(&Token::Function(ref name)) if counter_type == CounterType::Reset && name.eq_ignore_ascii_case("reversed") => { + input.parse_nested_block(|input| { + let location = input.current_source_location(); + Ok((CustomIdent::from_ident(location, input.expect_ident()?, &["none"])?, true)) + })? + } Ok(t) => { let t = t.clone(); return Err(location.new_unexpected_token_error(t)); @@ -69,10 +99,19 @@ fn parse_counters<'i, 't>( Err(_) => break, }; - let value = input - .try_parse(|input| Integer::parse(context, input)) - .unwrap_or(Integer::new(default_value)); - counters.push(CounterPair { name, value }); + let value = match input.try_parse(|input| Integer::parse(context, input)) { + Ok(start) => + if start.value == i32::min_value() { + // The spec says that values must be clamped to the valid range, + // and we reserve i32::min_value() as an internal magic value. + // https://drafts.csswg.org/css-lists/#auto-numbering + Integer::new(i32::min_value() + 1) + } else { + start + }, + _ => Integer::new(if is_reversed { i32::min_value() } else { counter_type.default_value() }), + }; + counters.push(CounterPair { name, value, is_reversed }); } if !counters.is_empty() { diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 64bc063960e..4aeee691566 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -44,7 +44,7 @@ pub use self::box_::{ScrollSnapAlign, ScrollSnapAxis, ScrollSnapStrictness, Scro pub use self::box_::{TouchAction, TransitionProperty, VerticalAlign, WillChange}; pub use self::color::{Color, ColorOrAuto, ColorPropertyValue, ColorScheme}; pub use self::column::ColumnCount; -pub use self::counters::{Content, ContentItem, CounterIncrement, CounterSetOrReset}; +pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset, CounterSet}; pub use self::easing::TimingFunction; pub use self::effects::{BoxShadow, Filter, SimpleShadow}; pub use self::flex::FlexBasis; @@ -577,6 +577,12 @@ impl One for Integer { } } +impl PartialEq for Integer { + fn eq(&self, value: &i32) -> bool { + self.value() == *value + } +} + impl Integer { /// Trivially constructs a new `Integer` value. pub fn new(val: CSSInteger) -> Self {