RESOLVED FIXED 236199
[css-logical] changing the writing-mode via a CSS variable does not update the physical properties
https://bugs.webkit.org/show_bug.cgi?id=236199
Summary [css-logical] changing the writing-mode via a CSS variable does not update th...
Antoine Quint
Reported 2022-02-06 06:23:22 PST
Created attachment 451039 [details] Test The attached test checks that changing the writing-mode via a CSS variable correctly updates the physical properties when using a logical property to set their value. Alas, we fail to do that correctly. This costs us a unique failure in the WPT test css/css-logical/animation-004.html since we fail to update CSS transitions as values in the before and after computed styles are the same (once the fix for bug 236197 is applied). Not using a CSS variable makes everything work as expected.
Attachments
Test (1.05 KB, text/html)
2022-02-06 06:23 PST, Antoine Quint
no flags
Patch (18.20 KB, patch)
2022-02-07 09:32 PST, Oriol Brufau
no flags
Patch (25.37 KB, patch)
2022-02-07 16:28 PST, Oriol Brufau
no flags
Patch (27.55 KB, patch)
2022-03-16 10:40 PDT, Oriol Brufau
no flags
Patch (27.55 KB, patch)
2022-03-16 10:44 PDT, Oriol Brufau
no flags
Patch for EWS (39.37 KB, patch)
2022-03-16 10:45 PDT, Oriol Brufau
ews-feeder: commit-queue-
Patch for EWS (49.75 KB, patch)
2022-03-17 18:39 PDT, Oriol Brufau
no flags
Patch (27.50 KB, patch)
2022-03-17 19:32 PDT, Oriol Brufau
no flags
Patch for EWS (52.19 KB, patch)
2022-03-17 19:33 PDT, Oriol Brufau
no flags
Patch (27.55 KB, patch)
2022-03-20 07:47 PDT, Oriol Brufau
no flags
Patch for EWS (65.86 KB, patch)
2022-04-25 12:54 PDT, Oriol Brufau
no flags
Patch (25.15 KB, patch)
2022-04-26 19:44 PDT, Oriol Brufau
no flags
Patch (25.07 KB, patch)
2022-04-27 07:37 PDT, Oriol Brufau
no flags
Patch (25.91 KB, patch)
2022-04-27 09:40 PDT, Oriol Brufau
no flags
Antoine Quint
Comment 1 2022-02-06 06:46:06 PST
When PropertyCascade::set() is called we're still resolving CSSPropertyBlockSize to CSSPropertyHeight, not accounting for the change made to the CSS variable changing the value of writing-mode.
Oriol Brufau
Comment 2 2022-02-07 08:24:56 PST
So, this is not related to transitions at all. Test: <div style="--wm: vertical-lr; writing-mode: var(--wm); block-size: 200px; inline-size: 100px; background: cyan"></div> <br> Reference: <div style="height: 100px; width: 200px; background: cyan"></div> The test is 200px tall and 100px wide, it should be the opposite. The current behavior isn't only problematic with variables, e.g. <div style="writing-mode: vertical-lr"> <div style="writing-mode: initial; block-size: 100px; inline-size: 200px; background: cyan"></div> </div> I think I already have a patch.
Antoine Quint
Comment 3 2022-02-07 08:30:22 PST
(In reply to Oriol Brufau from comment #2) > So, this is not related to transitions at all. That's right, I only found out about it while looking at a transition issue. If you find a fix, please make sure it also fixes the remaining failure in css/css-logical/animation-004.html.
Oriol Brufau
Comment 4 2022-02-07 09:32:45 PST
EWS Watchlist
Comment 5 2022-02-07 09:38:04 PST
This patch modifies the imported WPT tests. Please ensure that any changes on the tests (not coming from a WPT import) are exported to WPT. Please see https://trac.webkit.org/wiki/WPTExportProcess
Oriol Brufau
Comment 6 2022-02-07 16:28:33 PST
Oriol Brufau
Comment 7 2022-02-07 16:42:15 PST
This patch avoids failing logical-border-props-with-variables.html and some asserts. But tests related to `revert` still fail, that's because of bug 236272. I don't know enough of how the cascade is implemented in WebKit to fix that one.
Radar WebKit Bug Importer
Comment 8 2022-02-13 06:24:15 PST
Oriol Brufau
Comment 9 2022-03-16 10:40:37 PDT
Oriol Brufau
Comment 10 2022-03-16 10:44:04 PDT
Oriol Brufau
Comment 11 2022-03-16 10:45:59 PDT
Created attachment 454863 [details] Patch for EWS
Oriol Brufau
Comment 12 2022-03-17 18:39:35 PDT
Created attachment 455057 [details] Patch for EWS
Oriol Brufau
Comment 13 2022-03-17 19:32:25 PDT
Oriol Brufau
Comment 14 2022-03-17 19:33:40 PDT
Created attachment 455061 [details] Patch for EWS
Antoine Quint
Comment 15 2022-03-18 01:07:13 PDT
There are two ChangeLog entries in your latest patch.
Oriol Brufau
Comment 16 2022-03-18 06:19:28 PDT
(In reply to Antoine Quint from comment #15) > There are two ChangeLog entries in your latest patch. The attachment "Patch" is the actual patch, but it fails fast/css/appearance-apple-pay-button-border-radius.html because of bug 238062. "Patch for EWS" contains the patches for both bugs to ensure that then it works.
Darin Adler
Comment 17 2022-03-20 06:22:43 PDT
Comment on attachment 455060 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=455060&action=review > Source/WebCore/style/StyleBuilder.cpp:271 > + const RenderStyle& style = m_state.style(); auto& > Source/WebCore/style/StyleBuilder.cpp:320 > + const RenderStyle& style = m_state.style(); auto& > Source/WebCore/style/StyleBuilder.cpp:321 > + CSSPropertyID logicalId = CSSProperty::unresolvePhysicalProperty(id, style.direction(), style.writingMode()); auto
Oriol Brufau
Comment 18 2022-03-20 07:47:42 PDT
EWS
Comment 19 2022-03-20 09:39:00 PDT
Committed r291546 (248652@main): <https://commits.webkit.org/248652@main> All reviewed patches have been landed. Closing bug and clearing flags on attachment 455195 [details].
WebKit Commit Bot
Comment 20 2022-03-22 12:16:25 PDT
Re-opened since this is blocked by bug 238218
Darin Adler
Comment 21 2022-03-22 12:59:24 PDT
We’ll have to figure out why this was a significant regression in the Speedometer2/jQuery-TodoMVC test, and find a way to fix this without slowing that down so much.
Oriol Brufau
Comment 22 2022-03-22 13:05:29 PDT
My guess is that the perf regression may be because if you have something like <div style="height: 1px; height: 2px; height: 3px; height: 4px; height: 5px"></div> Previously only 'height: 5px' was applied, but now all declarations are applied one by one. This was already happening for deferred properties, though. It's just that they weren't used much frequently. But my patch turned some frequently used properties into deferred. Possible solution: in PropertyCascade::setDeferred, if m_deferredPropertiesIndices already had the CSSPropertyID, I can get the old index, invalidate the Property entry, and then skip it when applying. Just I guess, though. Let's see if I can reproduce.
Oriol Brufau
Comment 23 2022-03-22 18:53:12 PDT
My guess was on the right track (but the declarations need to be in different rules): <!DOCTYPE html> <style> </style> <div></div> <script> const sheet = document.styleSheets[0]; for (let i=0; i < 3e6; ++i) { sheet.insertRule(`.styled { width: ${i}px }`, i); } const target = document.querySelector("div"); getComputedStyle(target).height; const t = performance.now(); target.className = "styled"; getComputedStyle(target).height; document.body.prepend(performance.now() - t); </script> With my patch, this worsened from ~1600 to ~2000. Invalidating the property if it's already there, and then not applying it, seems to improve things slightly, but not that much. I guess the time is spent populating the huge vector. Something like this does the trick here: @@ -155,7 +155,27 @@ void PropertyCascade::setDeferred(CSSPropertyID id, CSSValue& cssValue, const Ma Property property; memset(property.cssValue, 0, sizeof(property.cssValue)); setPropertyInternal(property, id, cssValue, matchedProperties, cascadeLevel); - m_deferredPropertiesIndices.set(id, m_deferredProperties.size()); + unsigned size = m_deferredProperties.size(); + auto iterator = m_deferredPropertiesIndices.find(id); + if (iterator != m_deferredPropertiesIndices.end()) { + unsigned index = iterator.get()->value; + ASSERT(index < size); + if (index == size - 1) { + m_deferredProperties[index] = property; + return; + } + m_deferredProperties[index].id = CSSPropertyInvalid; + } + m_deferredPropertiesIndices.set(id, size); m_deferredProperties.append(property); } but only addresses a corner case. We could then get a bad case like this: div {width: 0px} div {inline-size: 1px} div {width: 2px} div {inline-size: 3px} div {width: 4px} /* ... */ So I think I should actually entirely change the data structure into something like: HashMap<CSSPropertyID, Property> m_deferredProperties; HashMap<CSSPropertyID, unsigned> m_deferredPropertiesIndices; unsigned m_indexForDeferred; m_indexForDeferred is initially set to 0. Then, PropertyCascade::setDeferred should do something like m_deferredProperties.set(id, property); m_deferredPropertiesIndices.set(id, m_indexForDeferred++); Finally, to apply the properties, auto deferredPropertiesVector = copyToVector(m_deferredProperties.values()); std::sort(deferredPropertiesVector.begin(), deferredPropertiesVector.end(), comp); with a comparator that uses m_deferredPropertiesIndices. May be improved further, e.g. storing in m_properties instead of m_deferredProperties.
Antti Koivisto
Comment 24 2022-03-23 05:41:17 PDT
PropertyCascade is a performance sensitive class. All code changes here need to be carefully evaluated for performance impact. The deferred properties path is clearly not very well optimized. It does heap allocations with a vector and a (recently added) HashMap. Use of this path can't be expanded before it has been made to perform similarly to the main path. It can/should probably use numCSSProperties arrays/bitsets similar to the main path.
Antti Koivisto
Comment 25 2022-03-23 06:35:08 PDT
As far as I see that hashmap is not even used except in the very niche rollback case.
Oriol Brufau
Comment 26 2022-04-25 12:54:51 PDT
Created attachment 458293 [details] Patch for EWS
Oriol Brufau
Comment 27 2022-04-26 19:44:08 PDT
Oriol Brufau
Comment 28 2022-04-27 04:23:27 PDT
Comment on attachment 458413 [details] Patch Darin, I guess you should take a look again, since after the refactorings in other bugs, the patch has had some non-trivial changes. Just the part in Source, LayoutTests is the same as last time.
Antti Koivisto
Comment 29 2022-04-27 04:39:03 PDT
Comment on attachment 458413 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=458413&action=review Nice! > Source/WebCore/style/PropertyCascade.cpp:157 > + CSSPropertyID relatedID; > + if (!CSSProperty::isInLogicalPropertyGroup(propertyID)) > + relatedID = getRelatedPropertyId(propertyID); > + else if (CSSProperty::isDirectionAwareProperty(propertyID)) > + relatedID = CSSProperty::resolveDirectionAwareProperty(propertyID, direction, writingMode); > + else > + relatedID = CSSProperty::unresolvePhysicalProperty(propertyID, direction, writingMode); Would read better as a lambda. > Source/WebCore/style/StyleBuilder.cpp:272 > + auto& style = m_state.style(); > + CSSPropertyID newId = CSSProperty::resolveDirectionAwareProperty(id, style.direction(), style.writingMode()); Maybe either use m_state.style() or cache style to a local on top level of the function (and use it everywhere). > Source/WebCore/style/StyleBuilder.cpp:322 > - } else if (auto* property = rollbackCascade->lastDeferredPropertyResolvingRelated(id)) { > - applyRollbackCascadeProperty(*property, linkMatchMask); > - return; > + } else { > + auto& style = m_state.style(); > + if (auto* property = rollbackCascade->lastDeferredPropertyResolvingRelated(id, style.direction(), style.writingMode())) { Maybe either use m_state.style() or cache style to a local on top level of the function (and use it everywhere).
Oriol Brufau
Comment 30 2022-04-27 07:37:16 PDT
Antti Koivisto
Comment 31 2022-04-27 08:42:53 PDT
Comment on attachment 458444 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=458444&action=review > Source/WebCore/style/PropertyCascade.cpp:151 > + CSSPropertyID relatedID = [&]() { could be auto () is not needed > Source/WebCore/style/StyleBuilder.cpp:269 > + auto& style = m_state.style(); There are some other uses of m_state.style() that can also be replaced.
Oriol Brufau
Comment 32 2022-04-27 09:40:13 PDT
EWS
Comment 33 2022-04-27 15:59:43 PDT
Committed r293543 (250063@main): <https://commits.webkit.org/250063@main> All reviewed patches have been landed. Closing bug and clearing flags on attachment 458454 [details].
Note You need to log in before you can comment on or make changes to this bug.