mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
style: [css-lists] Style system changes to support 'reversed(<counter-name>)'
Differential Revision: https://phabricator.services.mozilla.com/D129955
This commit is contained in:
parent
53b657e97b
commit
82c0673881
6 changed files with 141 additions and 29 deletions
|
@ -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",
|
||||||
|
|
|
@ -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>;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue