style: [css-lists] Style system changes to support 'reversed(<counter-name>)'

Differential Revision: https://phabricator.services.mozilla.com/D129955
This commit is contained in:
Mats Palmgren 2023-05-31 11:44:35 +02:00 committed by Oriol Brufau
parent 53b657e97b
commit 82c0673881
6 changed files with 141 additions and 29 deletions

View file

@ -29,7 +29,7 @@ ${helpers.predefined_type(
${helpers.predefined_type( ${helpers.predefined_type(
"counter-reset", "counter-reset",
"CounterSetOrReset", "CounterReset",
engines="gecko servo-2013", engines="gecko servo-2013",
initial_value="Default::default()", initial_value="Default::default()",
animation_value_type="discrete", animation_value_type="discrete",
@ -39,7 +39,7 @@ ${helpers.predefined_type(
${helpers.predefined_type( ${helpers.predefined_type(
"counter-set", "counter-set",
"CounterSetOrReset", "CounterSet",
engines="gecko", engines="gecko",
initial_value="Default::default()", initial_value="Default::default()",
animation_value_type="discrete", animation_value_type="discrete",

View file

@ -7,13 +7,17 @@
use crate::values::computed::image::Image; use crate::values::computed::image::Image;
use crate::values::generics::counters as generics; use crate::values::generics::counters as generics;
use crate::values::generics::counters::CounterIncrement as GenericCounterIncrement; 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. /// A computed value for the `counter-increment` property.
pub type CounterIncrement = GenericCounterIncrement<i32>; pub type CounterIncrement = GenericCounterIncrement<i32>;
/// A computed value for the `counter-set` and `counter-reset` properties. /// A computed value for the `counter-reset` property.
pub type CounterSetOrReset = GenericCounterSetOrReset<i32>; pub type CounterReset = GenericCounterReset<i32>;
/// A computed value for the `counter-set` property.
pub type CounterSet = GenericCounterSet<i32>;
/// A computed value for the `content` property. /// A computed value for the `content` property.
pub type Content = generics::GenericContent<Image>; pub type Content = generics::GenericContent<Image>;

View file

@ -52,7 +52,7 @@ pub use self::box_::{ScrollSnapAlign, ScrollSnapAxis, ScrollSnapStrictness, Scro
pub use self::box_::{TouchAction, VerticalAlign, WillChange}; pub use self::box_::{TouchAction, VerticalAlign, WillChange};
pub use self::color::{Color, ColorOrAuto, ColorPropertyValue, ColorScheme}; pub use self::color::{Color, ColorOrAuto, ColorPropertyValue, ColorScheme};
pub use self::column::ColumnCount; 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::easing::TimingFunction;
pub use self::effects::{BoxShadow, Filter, SimpleShadow}; pub use self::effects::{BoxShadow, Filter, SimpleShadow};
pub use self::flex::FlexBasis; pub use self::flex::FlexBasis;

View file

@ -12,6 +12,8 @@ use crate::values::generics::CounterStyle;
use crate::values::specified::Attr; use crate::values::specified::Attr;
use crate::values::CustomIdent; use crate::values::CustomIdent;
use std::ops::Deref; use std::ops::Deref;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
/// A name / value pair for counters. /// A name / value pair for counters.
#[derive( #[derive(
@ -21,7 +23,6 @@ use std::ops::Deref;
PartialEq, PartialEq,
SpecifiedValueInfo, SpecifiedValueInfo,
ToComputedValue, ToComputedValue,
ToCss,
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
@ -31,9 +32,35 @@ pub struct GenericCounterPair<Integer> {
pub name: CustomIdent, pub name: CustomIdent,
/// The value of the counter / increment / etc. /// The value of the counter / increment / etc.
pub value: Integer, 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; pub use self::GenericCounterPair as CounterPair;
impl<Integer> ToCss for CounterPair<Integer>
where
Integer: ToCss + PartialEq<i32>,
{
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> 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. /// A generic value for the `counter-increment` property.
#[derive( #[derive(
Clone, Clone,
@ -48,7 +75,7 @@ pub use self::GenericCounterPair as CounterPair;
ToShmem, ToShmem,
)] )]
#[repr(transparent)] #[repr(transparent)]
pub struct GenericCounterIncrement<I>(pub GenericCounters<I>); pub struct GenericCounterIncrement<I>(#[css(field_bound)] pub GenericCounters<I>);
pub use self::GenericCounterIncrement as CounterIncrement; pub use self::GenericCounterIncrement as CounterIncrement;
impl<I> CounterIncrement<I> { impl<I> CounterIncrement<I> {
@ -68,7 +95,7 @@ impl<I> Deref for CounterIncrement<I> {
} }
} }
/// A generic value for the `counter-set` and `counter-reset` properties. /// A generic value for the `counter-set` property.
#[derive( #[derive(
Clone, Clone,
Debug, Debug,
@ -82,18 +109,52 @@ impl<I> Deref for CounterIncrement<I> {
ToShmem, ToShmem,
)] )]
#[repr(transparent)] #[repr(transparent)]
pub struct GenericCounterSetOrReset<I>(pub GenericCounters<I>); pub struct GenericCounterSet<I>(#[css(field_bound)] pub GenericCounters<I>);
pub use self::GenericCounterSetOrReset as CounterSetOrReset; pub use self::GenericCounterSet as CounterSet;
impl<I> CounterSetOrReset<I> { impl<I> CounterSet<I> {
/// Returns a new value for `counter-set` / `counter-reset`. /// Returns a new value for `counter-set`.
#[inline] #[inline]
pub fn new(counters: Vec<CounterPair<I>>) -> Self { pub fn new(counters: Vec<CounterPair<I>>) -> Self {
CounterSetOrReset(Counters(counters.into())) CounterSet(Counters(counters.into()))
} }
} }
impl<I> Deref for CounterSetOrReset<I> { impl<I> Deref for CounterSet<I> {
type Target = [CounterPair<I>];
#[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<I>(#[css(field_bound)] pub GenericCounters<I>);
pub use self::GenericCounterReset as CounterReset;
impl<I> CounterReset<I> {
/// Returns a new value for `counter-reset`.
#[inline]
pub fn new(counters: Vec<CounterPair<I>>) -> Self {
CounterReset(Counters(counters.into()))
}
}
impl<I> Deref for CounterReset<I> {
type Target = [CounterPair<I>]; type Target = [CounterPair<I>];
#[inline] #[inline]
@ -119,7 +180,9 @@ impl<I> Deref for CounterSetOrReset<I> {
)] )]
#[repr(transparent)] #[repr(transparent)]
pub struct GenericCounters<I>( pub struct GenericCounters<I>(
#[css(iterable, if_empty = "none")] crate::OwnedSlice<GenericCounterPair<I>>, #[css(field_bound)]
#[css(iterable, if_empty = "none")]
crate::OwnedSlice<GenericCounterPair<I>>,
); );
pub use self::GenericCounters as Counters; pub use self::GenericCounters as Counters;

View file

@ -21,6 +21,18 @@ use cssparser::{Parser, Token};
use selectors::parser::SelectorParseErrorKind; use selectors::parser::SelectorParseErrorKind;
use style_traits::{KeywordsCollectFn, ParseError, SpecifiedValueInfo, StyleParseErrorKind}; 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. /// A specified value for the `counter-increment` property.
pub type CounterIncrement = generics::GenericCounterIncrement<Integer>; pub type CounterIncrement = generics::GenericCounterIncrement<Integer>;
@ -29,26 +41,38 @@ impl Parse for CounterIncrement {
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
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. /// A specified value for the `counter-set` property.
pub type CounterSetOrReset = generics::GenericCounterSetOrReset<Integer>; pub type CounterSet = generics::GenericCounterSet<Integer>;
impl Parse for CounterSetOrReset { impl Parse for CounterSet {
fn parse<'i, 't>( fn parse<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
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<Integer>;
impl Parse for CounterReset {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
Ok(Self::new(parse_counters(context, input, CounterType::Reset)?))
} }
} }
fn parse_counters<'i, 't>( fn parse_counters<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
default_value: i32, counter_type: CounterType,
) -> Result<Vec<CounterPair<Integer>>, ParseError<'i>> { ) -> Result<Vec<CounterPair<Integer>>, ParseError<'i>> {
if input if input
.try_parse(|input| input.expect_ident_matching("none")) .try_parse(|input| input.expect_ident_matching("none"))
@ -60,8 +84,14 @@ fn parse_counters<'i, 't>(
let mut counters = Vec::new(); let mut counters = Vec::new();
loop { loop {
let location = input.current_source_location(); let location = input.current_source_location();
let name = match input.next() { let (name, is_reversed) = match input.next() {
Ok(&Token::Ident(ref ident)) => CustomIdent::from_ident(location, ident, &["none"])?, 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) => { Ok(t) => {
let t = t.clone(); let t = t.clone();
return Err(location.new_unexpected_token_error(t)); return Err(location.new_unexpected_token_error(t));
@ -69,10 +99,19 @@ fn parse_counters<'i, 't>(
Err(_) => break, Err(_) => break,
}; };
let value = input let value = match input.try_parse(|input| Integer::parse(context, input)) {
.try_parse(|input| Integer::parse(context, input)) Ok(start) =>
.unwrap_or(Integer::new(default_value)); if start.value == i32::min_value() {
counters.push(CounterPair { name, 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() { if !counters.is_empty() {

View file

@ -44,7 +44,7 @@ pub use self::box_::{ScrollSnapAlign, ScrollSnapAxis, ScrollSnapStrictness, Scro
pub use self::box_::{TouchAction, TransitionProperty, VerticalAlign, WillChange}; pub use self::box_::{TouchAction, TransitionProperty, VerticalAlign, WillChange};
pub use self::color::{Color, ColorOrAuto, ColorPropertyValue, ColorScheme}; pub use self::color::{Color, ColorOrAuto, ColorPropertyValue, ColorScheme};
pub use self::column::ColumnCount; 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::easing::TimingFunction;
pub use self::effects::{BoxShadow, Filter, SimpleShadow}; pub use self::effects::{BoxShadow, Filter, SimpleShadow};
pub use self::flex::FlexBasis; pub use self::flex::FlexBasis;
@ -577,6 +577,12 @@ impl One for Integer {
} }
} }
impl PartialEq<i32> for Integer {
fn eq(&self, value: &i32) -> bool {
self.value() == *value
}
}
impl Integer { impl Integer {
/// Trivially constructs a new `Integer` value. /// Trivially constructs a new `Integer` value.
pub fn new(val: CSSInteger) -> Self { pub fn new(val: CSSInteger) -> Self {