diff --git a/components/layout/flow.rs b/components/layout/flow.rs index e42871dfa24..c21371b8520 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -1035,8 +1035,8 @@ impl BaseFlow { } } - if !style.get_counters().counter_reset.0.is_empty() || - !style.get_counters().counter_increment.0.is_empty() { + if !style.get_counters().counter_reset.get_values().is_empty() || + !style.get_counters().counter_increment.get_values().is_empty() { flags.insert(FlowFlags::AFFECTS_COUNTERS) } } diff --git a/components/layout/generated_content.rs b/components/layout/generated_content.rs index e21e2a7e864..b1716d9dc54 100644 --- a/components/layout/generated_content.rs +++ b/components/layout/generated_content.rs @@ -272,7 +272,7 @@ impl<'a, 'b> ResolveGeneratedContentFragmentMutator<'a, 'b> { } self.traversal.list_item.truncate_to_level(self.level); - for &(ref counter_name, value) in &fragment.style().get_counters().counter_reset.0 { + for &(ref counter_name, value) in fragment.style().get_counters().counter_reset.get_values() { let counter_name = &*counter_name.0; if let Some(ref mut counter) = self.traversal.counters.get_mut(counter_name) { counter.reset(self.level, value); @@ -284,7 +284,7 @@ impl<'a, 'b> ResolveGeneratedContentFragmentMutator<'a, 'b> { self.traversal.counters.insert(counter_name.to_owned(), counter); } - for &(ref counter_name, value) in &fragment.style().get_counters().counter_increment.0 { + for &(ref counter_name, value) in fragment.style().get_counters().counter_increment.get_values() { let counter_name = &*counter_name.0; if let Some(ref mut counter) = self.traversal.counters.get_mut(counter_name) { counter.increment(self.level, value); diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 8f2633a2cb1..1954a79d531 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -5675,11 +5675,14 @@ clip-path } % for counter_property in ["Increment", "Reset"]: - pub fn set_counter_${counter_property.lower()}(&mut self, v: longhands::counter_increment::computed_value::T) { + pub fn set_counter_${counter_property.lower()}( + &mut self, + v: longhands::counter_${counter_property.lower()}::computed_value::T + ) { unsafe { bindings::Gecko_ClearAndResizeCounter${counter_property}s(&mut self.gecko, - v.0.len() as u32); - for (i, (name, value)) in v.0.into_iter().enumerate() { + v.get_values().len() as u32); + for (i, &(ref name, value)) in v.get_values().into_iter().enumerate() { self.gecko.m${counter_property}s[i].mCounter.assign(name.0.as_slice()); self.gecko.m${counter_property}s[i].mValue = value; } @@ -5696,11 +5699,13 @@ clip-path self.copy_counter_${counter_property.lower()}_from(other) } - pub fn clone_counter_${counter_property.lower()}(&self) -> longhands::counter_increment::computed_value::T { + pub fn clone_counter_${counter_property.lower()}( + &self + ) -> longhands::counter_${counter_property.lower()}::computed_value::T { use values::CustomIdent; use gecko_string_cache::Atom; - longhands::counter_increment::computed_value::T( + longhands::counter_${counter_property.lower()}::computed_value::T::new( self.gecko.m${counter_property}s.iter().map(|ref gecko_counter| { (CustomIdent(Atom::from(gecko_counter.mCounter.to_string())), gecko_counter.mValue) }).collect() diff --git a/components/style/properties/longhand/counters.mako.rs b/components/style/properties/longhand/counters.mako.rs index d55e880dcc9..0c906b75f0f 100644 --- a/components/style/properties/longhand/counters.mako.rs +++ b/components/style/properties/longhand/counters.mako.rs @@ -236,131 +236,14 @@ } -<%helpers:longhand name="counter-increment" animation_value_type="discrete" - spec="https://drafts.csswg.org/css-lists/#propdef-counter-increment"> - use std::fmt::{self, Write}; - use style_traits::{CssWriter, ToCss}; - use values::CustomIdent; +${helpers.predefined_type("counter-increment", + "CounterIncrement", + initial_value="computed::CounterIncrement::none()", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-lists/#propdef-counter-increment")} - #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] - #[derive(Clone, Debug, PartialEq)] - pub struct SpecifiedValue(pub Vec<(CustomIdent, specified::Integer)>); - - pub mod computed_value { - use std::fmt::{self, Write}; - use style_traits::{CssWriter, ToCss}; - use values::CustomIdent; - - #[derive(Clone, Debug, MallocSizeOf, PartialEq)] - pub struct T(pub Vec<(CustomIdent, i32)>); - - impl ToCss for T { - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result - where - W: Write, - { - if self.0.is_empty() { - return dest.write_str("none") - } - - let mut first = true; - for &(ref name, value) in &self.0 { - if !first { - dest.write_str(" ")?; - } - first = false; - name.to_css(dest)?; - dest.write_str(" ")?; - value.to_css(dest)?; - } - Ok(()) - } - } - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - computed_value::T(self.0.iter().map(|&(ref name, ref value)| { - (name.clone(), value.to_computed_value(context)) - }).collect::>()) - } - - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - SpecifiedValue(computed.0.iter().map(|&(ref name, ref value)| { - (name.clone(), specified::Integer::from_computed_value(&value)) - }).collect::>()) - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(Vec::new()) - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result - where - W: Write, - { - if self.0.is_empty() { - return dest.write_str("none"); - } - let mut first = true; - for &(ref name, ref value) in &self.0 { - if !first { - dest.write_str(" ")?; - } - first = false; - name.to_css(dest)?; - dest.write_str(" ")?; - value.to_css(dest)?; - } - - Ok(()) - } - } - - pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) - -> Result> { - parse_common(context, 1, input) - } - - pub fn parse_common<'i, 't>(context: &ParserContext, default_value: i32, input: &mut Parser<'i, 't>) - -> Result> { - if input.try(|input| input.expect_ident_matching("none")).is_ok() { - return Ok(SpecifiedValue(Vec::new())) - } - - let mut counters = Vec::new(); - loop { - let location = input.current_source_location(); - let counter_name = match input.next() { - Ok(&Token::Ident(ref ident)) => CustomIdent::from_ident(location, ident, &["none"])?, - Ok(t) => return Err(location.new_unexpected_token_error(t.clone())), - Err(_) => break, - }; - let counter_delta = input.try(|input| specified::Integer::parse(context, input)) - .unwrap_or(specified::Integer::new(default_value)); - counters.push((counter_name, counter_delta)) - } - - if !counters.is_empty() { - Ok(SpecifiedValue(counters)) - } else { - Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) - } - } - - -<%helpers:longhand name="counter-reset" animation_value_type="discrete" - spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-reset"> - pub use super::counter_increment::{SpecifiedValue, computed_value, get_initial_value}; - use super::counter_increment::parse_common; - - pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) - -> Result> { - parse_common(context, 0, input) - } - +${helpers.predefined_type("counter-reset", + "CounterReset", + initial_value="computed::CounterReset::none()", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-reset")} diff --git a/components/style/values/computed/counters.rs b/components/style/values/computed/counters.rs new file mode 100644 index 00000000000..5c654ec8054 --- /dev/null +++ b/components/style/values/computed/counters.rs @@ -0,0 +1,80 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! Computed values for counter properties + +use values::CustomIdent; +use values::computed::{Context, ToComputedValue}; +use values::generics::counters::CounterIntegerList; +use values::specified::{CounterIncrement as SpecifiedCounterIncrement, CounterReset as SpecifiedCounterReset}; + +type ComputedIntegerList = CounterIntegerList; + +/// A computed value for the `counter-increment` property. +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] +pub struct CounterIncrement(pub ComputedIntegerList); + +impl CounterIncrement { + /// Returns the `none` value. + #[inline] + pub fn none() -> CounterIncrement { + CounterIncrement(ComputedIntegerList::new(Vec::new())) + } + + /// Returns a new computed `counter-increment` object with the given values. + pub fn new(vec: Vec<(CustomIdent, i32)>) -> CounterIncrement { + CounterIncrement(ComputedIntegerList::new(vec)) + } + + /// Returns the values of the computed `counter-increment` object. + pub fn get_values(&self) -> &[(CustomIdent, i32)] { + self.0.get_values() + } +} + +impl ToComputedValue for SpecifiedCounterIncrement { + type ComputedValue = CounterIncrement; + + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + CounterIncrement(self.0.to_computed_value(context)) + } + + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + SpecifiedCounterIncrement(ToComputedValue::from_computed_value(&computed.0)) + } +} + +/// A computed value for the `counter-reset` property. +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] +pub struct CounterReset(pub ComputedIntegerList); + +impl CounterReset { + /// Returns the `none` value. + #[inline] + pub fn none() -> CounterReset { + CounterReset(ComputedIntegerList::new(Vec::new())) + } + + /// Returns a new computed `counter-reset` object with the given values. + pub fn new(vec: Vec<(CustomIdent, i32)>) -> CounterReset { + CounterReset(ComputedIntegerList::new(vec)) + } + + /// Returns the values of the computed `counter-reset` object. + pub fn get_values(&self) -> &[(CustomIdent, i32)] { + self.0.get_values() + } +} + +impl ToComputedValue for SpecifiedCounterReset { + type ComputedValue = CounterReset; + + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + CounterReset(self.0.to_computed_value(context)) + } + + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + SpecifiedCounterReset(ToComputedValue::from_computed_value(&computed.0)) + } +} diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 6a1f556ec85..66dd5297729 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -46,6 +46,7 @@ pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, pub use self::box_::{AnimationIterationCount, AnimationName, Display, OverscrollBehavior, Contain}; pub use self::box_::{OverflowClipBox, ScrollSnapType, TouchAction, VerticalAlign, WillChange}; pub use self::color::{Color, ColorPropertyValue, RGBAColor}; +pub use self::counters::{CounterIncrement, CounterReset}; pub use self::effects::{BoxShadow, Filter, SimpleShadow}; pub use self::flex::FlexBasis; pub use self::image::{Gradient, GradientItem, Image, ImageLayer, LineDirection, MozImageRect}; @@ -86,6 +87,7 @@ pub mod border; #[path = "box.rs"] pub mod box_; pub mod color; +pub mod counters; pub mod effects; pub mod flex; pub mod font; diff --git a/components/style/values/generics/counters.rs b/components/style/values/generics/counters.rs index 127f94ac45d..a2349ec222c 100644 --- a/components/style/values/generics/counters.rs +++ b/components/style/values/generics/counters.rs @@ -5,26 +5,37 @@ //! Generic types for counters-related CSS values. use std::fmt; +use std::fmt::Write; use style_traits::{CssWriter, ToCss}; use values::CustomIdent; -/// A generic value for the `counter-increment` property. +/// A generic value for both the `counter-increment` and `counter-reset` property. /// -/// Keyword `none` is represented by an empty slice. -#[derive(Clone, Debug, PartialEq, ToComputedValue)] -pub struct CounterIncrement(Box<[(CustomIdent, Integer)]); +/// Keyword `none` is represented by an empty vector. +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)] +pub struct CounterIntegerList(Box<[(CustomIdent, I)]>); -impl CounterIncrement { - /// Returns `none`. +impl CounterIntegerList { + /// Returns the `none` value. #[inline] - pub fn none() -> Self { - CounterIncrement(vec![].into_boxed_slice()) + pub fn none() -> CounterIntegerList { + CounterIntegerList(vec![].into_boxed_slice()) + } + + /// Returns a new CounterIntegerList object. + pub fn new(vec: Vec<(CustomIdent, I)>) -> CounterIntegerList { + CounterIntegerList(vec.into_boxed_slice()) + } + + /// Returns the values of the CounterIntegerList object. + pub fn get_values(&self) -> &[(CustomIdent, I)] { + self.0.as_ref() } } -impl ToCss for CounterIncrement +impl ToCss for CounterIntegerList where - I: ToCss, + I: ToCss { #[inline] fn to_css(&self, dest: &mut CssWriter) -> fmt::Result @@ -32,12 +43,15 @@ where W: fmt::Write, { if self.0.is_empty() { - return dest.write_str("none"); + return dest.write_str("none") } - for (&(ref name, ref value), i) in self.0.iter().enumerate() { - if i != 0 { + + let mut first = true; + for &(ref name, ref value) in self.get_values() { + if !first { dest.write_str(" ")?; } + first = false; name.to_css(dest)?; dest.write_str(" ")?; value.to_css(dest)?; diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index 0943b1b0293..682736f8013 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -16,6 +16,7 @@ pub mod basic_shape; pub mod border; #[path = "box.rs"] pub mod box_; +pub mod counters; pub mod effects; pub mod flex; pub mod font; diff --git a/components/style/values/specified/counters.rs b/components/style/values/specified/counters.rs new file mode 100644 index 00000000000..5ffe35f80ce --- /dev/null +++ b/components/style/values/specified/counters.rs @@ -0,0 +1,102 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! Specified types for counter properties. + +use cssparser::Parser; +use parser::{Parse, ParserContext}; +use style_traits::ParseError; +use values::CustomIdent; +use values::generics::counters::CounterIntegerList; +use values::specified::Integer; + +/// A specified value for the `counter-increment` and `counter-reset` property. +type SpecifiedIntegerList = CounterIntegerList; + +impl SpecifiedIntegerList { + fn parse_with_default<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + default_value: i32 + ) -> Result> { + use cssparser::Token; + use style_traits::StyleParseErrorKind; + + if input.try(|input| input.expect_ident_matching("none")).is_ok() { + return Ok(CounterIntegerList::new(Vec::new())) + } + + let mut counters: Vec<(CustomIdent, Integer)> = Vec::new(); + loop { + let location = input.current_source_location(); + let counter_name = match input.next() { + Ok(&Token::Ident(ref ident)) => CustomIdent::from_ident(location, ident, &["none"])?, + Ok(t) => return Err(location.new_unexpected_token_error(t.clone())), + Err(_) => break, + }; + + let counter_delta = input.try(|input| Integer::parse(context, input)) + .unwrap_or(Integer::new(default_value)); + counters.push((counter_name, counter_delta)) + } + + if !counters.is_empty() { + Ok(CounterIntegerList::new(counters)) + } else { + Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + } + } +} + +/// A specified value for the `counter-increment` property. +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] +#[derive(Clone, Debug, PartialEq, ToCss)] +pub struct CounterIncrement(pub SpecifiedIntegerList); + +impl CounterIncrement { + /// Returns a new specified `counter-increment` object with the given values. + pub fn new(vec: Vec<(CustomIdent, Integer)>) -> CounterIncrement { + CounterIncrement(SpecifiedIntegerList::new(vec)) + } + + /// Returns the values of the specified `counter-increment` object. + pub fn get_values(&self) -> &[(CustomIdent, Integer)] { + self.0.get_values() + } +} + +impl Parse for CounterIncrement { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't> + ) -> Result> { + Ok(CounterIncrement(SpecifiedIntegerList::parse_with_default(context, input, 1)?)) + } +} + +/// A specified value for the `counter-reset` property. +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] +#[derive(Clone, Debug, PartialEq, ToCss)] +pub struct CounterReset(pub SpecifiedIntegerList); + +impl CounterReset { + /// Returns a new specified `counter-reset` object with the given values. + pub fn new(vec: Vec<(CustomIdent, Integer)>) -> CounterReset { + CounterReset(SpecifiedIntegerList::new(vec)) + } + + /// Returns the values of the specified `counter-reset` object. + pub fn get_values(&self) -> &[(CustomIdent, Integer)] { + self.0.get_values() + } +} + +impl Parse for CounterReset { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't> + ) -> Result> { + Ok(CounterReset(SpecifiedIntegerList::parse_with_default(context, input, 0)?)) + } +} diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 57db9bcfca5..2bf322922d5 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -40,6 +40,7 @@ pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, pub use self::box_::{AnimationIterationCount, AnimationName, Display, OverscrollBehavior, Contain}; pub use self::box_::{OverflowClipBox, ScrollSnapType, TouchAction, VerticalAlign, WillChange}; pub use self::color::{Color, ColorPropertyValue, RGBAColor}; +pub use self::counters::{CounterIncrement, CounterReset}; pub use self::effects::{BoxShadow, Filter, SimpleShadow}; pub use self::flex::FlexBasis; #[cfg(feature = "gecko")] @@ -85,6 +86,7 @@ pub mod border; pub mod box_; pub mod calc; pub mod color; +pub mod counters; pub mod effects; pub mod flex; pub mod font; diff --git a/tests/unit/style/properties/serialization.rs b/tests/unit/style/properties/serialization.rs index 282051d8779..89ab8c8ea6d 100644 --- a/tests/unit/style/properties/serialization.rs +++ b/tests/unit/style/properties/serialization.rs @@ -1027,7 +1027,7 @@ mod shorthand_serialization { properties.push((CustomIdent("counter1".into()), Integer::new(1))); properties.push((CustomIdent("counter2".into()), Integer::new(-4))); - let counter_increment = CounterIncrement(properties); + let counter_increment = CounterIncrement::new(properties); let counter_increment_css = "counter1 1 counter2 -4"; assert_eq!(counter_increment.to_css_string(), counter_increment_css); @@ -1035,7 +1035,7 @@ mod shorthand_serialization { #[test] fn counter_increment_without_properties_should_serialize_correctly() { - let counter_increment = CounterIncrement(Vec::new()); + let counter_increment = CounterIncrement::new(Vec::new()); let counter_increment_css = "none"; assert_eq!(counter_increment.to_css_string(), counter_increment_css);