Details
- Reviewers
dshin - Group Reviewers
Restricted Project - Commits
- rFIREFOXAUTOLANDb09e47c25222: Bug 2009001 - Support chained references in attr when type() syntax is used.
- Bugzilla Bug ID
- 2009001
Diff Detail
- Repository
- rFIREFOXAUTOLAND firefox-autoland
- Build Status
Buildable 935595 Build 1036746: arc lint + arc unit
Event Timeline
| testing/web-platform/meta/css/css-values/attr-cycle.html.ini | ||
|---|---|---|
| 2 |
This is interesting, because Firefox and Safari are stricter in this regard compared to Chrome, even without attr. e.g.: #foo {
--z: 10px;
--x: var(--y);
--y: var(--z, var(--x));
width: var(--y);
}width will be 10px for Chrome, but not for Safari and Firefox. Glancing at the spec, I don't think it defines one way or the other? EDIT: Ah, this spec discussion seems relevant: https://github.com/w3c/csswg-drafts/issues/11500 | |
| 2 | (Here's the mapping) to the failing tests) | |
| testing/web-platform/meta/css/css-values/attr-cycle.html.ini | ||
|---|---|---|
| 2 |
(FWIW, same should apply for raw-string - we should just be not populating references for these, I'd think) | |
| servo/components/style/custom_properties.rs | ||
|---|---|---|
| 1894 | s/variable/attr/g | |
| servo/components/style/properties/cascade.rs | ||
| 262 | So that concern I don't think should be an issue as long as we handle the"shortcut" cases like we do for variables here and here. Namely - trivial attr() should be already populated, and attr() referencing others should get substituted when it needs to be, because references get processed First-In-Last-Out in the stack here. | |
| servo/components/style/custom_properties.rs | ||
|---|---|---|
| 1335 | comment for linking purposes | |
| servo/components/style/properties/cascade.rs | ||
|---|---|---|
| 258 | @emilio, after discussing with @sukil - <style>
#foo {
width: attr(bar type(*));
}
</style>
<div id=foo bar="attr(baz type(*))" baz="attr(bar type(*))"></div>We have only one non-custom property that does participate in a cycle. | |
| servo/components/style/custom_properties.rs | ||
|---|---|---|
| 503 | Not a huge fan of what seems to be an implementation detail of CustomPropertiesMap leaking out. i.e. IndexMap being used is not known in this source file. | |
| 504 | Isn't this just substitution_functions.size()? | |
| 1836 | Probably is_attr || registration. /*...*/ is fine | |
| testing/web-platform/meta/css/css-values/attr-cycle.html.ini | ||
| 9 | Out of curiosity (Since cycle detection isn't the main objective of this review, bug 1997338 is), what starts failing here? | |
Addressed comments :)
| testing/web-platform/meta/css/css-values/attr-cycle.html.ini | ||
|---|---|---|
| 9 | I added a test to verify that same var and attr names have collision issues. Removing it, for now at least, want to think on that test some more. | |
This seems to make sense, though I need a bit more time to digest. Some style-related nits in the meantime.
| servo/components/style/custom_properties.rs | ||
|---|---|---|
| 478 | Extra whitespace (Linting in general?) | |
| 1175 | Maybe let local_name = if cfg!(feature = "gecko") {/*...*/} else {/*...*/}; | |
| testing/web-platform/tests/css/css-values/attr-all-types.html | ||
| 31 ↗ | (On Diff #1213946) | Any reason for this change? |
| testing/web-platform/tests/css/css-values/attr-all-types.html | ||
|---|---|---|
| 31 ↗ | (On Diff #1213946) | Yes so we were passing the following test for the incorrect reasons because width: 3 isn't valid right? test_valid_attr('width', 'attr(data-foo type(*))', 'attr(data-bar type(<number>), 11)', '3');So width: attr(data-foo type(*)) became approximately width: 1264px and width: 3 became width: 1264px --- which allowed us to pass the test without correctly substituting. |
A few more nits, but overall this makes sense.
Though, we should run mach try perf --rebuild 10 --show-all with 'shippable 'speedometer 'firefox 'windows | 'linux2404 | 'osx1500. As @emilio mentioned, we're touching the hot path, so want to make sure we want to avoid potential immediate post-landing fallout.
| servo/components/style/custom_properties.rs | ||
|---|---|---|
| 491 | Probably should just DOM attributes. | |
| 1171 | Given how it's used, it should probably be Result<(), ()> | |
| 1176 | var() ref uses seen to skip lookup and insertion if the property was already referenced. Maybe worth something similar here. | |
| 1323 | I think this is almost there, maybe should mention why we need specific handling for attr(). | |
| 1611–1613 | can we move this down around line 1579 where custom properties get assigned as well? | |
| 1980 | (Aside, for bug 1997338) It's likely that we will want to extend references_from_non_custom_properties to store names, as well as type (var or attr). Non-custom property references are only significant in the sense that it can loop back to properties in SingleNonCustomReference (Because attr() -> var() -> registered length property -> uses em/lh). | |
| 2173 | Should add comment to the effect of "Short circuit - attr() is always treated as if unregistered" | |
| testing/web-platform/tests/css/css-values/attr-all-types.html | ||
|---|---|---|
| 31 ↗ | (On Diff #1213946) | Er... Yeah, you're right. That is a strange test. |
Addressed nits (few questions)
| servo/components/style/custom_properties.rs | ||
|---|---|---|
| 491 | I've rewritten it to now (hopefully) emphasis that even post CustomPropertiesBuilder::build(), this map could remain incomplete (i.e. attrs using attr-unit are excluded). | |
| 1175 | Had difficulties getting this to work with compiler type mismatch issues. Though mayhaps I was doing some silly stuff. | |
| 1176 | We do have an seen.attr get used in update_attributes_map() to skip seen attrs. In traverse we also check if context.map.get_attr(&next.name).is_none() {...} before calling map_attribute_name_to_value(). Lmk if that sounds sufficient enough. | |
Thanks for your patience. We're pretty close.
BTW, fairly confident that this will conflict with @diegociudadreale's namespace changes, may want to rebase and deal with that right now.
| servo/components/style/custom_properties.rs | ||
|---|---|---|
| 491 | Ah, uh, missed the comment in 1505. Any reason we shouldn't just substitute it right there? It just seems simpler, and this seems like a trip hazard from the caller perspective (It's supposed to contain _Computed_ substitution functions, after all). | |
| 492 | Is there an issue making this OwnMap? Inherited stuff should not be an issue (Because you can't really declare inheriting attrs) | |
| 1175 | Right.. That's fun. You'd think it should still work given one branch gets compiled out.. but oh well | |
| 1176 | Ok, so maybe this function should either return the value Result<ComputedRegisteredValue, ()>, or should use like IndexMap::entry 1, and return if we did a lookup or not. (Note substitution_functions simply being used to insert at the end, which generally tells me "it should just return the value and have the caller handle it") | |
Ok, we're at a good place, but some PerfCompare numbers warranted a bit more scrutiny around iter_declarations - I think we can do a bit better? Should try to run another round of speedometer changes with that.
| servo/components/style/custom_properties.rs | ||
|---|---|---|
| 537 | Flatten, perhaps? | |
| 1362–1372 | I wonder if you can move maybe_note_attr_dependency here - basically: if refs.any_attr {
self.update_attributes_map(attribute_tracker, &v.value.variable_value);
if !refs.any_var {
return;
}
}I think that's logically equivalent, and may quell some of the concerning signs of regression I see on PerfCompare :( | |
Moved maybe_note_attr_dependency and here are the PerfCompare results: https://perf.compare/compare-results?baseRev=dd7959c232877d925207b52c94e8b023f1556b65&baseRepo=try&newRev=97379572675bb140923ed3c7b3b88fbea963d26f&newRepo=try&framework=13
| servo/components/style/custom_properties.rs | ||
|---|---|---|
| 537 | Flatten unfortunately seems not implemented for Option<&Option<T>>, I alternatively used and_then(). | |
FWIW I think now that we dig into the variable value unconditionally, might_have_non_custom_or_attr_dependency makes a lot less sense, since we're basically doing the same checks maybe_note_non_custom_dependency would do...
My guess is that just the Arc<UnparsedValue> dereference there is enough to pollute the cache in that test-case... But it's just a guess really. @dshin have you tried to avoid it (just remove the any_attr check?)
| servo/components/style/custom_properties.rs | ||
|---|---|---|
| 1335 | I don't think this is going to be it, but maybe change this to: if let PropertyDeclaration::WithVariables(v) = decl {
return matches!(id, LonghandId::LineHeight | LonghandId::FontSize) || v.value.variable_value.references.any_attr;
}It should shave a branch in the common case? | |
| servo/components/style/custom_properties_map.rs | ||
|---|---|---|
| 225 | Why can't this be IndexMap<Key, ComputedRegisteredValue, FxBuildHasher>? You only insert Some(..) right? | |
| servo/components/style/custom_properties_map.rs | ||
|---|---|---|
| 225 | Right! We disallow removing elements so we can just directly store ComputedRegisteredValue. | |
| servo/components/style/custom_properties_map.rs | ||
|---|---|---|
| 243 | The extra clone() here is a bit unfortunate btw, would be nice to avoid... | |
| servo/components/style/custom_properties_map.rs | ||
|---|---|---|
| 243 | I was able to address this (TIL & yay for Equivalent trait!), but to no effect :( | |
| servo/components/style/custom_properties_map.rs | ||
|---|---|---|
| 243 | It ends up looking like: #[derive(Clone, Debug, Hash, Eq, PartialEq)]
struct KeyRef<'a>(&'a Name, SubstitutionFunctionKind);
impl<'a> Equivalent<Key> for KeyRef<'a> {
fn equivalent(&self, key: &Key) -> bool {
*self.0 == key.0 && self.1 == key.1
}
}
//...
self.0.get(&KeyRef(name, kind)) | |
| servo/components/style/queries/condition.rs | ||
|---|---|---|
| 412 | Going from inherited customproperties to all substitution functions seem pretty incorrect here. | |
| servo/components/style/queries/condition.rs | ||
|---|---|---|
| 412 |
I guess it doesn't really change behavior because at the point we're handling container queries the builder really only has the inherited properties. But would be good to be explicit and use inherited_custom_properties() + None | |