Bug 237175

Summary: [css] text-decoration is not implemented as a shorthand
Product: WebKit Reporter: Oriol Brufau <obrufau>
Component: CSSAssignee: Oriol Brufau <obrufau>
Status: RESOLVED FIXED    
Severity: Normal CC: commit-queue, darin, esprehn+autocc, ews-watchlist, glenn, gyuyoung.kim, joepeck, koivisto, macpherson, menard, mifenton, ntim, simon.fraser, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
See Also: https://bugs.webkit.org/show_bug.cgi?id=230083
Bug Depends on: 237412    
Bug Blocks: 230083, 236272, 237400, 238126    
Attachments:
Description Flags
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch none

Oriol Brufau
Reported 2022-02-24 19:39:03 PST
<!DOCTYPE html> <div>I should have underline</div> <script> var element = document.querySelector("div"); element.style.all = "initial"; element.style.textDecoration = "underline"; </script> The element should be underlined, but it's not! The cause is that 'text-decoration' is not a shorthand of 'text-decoration-color', 'text-decoration-line', etc. So when the 'all' shorthand expands, the longhands appear later. When setting 'text-decoration: underline', it's just updated in place. The longhands still have precedence appearing later, and they are still set to 'initial'.
Attachments
Patch (25.93 KB, patch)
2022-02-25 10:54 PST, Oriol Brufau
no flags
Patch (222.37 KB, patch)
2022-02-26 15:36 PST, Oriol Brufau
no flags
Patch (236.98 KB, patch)
2022-02-28 06:36 PST, Oriol Brufau
no flags
Patch (244.62 KB, patch)
2022-02-28 11:54 PST, Oriol Brufau
no flags
Patch (264.24 KB, patch)
2022-03-02 11:59 PST, Oriol Brufau
no flags
Patch (232.90 KB, patch)
2022-03-03 16:06 PST, Oriol Brufau
no flags
Patch (72.63 KB, patch)
2022-03-07 13:06 PST, Oriol Brufau
no flags
Radar WebKit Bug Importer
Comment 1 2022-02-25 09:56:07 PST
Oriol Brufau
Comment 2 2022-02-25 10:54:08 PST
Oriol Brufau
Comment 3 2022-02-26 15:36:56 PST
Oriol Brufau
Comment 4 2022-02-28 06:36:22 PST
Oriol Brufau
Comment 5 2022-02-28 11:54:43 PST
Oriol Brufau
Comment 6 2022-03-02 05:22:23 PST
Comment on attachment 453413 [details] Patch PTAL. I did some editing changes to preserve test expectations using text-decoration, but not sure if you would prefer just replacing text-decoration with text-decoration-line and keep the logic as-is.
Darin Adler
Comment 7 2022-03-02 08:34:15 PST
Comment on attachment 453413 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=453413&action=review This looks good to me overall. Could use better test coverage for some of the new behaviors and at least one function has gotten noticeably less clear. > Source/WebCore/ChangeLog:28 > + - Use 'text-decoration-line' get getting values. get getting -> when getting > Source/WebCore/css/CSSComputedStyleDeclaration.cpp:3524 > + return nullptr; Is it really OK to just return null in cases like this? Can we add test coverage for this so we can compare behavior with other browser engines for interoperability? > Source/WebCore/css/StyleProperties.cpp:286 > + return String(); What is the impact of returning null string in cases like this? Again can we create test coverage? > Source/WebCore/css/parser/CSSPropertyParser.cpp:6288 > + RefPtr<CSSValue> line = consumeTextDecorationLine(m_range); auto > Source/WebCore/editing/EditingStyle.cpp:602 > + style->setProperty(CSSPropertyTextDecoration, valueList->cssText()); This seems really unfortunate, to be serializing snd then parsing the text form. The rest of this code goes out of its way to use the object model, not text. Presumably for multiple reasons including performance. > Source/WebCore/editing/EditingStyle.cpp:604 > + style->setProperty(CSSPropertyTextDecoration, "none"); Ditto. > Source/WebCore/editing/EditingStyle.cpp:903 > + newInlineStyle->setProperty(CSSPropertyTextDecoration, newValueList->cssText()); Again. > Source/WebCore/editing/EditingStyle.cpp:1467 > void EditingStyle::removeEquivalentProperties(T& style) Disappointing how much more complex the algorithm has become. Worth considering refactoring further to make it easier to understand. > Source/WebCore/editing/markup.cpp:939 > + fullySelectedRootStyle->style()->setProperty(CSSPropertyTextDecoration, "none"); Again.
Oriol Brufau
Comment 8 2022-03-02 09:03:13 PST
Comment on attachment 453413 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=453413&action=review >> Source/WebCore/css/CSSComputedStyleDeclaration.cpp:3524 >> + return nullptr; > > Is it really OK to just return null in cases like this? Can we add test coverage for this so we can compare behavior with other browser engines for interoperability? When a shorthand can't represent the values of it's longhands, it should be serialized as empty string. This is per CSSOM spec: https://drafts.csswg.org/cssom/#serialize-a-css-value «If there is no such shorthand or shorthand cannot exactly represent the values of all the properties in list, return the empty string.» It's just that other browsers obey the text decoration spec, and the text-decoration shorthand accepts values for any of its longhands, so the serialization works. But in WebKit, text-decoration only accepts the same values as text-decoration-line. I thought it would be better to keep the accepted syntax as-is for now, but I can expand it if you prefer. >> Source/WebCore/css/StyleProperties.cpp:286 >> + return String(); > > What is the impact of returning null string in cases like this? Again can we create test coverage? The WPT css/css-text-decor/parsing/text-decoration-valid.html checks that the shorthand can accept and serialize the various longhands. But again, I wanted to minimize the changes so I kept the syntax as-is. So the test continues failing. >> Source/WebCore/editing/EditingStyle.cpp:602 >> + style->setProperty(CSSPropertyTextDecoration, valueList->cssText()); > > This seems really unfortunate, to be serializing snd then parsing the text form. The rest of this code goes out of its way to use the object model, not text. Presumably for multiple reasons including performance. Yes, but when using a CSSValue, shorthands are not expanded into longhands :( If you prefer I can leave the logic as-is, and just get/set/remove CSSPropertyTextDecorationLine instead of CSSPropertyTextDecoration. Then I will need to update various editing test expectations.
Darin Adler
Comment 9 2022-03-02 10:11:53 PST
Comment on attachment 453413 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=453413&action=review >>> Source/WebCore/css/CSSComputedStyleDeclaration.cpp:3524 >>> + return nullptr; >> >> Is it really OK to just return null in cases like this? Can we add test coverage for this so we can compare behavior with other browser engines for interoperability? > > When a shorthand can't represent the values of it's longhands, it should be serialized as empty string. > This is per CSSOM spec: https://drafts.csswg.org/cssom/#serialize-a-css-value > «If there is no such shorthand or shorthand cannot exactly represent the values of all the properties in list, return the empty string.» > > It's just that other browsers obey the text decoration spec, and the text-decoration shorthand accepts values for any of its longhands, so the serialization works. > But in WebKit, text-decoration only accepts the same values as text-decoration-line. > I thought it would be better to keep the accepted syntax as-is for now, but I can expand it if you prefer. That’s fine. We need test coverage for this behavior, even if it’s behavior we plan to fix and improve. >>> Source/WebCore/css/StyleProperties.cpp:286 >>> + return String(); >> >> What is the impact of returning null string in cases like this? Again can we create test coverage? > > The WPT css/css-text-decor/parsing/text-decoration-valid.html checks that the shorthand can accept and serialize the various longhands. > But again, I wanted to minimize the changes so I kept the syntax as-is. So the test continues failing. That’s fine. We need test coverage for this behavior, even if it’s behavior we plan to fix and improve.
Darin Adler
Comment 10 2022-03-02 10:14:06 PST
Comment on attachment 453413 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=453413&action=review >>> Source/WebCore/editing/EditingStyle.cpp:602 >>> + style->setProperty(CSSPropertyTextDecoration, valueList->cssText()); >> >> This seems really unfortunate, to be serializing snd then parsing the text form. The rest of this code goes out of its way to use the object model, not text. Presumably for multiple reasons including performance. > > Yes, but when using a CSSValue, shorthands are not expanded into longhands :( > If you prefer I can leave the logic as-is, and just get/set/remove CSSPropertyTextDecorationLine instead of CSSPropertyTextDecoration. > Then I will need to update various editing test expectations. Is the use of serializing through text the long term strategy here? Or a short term stopgap? I don’t understand why we need to serialize and deserialize to get the effect you describe.
Darin Adler
Comment 11 2022-03-02 10:14:43 PST
Comment on attachment 453413 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=453413&action=review >> Source/WebCore/editing/EditingStyle.cpp:604 >> + style->setProperty(CSSPropertyTextDecoration, "none"); > > Ditto. The way to do this without involving parsing would be to set the four longhands instead of setting the shorthand.
Oriol Brufau
Comment 12 2022-03-02 11:58:35 PST
Comment on attachment 453413 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=453413&action=review >> Source/WebCore/ChangeLog:28 >> + - Use 'text-decoration-line' get getting values. > > get getting -> when getting Done. >>>> Source/WebCore/css/CSSComputedStyleDeclaration.cpp:3524 >>>> + return nullptr; >>> >>> Is it really OK to just return null in cases like this? Can we add test coverage for this so we can compare behavior with other browser engines for interoperability? >> >> When a shorthand can't represent the values of it's longhands, it should be serialized as empty string. >> This is per CSSOM spec: https://drafts.csswg.org/cssom/#serialize-a-css-value >> «If there is no such shorthand or shorthand cannot exactly represent the values of all the properties in list, return the empty string.» >> >> It's just that other browsers obey the text decoration spec, and the text-decoration shorthand accepts values for any of its longhands, so the serialization works. >> But in WebKit, text-decoration only accepts the same values as text-decoration-line. >> I thought it would be better to keep the accepted syntax as-is for now, but I can expand it if you prefer. > > That’s fine. We need test coverage for this behavior, even if it’s behavior we plan to fix and improve. Extended fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-decoration-shorthand.html to check this. >>>> Source/WebCore/css/StyleProperties.cpp:286 >>>> + return String(); >>> >>> What is the impact of returning null string in cases like this? Again can we create test coverage? >> >> The WPT css/css-text-decor/parsing/text-decoration-valid.html checks that the shorthand can accept and serialize the various longhands. >> But again, I wanted to minimize the changes so I kept the syntax as-is. So the test continues failing. > > That’s fine. We need test coverage for this behavior, even if it’s behavior we plan to fix and improve. Extended fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-decoration-shorthand.html to check this. >> Source/WebCore/css/parser/CSSPropertyParser.cpp:6288 >> + RefPtr<CSSValue> line = consumeTextDecorationLine(m_range); > > auto Done. >>>> Source/WebCore/editing/EditingStyle.cpp:602 >>>> + style->setProperty(CSSPropertyTextDecoration, valueList->cssText()); >>> >>> This seems really unfortunate, to be serializing snd then parsing the text form. The rest of this code goes out of its way to use the object model, not text. Presumably for multiple reasons including performance. >> >> Yes, but when using a CSSValue, shorthands are not expanded into longhands :( >> If you prefer I can leave the logic as-is, and just get/set/remove CSSPropertyTextDecorationLine instead of CSSPropertyTextDecoration. >> Then I will need to update various editing test expectations. > > Is the use of serializing through text the long term strategy here? Or a short term stopgap? I don’t understand why we need to serialize and deserialize to get the effect you describe. Changed to setting the 4 longhands. >>> Source/WebCore/editing/EditingStyle.cpp:604 >>> + style->setProperty(CSSPropertyTextDecoration, "none"); >> >> Ditto. > > The way to do this without involving parsing would be to set the four longhands instead of setting the shorthand. Done. >> Source/WebCore/editing/EditingStyle.cpp:903 >> + newInlineStyle->setProperty(CSSPropertyTextDecoration, newValueList->cssText()); > > Again. Changed to setting the 4 longhands. >> Source/WebCore/editing/EditingStyle.cpp:1467 >> void EditingStyle::removeEquivalentProperties(T& style) > > Disappointing how much more complex the algorithm has become. Worth considering refactoring further to make it easier to understand. What refactoring do you have in mind? >> Source/WebCore/editing/markup.cpp:939 >> + fullySelectedRootStyle->style()->setProperty(CSSPropertyTextDecoration, "none"); > > Again. Changed to setting the 4 longhands.
Oriol Brufau
Comment 13 2022-03-02 11:59:26 PST
Darin Adler
Comment 14 2022-03-02 12:07:46 PST
Comment on attachment 453413 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=453413&action=review >>> Source/WebCore/editing/EditingStyle.cpp:1467 >>> void EditingStyle::removeEquivalentProperties(T& style) >> >> Disappointing how much more complex the algorithm has become. Worth considering refactoring further to make it easier to understand. > > What refactoring do you have in mind? Mainly cutting down on loops and making logic more direct. Well, one refactoring would be that since the loop handles each property once, a separate step would be to build a set and then we would iterate the set rather than building the "handle each property only once" into the same loop that does the work. Might need a ListHashSet to preserve the ordering, though. It also seems strange, on reflection, that the loop handles shorthands of they show up after a longhand than if the show up before it, since the shorthands are all added to "alreadyHandled" if you encounter a longhand. Seems like the canRemoveAllLonghands logic could be broken out into a function. With some other fiddling we could make this easier to read. You don’t have to do this, but this was a really simple function before, and I do think decomposing it a bit will make it simpler.
Oriol Brufau
Comment 15 2022-03-02 12:22:11 PST
(In reply to Darin Adler from comment #14) > Comment on attachment 453413 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=453413&action=review > > >>> Source/WebCore/editing/EditingStyle.cpp:1467 > >>> void EditingStyle::removeEquivalentProperties(T& style) > >> > >> Disappointing how much more complex the algorithm has become. Worth considering refactoring further to make it easier to understand. > > > > What refactoring do you have in mind? > > Mainly cutting down on loops and making logic more direct. > > Well, one refactoring would be that since the loop handles each property > once, a separate step would be to build a set and then we would iterate the > set rather than building the "handle each property only once" into the same > loop that does the work. Might need a ListHashSet to preserve the ordering, > though. > > It also seems strange, on reflection, that the loop handles shorthands of > they show up after a longhand than if the show up before it, since the > shorthands are all added to "alreadyHandled" if you encounter a longhand. > > Seems like the canRemoveAllLonghands logic could be broken out into a > function. > > With some other fiddling we could make this easier to read. You don’t have > to do this, but this was a really simple function before, and I do think > decomposing it a bit will make it simpler. Should I file another bug for that?
Darin Adler
Comment 16 2022-03-02 12:31:21 PST
(In reply to Oriol Brufau from comment #15) > Should I file another bug for that? It’s not mandatory, but if you have the time to follow up and improve it a bit I’d welcome that.
EWS
Comment 17 2022-03-02 14:29:45 PST
Committed r290756 (248000@main): <https://commits.webkit.org/248000@main> All reviewed patches have been landed. Closing bug and clearing flags on attachment 453644 [details].
Tim Nguyen (:ntim)
Comment 18 2022-03-02 14:51:36 PST
Bug 230083 was originally filed for this task fwiw, and had a patch on it. Thanks for working on this!
WebKit Commit Bot
Comment 19 2022-03-03 02:06:09 PST
Re-opened since this is blocked by bug 237412
Oriol Brufau
Comment 20 2022-03-03 13:45:29 PST
Testing locally, it seems that making text-decoration be a shorthand of only text-decoration-line doesn't regress perf, so I guess I can try that as a first step, and leave the other longhands for bug 230083.
Darin Adler
Comment 21 2022-03-03 13:50:33 PST
Sounds like a good strategy; I’m sure we’ll find a way to do it all with high performance, too.
Oriol Brufau
Comment 22 2022-03-03 16:06:51 PST
Oriol Brufau
Comment 23 2022-03-07 13:06:48 PST
Oriol Brufau
Comment 24 2022-03-07 13:10:23 PST
Darin, can you confirm if the new patch looks good?
EWS
Comment 25 2022-03-14 12:19:22 PDT
Committed r291244 (248399@main): <https://commits.webkit.org/248399@main> All reviewed patches have been landed. Closing bug and clearing flags on attachment 454019 [details].
Note You need to log in before you can comment on or make changes to this bug.