Skip to content

Commit 0ab0e71

Browse files
author
Swarup Ukil
committed
Bug 1998245 - Implement support for <number> and <attr-unit>. r=emilio,firefox-style-system-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D277823
1 parent 99b0d82 commit 0ab0e71

File tree

13 files changed

+144
-151
lines changed

13 files changed

+144
-151
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

servo/components/style/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ smallvec = "1.0"
8989
static_assertions = "1.1"
9090
static_prefs = { path = "../../../modules/libpref/init/static_prefs" }
9191
string_cache = { version = "0.8", optional = true }
92+
strum = "0.27"
93+
strum_macros = "0.27"
9294
style_derive = {path = "../style_derive"}
9395
style_traits = {path = "../style_traits"}
9496
to_shmem = {path = "../to_shmem"}

servo/components/style/custom_properties.rs

Lines changed: 90 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use crate::selector_map::{PrecomputedHashMap, PrecomputedHashSet};
2727
use crate::stylesheets::UrlExtraData;
2828
use crate::stylist::Stylist;
2929
use crate::values::computed::{self, ToComputedValue};
30+
use crate::values::generics::calc::SortKey as AttrUnit;
3031
use crate::values::specified::FontRelativeLength;
3132
use crate::values::AtomIdent;
3233
use crate::Atom;
@@ -476,8 +477,9 @@ enum SubstitutionFunctionKind {
476477
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem, Parse)]
477478
enum AttributeType {
478479
None,
480+
RawString,
479481
Type(Descriptor),
480-
Unit,
482+
Unit(AttrUnit),
481483
}
482484

483485
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
@@ -841,18 +843,12 @@ fn parse_declaration_value_block<'i, 't>(
841843
name.as_ref()
842844
});
843845

844-
let mut attribute_syntax = AttributeType::None;
845-
if substitution_kind == SubstitutionFunctionKind::Attr
846-
&& input
847-
.try_parse(|input| input.expect_function_matching("type"))
848-
.is_ok()
849-
{
850-
// TODO(descalante): determine what to do for `type(garbage)` bug 2006626
851-
attribute_syntax = input
852-
.parse_nested_block(Descriptor::from_css_parser)
853-
.ok()
854-
.map_or(AttributeType::None, AttributeType::Type);
855-
}
846+
let attribute_syntax =
847+
if substitution_kind == SubstitutionFunctionKind::Attr {
848+
parse_attr_type(input)
849+
} else {
850+
AttributeType::None
851+
};
856852

857853
// We want the order of the references to match source order. So we need to reserve our slot
858854
// now, _before_ parsing our fallback. Note that we don't care if parsing fails after all, since
@@ -972,6 +968,32 @@ fn parse_declaration_value_block<'i, 't>(
972968
Ok((first_token_type, last_token_type))
973969
}
974970

971+
/// Parse <attr-type> = type( <syntax> ) | raw-string | number | <attr-unit>.
972+
/// https://drafts.csswg.org/css-values-5/#attr-notation
973+
fn parse_attr_type<'i, 't>(input: &mut Parser<'i, 't>) -> AttributeType {
974+
input
975+
.try_parse(|input| {
976+
Ok(match input.next()? {
977+
Token::Function(ref name) if name.eq_ignore_ascii_case("type") => {
978+
AttributeType::Type(input.parse_nested_block(Descriptor::from_css_parser)?)
979+
},
980+
Token::Ident(ref ident) => {
981+
if ident.eq_ignore_ascii_case("raw-string") {
982+
AttributeType::RawString
983+
} else {
984+
let unit = AttrUnit::from_ident(ident).map_err(|_| {
985+
input.new_custom_error(StyleParseErrorKind::UnspecifiedError)
986+
})?;
987+
AttributeType::Unit(unit)
988+
}
989+
},
990+
Token::Delim('%') => AttributeType::Unit(AttrUnit::Percentage),
991+
_ => return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
992+
})
993+
})
994+
.unwrap_or(AttributeType::None)
995+
}
996+
975997
/// A struct that takes care of encapsulating the cascade process for custom properties.
976998
pub struct CustomPropertiesBuilder<'a, 'b: 'a> {
977999
seen: PrecomputedHashSet<&'a Name>,
@@ -2149,6 +2171,13 @@ fn substitute_one_reference<'a>(
21492171
references: &mut std::iter::Peekable<std::slice::Iter<SubstitutionFunctionReference>>,
21502172
attr_provider: &dyn AttributeProvider,
21512173
) -> Result<Substitution<'a>, ()> {
2174+
let simple_subst = |s: &str| {
2175+
Some(Substitution::new(
2176+
Cow::Owned(quoted_css_string(s)),
2177+
TokenSerializationType::Nothing,
2178+
TokenSerializationType::Nothing,
2179+
))
2180+
};
21522181
let substitution: Option<_> = match reference.substitution_kind {
21532182
SubstitutionFunctionKind::Var => {
21542183
let registration = stylist.get_custom_property_registration(&reference.name);
@@ -2163,27 +2192,56 @@ fn substitute_one_reference<'a>(
21632192
.get(&reference.name, device, url_data)
21642193
.map(Substitution::from_value)
21652194
},
2195+
// https://drafts.csswg.org/css-values-5/#attr-substitution
21662196
SubstitutionFunctionKind::Attr => attr_provider
21672197
.get_attr(AtomIdent::cast(&reference.name))
2168-
.and_then(|attr| {
2169-
let AttributeType::Type(syntax) = &reference.attribute_syntax else {
2170-
return Some(Substitution::new(
2171-
Cow::Owned(quoted_css_string(&attr)),
2172-
TokenSerializationType::Nothing,
2173-
TokenSerializationType::Nothing,
2174-
));
2175-
};
2176-
let mut input = ParserInput::new(&attr);
2177-
let mut parser = Parser::new(&mut input);
2178-
let value = SpecifiedRegisteredValue::parse(
2179-
&mut parser,
2180-
syntax,
2181-
url_data,
2182-
AllowComputationallyDependent::Yes,
2183-
)
2184-
.ok()?;
2185-
Some(Substitution::from_value(value.to_variable_value()))
2186-
}),
2198+
.map_or_else(
2199+
|| {
2200+
// Special case when fallback and <attr-type> are omitted.
2201+
// See FAILURE: https://drafts.csswg.org/css-values-5/#attr-substitution
2202+
if reference.fallback.is_none()
2203+
&& reference.attribute_syntax == AttributeType::None
2204+
{
2205+
simple_subst("")
2206+
} else {
2207+
None
2208+
}
2209+
},
2210+
|attr| {
2211+
let mut input = ParserInput::new(&attr);
2212+
let mut parser = Parser::new(&mut input);
2213+
match &reference.attribute_syntax {
2214+
AttributeType::Unit(unit) => {
2215+
let css = {
2216+
// Verify that attribute data is a <number-token>.
2217+
parser.expect_number().ok()?;
2218+
let mut s = attr.clone();
2219+
s.push_str(unit.as_ref());
2220+
s
2221+
};
2222+
let serialization = match unit {
2223+
AttrUnit::Number => TokenSerializationType::Number,
2224+
AttrUnit::Percentage => TokenSerializationType::Percentage,
2225+
_ => TokenSerializationType::Dimension,
2226+
};
2227+
let value =
2228+
ComputedValue::new(css, url_data, serialization, serialization);
2229+
Some(Substitution::from_value(value))
2230+
},
2231+
AttributeType::Type(syntax) => {
2232+
let value = SpecifiedRegisteredValue::parse(
2233+
&mut parser,
2234+
syntax,
2235+
url_data,
2236+
AllowComputationallyDependent::Yes,
2237+
)
2238+
.ok()?;
2239+
Some(Substitution::from_value(value.to_variable_value()))
2240+
},
2241+
AttributeType::RawString | AttributeType::None => simple_subst(&attr),
2242+
}
2243+
},
2244+
),
21872245
};
21882246

21892247
if let Some(s) = substitution {

servo/components/style/properties_and_values/syntax/mod.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,19 @@ impl Descriptor {
5858
/// https://drafts.csswg.org/css-values-5/#typedef-syntax
5959
#[inline]
6060
pub fn from_css_parser<'i>(input: &mut CSSParser<'i, '_>) -> Result<Self, StyleParseError<'i>> {
61-
//TODO(bug 2006624): Should also accept <syntax-string>
6261
let mut components = vec![];
62+
63+
if input.try_parse(|i| i.expect_delim('*')).is_ok() {
64+
return Ok(Self::universal());
65+
}
66+
67+
// Parse <syntax-string> if given.
68+
if let Ok(syntax_string) = input.try_parse(|i| i.expect_string_cloned()) {
69+
return Self::from_str(syntax_string.as_ref(), /* save_specified = */ true).or_else(
70+
|err| Err(input.new_custom_error(StyleParseErrorKind::PropertySyntaxField(err))),
71+
);
72+
}
73+
6374
loop {
6475
let name = Self::try_parse_component_name(input).map_err(|err| {
6576
input.new_custom_error(StyleParseErrorKind::PropertySyntaxField(err))

servo/components/style/values/generics/calc.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ use crate::values::generics::length::GenericAnchorSizeFunction;
1111
use crate::values::generics::position::{GenericAnchorFunction, GenericAnchorSide};
1212
use num_traits::Zero;
1313
use smallvec::SmallVec;
14+
use std::convert::AsRef;
1415
use std::fmt::{self, Write};
1516
use std::ops::{Add, Mul, Neg, Rem, Sub};
1617
use std::{cmp, mem};
18+
use strum_macros::AsRefStr;
1719
use style_traits::{CssWriter, NumericValue, ToCss, ToTyped, TypedValue};
1820

1921
use thin_vec::ThinVec;
@@ -116,10 +118,16 @@ pub enum RoundingStrategy {
116118
/// This determines the order in which we serialize members of a calc() sum.
117119
///
118120
/// See https://drafts.csswg.org/css-values-4/#sort-a-calculations-children
119-
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
121+
#[derive(
122+
AsRefStr, Clone, Copy, Debug, Eq, Ord, Parse, PartialEq, PartialOrd, MallocSizeOf, ToShmem,
123+
)]
124+
#[strum(serialize_all = "lowercase")]
120125
#[allow(missing_docs)]
121126
pub enum SortKey {
127+
#[strum(serialize = "")]
122128
Number,
129+
#[css(skip)]
130+
#[strum(serialize = "%")]
123131
Percentage,
124132
Cap,
125133
Ch,
@@ -147,14 +155,15 @@ pub enum SortKey {
147155
Lvmax,
148156
Lvmin,
149157
Lvw,
158+
Ms,
150159
Px,
151160
Rcap,
152161
Rch,
153162
Rem,
154163
Rex,
155164
Ric,
156165
Rlh,
157-
Sec,
166+
S, // Sec
158167
Svb,
159168
Svh,
160169
Svi,
@@ -167,7 +176,9 @@ pub enum SortKey {
167176
Vmax,
168177
Vmin,
169178
Vw,
179+
#[css(skip)]
170180
ColorComponent,
181+
#[css(skip)]
171182
Other,
172183
}
173184

servo/components/style/values/specified/calc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ impl generic::CalcNodeLeaf for Leaf {
306306
match *self {
307307
Self::Number(..) => SortKey::Number,
308308
Self::Percentage(..) => SortKey::Percentage,
309-
Self::Time(..) => SortKey::Sec,
309+
Self::Time(..) => SortKey::S,
310310
Self::Resolution(..) => SortKey::Dppx,
311311
Self::Angle(..) => SortKey::Deg,
312312
Self::Length(ref l) => match *l {

servo/components/style/values/specified/counters.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ impl Parse for Content {
226226
let style = Content::parse_counter_style(context, input);
227227
Ok(generics::ContentItem::Counters(name, separator, style))
228228
}),
229-
"attr" => input.parse_nested_block(|input| {
229+
"attr" if !static_prefs::pref!("layout.css.attr.enabled") => input.parse_nested_block(|input| {
230230
Ok(generics::ContentItem::Attr(Attr::parse_function(context, input)?))
231231
}),
232232
_ => {
Lines changed: 5 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,15 @@
11
[attr-all-types.html]
2-
[CSS Values and Units Test: attr]
3-
expected: FAIL
4-
5-
[CSS Values and Units Test: attr 2]
6-
expected: FAIL
7-
8-
[CSS Values and Units Test: attr 3]
9-
expected: FAIL
10-
11-
[CSS Values and Units Test: attr 6]
12-
expected: FAIL
13-
14-
[CSS Values and Units Test: attr 7]
15-
expected: FAIL
16-
17-
[CSS Values and Units Test: attr 11]
18-
expected: FAIL
19-
20-
[CSS Values and Units Test: attr 55]
21-
expected: FAIL
22-
23-
[CSS Values and Units Test: attr 56]
24-
expected: FAIL
25-
26-
[CSS Values and Units Test: attr 57]
27-
expected: FAIL
28-
29-
[CSS Values and Units Test: attr 58]
30-
expected: FAIL
31-
32-
[CSS Values and Units Test: attr 59]
33-
expected: FAIL
34-
35-
[CSS Values and Units Test: attr 63]
36-
expected: FAIL
37-
38-
[CSS Values and Units Test: attr 64]
39-
expected: FAIL
40-
41-
[CSS Values and Units Test: attr 66]
42-
expected: FAIL
43-
44-
[CSS Values and Units Test: attr 68]
45-
expected: FAIL
46-
47-
[CSS Values and Units Test: attr 70]
48-
expected: FAIL
49-
50-
[CSS Values and Units Test: attr 72]
51-
expected: FAIL
52-
532
[CSS Values and Units Test: attr 74]
543
expected: FAIL
55-
56-
[CSS Values and Units Test: attr 76]
57-
expected: FAIL
58-
59-
[CSS Values and Units Test: attr 78]
60-
expected: FAIL
61-
62-
[CSS Values and Units Test: attr 80]
63-
expected: FAIL
64-
65-
[CSS Values and Units Test: attr 82]
66-
expected: FAIL
67-
68-
[CSS Values and Units Test: attr 84]
69-
expected: FAIL
70-
71-
[CSS Values and Units Test: attr 86]
72-
expected: FAIL
73-
74-
[CSS Values and Units Test: attr 88]
75-
expected: FAIL
76-
77-
[CSS Values and Units Test: attr 90]
78-
expected: FAIL
79-
80-
[CSS Values and Units Test: attr 92]
81-
expected: FAIL
82-
83-
[CSS Values and Units Test: attr 94]
84-
expected: FAIL
85-
86-
[CSS Values and Units Test: attr 96]
87-
expected: FAIL
88-
89-
[CSS Values and Units Test: attr 108]
90-
expected: FAIL
91-
92-
[CSS Values and Units Test: attr 1]
93-
expected: FAIL
94-
95-
[CSS Values and Units Test: attr 12]
96-
expected: FAIL
97-
98-
[CSS Values and Units Test: attr 65]
4+
5+
[CSS Values and Units Test: attr 75]
996
expected: FAIL
1007

101-
[CSS Values and Units Test: attr 98]
8+
[CSS Values and Units Test: attr 76]
1029
expected: FAIL
10310

104-
[CSS Values and Units Test: attr 110]
11+
[CSS Values and Units Test: attr 77]
10512
expected: FAIL
10613

107-
[CSS Values and Units Test: attr 69]
14+
[CSS Values and Units Test: attr 79]
10815
expected: FAIL

0 commit comments

Comments
 (0)