Bug 1706346 part 1 - [css-lists] Style system changes to support 'reversed(<counter-name>)'. r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D129955
This commit is contained in:
Mats Palmgren 2021-11-14 03:49:35 +00:00
parent e432845f02
commit 2e0a36d04d
12 changed files with 159 additions and 41 deletions

View File

@ -101,7 +101,7 @@ void HTMLSharedListElement::MapOLAttributesIntoRule(
}
}
if (haveStart || haveReversed) {
aDecls.SetCounterResetListItem(start);
aDecls.SetCounterResetListItem(start, haveReversed);
}
}

View File

@ -101,9 +101,10 @@ class MappedDeclarations final {
Servo_DeclarationBlock_SetMathDepthValue(mDecl, aValue, aIsRelative);
}
// Set "counter-reset: list-item <integer>".
void SetCounterResetListItem(int32_t aValue) {
Servo_DeclarationBlock_SetCounterResetListItem(mDecl, aValue);
// Set "counter-reset: list-item <integer>". If aIsReversed is true then
// "list-item" instead becomes "reversed(list-item)".
void SetCounterResetListItem(int32_t aValue, bool aIsReversed) {
Servo_DeclarationBlock_SetCounterResetListItem(mDecl, aValue, aIsReversed);
}
// Set "counter-set: list-item <integer>".

View File

@ -557,7 +557,8 @@ cbindgen-types = [
{ gecko = "StyleVariantAlternatesList", servo = "crate::values::specified::font::VariantAlternatesList" },
{ gecko = "StyleSVGPaintOrder", servo = "crate::values::specified::svg::SVGPaintOrder" },
{ gecko = "StyleClipRectOrAuto", servo = "crate::values::computed::ClipRectOrAuto" },
{ gecko = "StyleCounterSetOrReset", servo = "crate::values::computed::CounterSetOrReset" },
{ gecko = "StyleCounterReset", servo = "crate::values::computed::CounterReset" },
{ gecko = "StyleCounterSet", servo = "crate::values::computed::CounterSet" },
{ gecko = "StyleCounterIncrement", servo = "crate::values::computed::CounterIncrement" },
{ gecko = "StyleContent", servo = "crate::values::computed::counters::Content" },
{ gecko = "StyleSymbolsType", servo = "crate::values::generics::SymbolsType" },

View File

@ -1704,8 +1704,8 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleContent {
mozilla::StyleContent mContent;
mozilla::StyleCounterIncrement mCounterIncrement;
mozilla::StyleCounterSetOrReset mCounterReset;
mozilla::StyleCounterSetOrReset mCounterSet;
mozilla::StyleCounterReset mCounterReset;
mozilla::StyleCounterSet mCounterSet;
};
struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUIReset {

View File

@ -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",

View File

@ -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<i32>;
/// A computed value for the `counter-set` and `counter-reset` properties.
pub type CounterSetOrReset = GenericCounterSetOrReset<i32>;
/// A computed value for the `counter-reset` property.
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.
pub type Content = generics::GenericContent<Image>;

View File

@ -50,7 +50,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;

View File

@ -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<Integer> {
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<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.
#[derive(
Clone,
@ -48,7 +75,7 @@ pub use self::GenericCounterPair as CounterPair;
ToShmem,
)]
#[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;
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(
Clone,
Debug,
@ -82,18 +109,52 @@ impl<I> Deref for CounterIncrement<I> {
ToShmem,
)]
#[repr(transparent)]
pub struct GenericCounterSetOrReset<I>(pub GenericCounters<I>);
pub use self::GenericCounterSetOrReset as CounterSetOrReset;
pub struct GenericCounterSet<I>(#[css(field_bound)] pub GenericCounters<I>);
pub use self::GenericCounterSet as CounterSet;
impl<I> CounterSetOrReset<I> {
/// Returns a new value for `counter-set` / `counter-reset`.
impl<I> CounterSet<I> {
/// Returns a new value for `counter-set`.
#[inline]
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>];
#[inline]
@ -119,7 +180,9 @@ impl<I> Deref for CounterSetOrReset<I> {
)]
#[repr(transparent)]
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;

View File

@ -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<Integer>;
@ -29,26 +41,38 @@ impl Parse for CounterIncrement {
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> 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.
pub type CounterSetOrReset = generics::GenericCounterSetOrReset<Integer>;
/// A specified value for the `counter-set` property.
pub type CounterSet = generics::GenericCounterSet<Integer>;
impl Parse for CounterSetOrReset {
impl Parse for CounterSet {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> 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>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
default_value: i32,
counter_type: CounterType,
) -> Result<Vec<CounterPair<Integer>>, 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() {

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::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<i32> 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 {

View File

@ -202,7 +202,8 @@ include = [
"PaintOrder",
"SVGPaintOrder",
"ClipRectOrAuto",
"CounterSetOrReset",
"CounterReset",
"CounterSet",
"CounterIncrement",
"WritingMode",
"Content",

View File

@ -5089,13 +5089,15 @@ pub extern "C" fn Servo_DeclarationBlock_SetMathDepthValue(
pub extern "C" fn Servo_DeclarationBlock_SetCounterResetListItem(
declarations: &RawServoDeclarationBlock,
counter_value: i32,
is_reversed: bool,
) {
use style::properties::PropertyDeclaration;
use style::values::generics::counters::{CounterPair, CounterSetOrReset};
use style::values::generics::counters::{CounterPair, CounterReset};
let prop = PropertyDeclaration::CounterReset(CounterSetOrReset::new(vec![CounterPair {
let prop = PropertyDeclaration::CounterReset(CounterReset::new(vec![CounterPair {
name: CustomIdent(atom!("list-item")),
value: style::values::specified::Integer::new(counter_value),
is_reversed,
}]));
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(prop, Importance::Normal);
@ -5108,11 +5110,12 @@ pub extern "C" fn Servo_DeclarationBlock_SetCounterSetListItem(
counter_value: i32,
) {
use style::properties::PropertyDeclaration;
use style::values::generics::counters::{CounterPair, CounterSetOrReset};
use style::values::generics::counters::{CounterPair, CounterSet};
let prop = PropertyDeclaration::CounterSet(CounterSetOrReset::new(vec![CounterPair {
let prop = PropertyDeclaration::CounterSet(CounterSet::new(vec![CounterPair {
name: CustomIdent(atom!("list-item")),
value: style::values::specified::Integer::new(counter_value),
is_reversed: false,
}]));
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(prop, Importance::Normal);