Bug 217623

Summary: CSSStyleDeclaration breaks JS spec (properties not showing up in Object.getOwnPropertyNames)
Product: WebKit Reporter: Sam Sneddon [:gsnedders] <gsnedders>
Component: CSSAssignee: Sam Weinig <sam>
Status: RESOLVED FIXED    
Severity: Normal CC: alecflett, annulen, beidson, cdumez, commit-queue, darin, emilio, esprehn+autocc, ews-watchlist, glenn, gyuyoung.kim, joepeck, jsbell, koivisto, kondapallykalyan, macpherson, menard, ryuan.choi, sam, sergio, 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=217626
https://bugs.webkit.org/show_bug.cgi?id=217627
https://bugs.webkit.org/show_bug.cgi?id=217622
https://bugs.webkit.org/show_bug.cgi?id=218849
Bug Depends on: 217667, 217776, 218525, 222517, 222518    
Bug Blocks:    
Attachments:
Description Flags
Patch
ews-feeder: commit-queue-
Patch
ews-feeder: commit-queue-
Patch
none
Patch
ews-feeder: commit-queue-
Patch
none
CSSStyleDeclaration+PropertyNames.idl
none
Patch
none
Patch
ews-feeder: commit-queue-
Patch
ews-feeder: commit-queue-
Patch
none
Patch
none
Patch
none
Patch none

Description Sam Sneddon [:gsnedders] 2020-10-12 11:01:43 PDT
> "-webkit-border-before" in document.body.style
< true
> document.body.style.hasOwnProperty("-webkit-border-before")
< true
> Object.keys(document.body.style).indexOf("-webkit-border-before")
< -1
> Object.getOwnPropertyNames(document.body.style).indexOf("-webkit-border-before")
< -1
> Object.getOwnPropertyNames(document.body.style.__proto__).indexOf("-webkit-border-before")
< -1
> Object.getOwnPropertyNames(document.body.style.__proto__.__proto__).indexOf("-webkit-border-before")
< -1

Note that the JS spec says for [[OwnPropertyKeys]] ( ), as an invariant:

> The returned List must contain at least the keys of all non-configurable own properties that have previously been observed.
Comment 1 Sam Weinig 2020-10-12 11:51:27 PDT
This is intertwined with this silly comment I made a few years ago (see https://trac.webkit.org/changeset/219622/webkit) in CSSStyleDeclaration.idl

`
    // Use named getters/setters for all support CSS property names. The spec says
    // these should be normal attributes, but there are too many combinations with
    // prefixes for this to be practical. If we remove legacy aliases, we should
    // reconsider this decision.
    getter (DOMString or double) (DOMString name);
    [CEReactions, CallNamedSetterOnlyForSupportedProperties] setter undefined (DOMString name, [LegacyNullToEmptyString] DOMString value);
`

The easiest (and perhaps best) way to fix this is generate a supplemental IDL file from CSSProperties.json and pass that to the bindings generator using the various rules from https://drafts.csswg.org/cssom/#the-cssstyledeclaration-interface.
Comment 2 Sam Weinig 2020-10-13 18:25:21 PDT Comment hidden (obsolete)
Comment 3 Sam Weinig 2020-10-13 18:57:33 PDT Comment hidden (obsolete)
Comment 4 Sam Weinig 2020-10-13 19:18:59 PDT
Created attachment 411293 [details]
Patch
Comment 5 Sam Sneddon [:gsnedders] 2020-10-14 04:45:33 PDT
"See also"-ing the other bugs that should hopefully be fixed by Sam's rewrite of the bindings code.

Also, Sam, can you review https://github.com/web-platform-tests/wpt/pull/26086 and https://github.com/web-platform-tests/wpt/pull/26082 as part of this? Should probably write a separate test for the Object.keys() issue described above.
Comment 6 Sam Weinig 2020-10-14 10:03:16 PDT
Created attachment 411340 [details]
Patch
Comment 7 Sam Weinig 2020-10-14 10:52:53 PDT
Created attachment 411349 [details]
Patch
Comment 8 Sam Weinig 2020-10-14 12:18:48 PDT
(In reply to Sam Weinig from comment #7)
> Created attachment 411349 [details]
> Patch

Now we are getting somewhere. 1 progression, 7 regressions. Some notes on the failures:

- Got to decide if we want to keep the weird css/pixel/pos prefixed variants.
- We currently support things like "element.style.epubCaptionSide", where epub has a lowercase "e". This seems to be non-standard, with the standard suggesting this should be "element.style.EpubCaptionSide".
- We have at least one test of the iteration order, which is not something is defined for IDL members, so I am not sure we need to maintain that.

Need to look into the rest more closely.
Comment 9 Sam Weinig 2020-10-14 12:19:46 PDT
Created attachment 411363 [details]
CSSStyleDeclaration+PropertyNames.idl

If anyone is interested, here is the generated IDL.
Comment 10 Sam Weinig 2020-10-14 19:30:33 PDT
Created attachment 411395 [details]
Patch
Comment 11 Sam Sneddon [:gsnedders] 2020-10-15 03:13:27 PDT
(In reply to Sam Weinig from comment #8)
> - Got to decide if we want to keep the weird css/pixel/pos prefixed variants.

If it's easy to keep them I think I'd rather do that as a later change (or an earlier change!)?

> - We currently support things like "element.style.epubCaptionSide", where
> epub has a lowercase "e". This seems to be non-standard, with the standard
> suggesting this should be "element.style.EpubCaptionSide".

While Chrome used to expose epubCaptionSide, they seem to only expose "-epub-caption-side" and now? So maybe we can drop epubCaptionSide?

> - We have at least one test of the iteration order, which is not something
> is defined for IDL members, so I am not sure we need to maintain that.

Us and Chrome seem pretty similar in enumeration order today, whereas Firefox seems a bit all over the place. Not sure it matters too much?
Comment 12 Sam Weinig 2020-10-15 10:00:09 PDT
Created attachment 411449 [details]
Patch
Comment 13 Sam Weinig 2020-10-15 10:05:50 PDT
(In reply to Sam Sneddon [:gsnedders] from comment #11)
> (In reply to Sam Weinig from comment #8)
> > - Got to decide if we want to keep the weird css/pixel/pos prefixed variants.
> 
> If it's easy to keep them I think I'd rather do that as a later change (or
> an earlier change!)?

I'm going to definitely keep them for this change but I think we should consider dropping them (it's better to drop them after the refactor as a separate step, since if we have to bring them back, we don't have to figure out how to make them work in the new system later on).

> 
> > - We currently support things like "element.style.epubCaptionSide", where
> > epub has a lowercase "e". This seems to be non-standard, with the standard
> > suggesting this should be "element.style.EpubCaptionSide".
> 
> While Chrome used to expose epubCaptionSide, they seem to only expose
> "-epub-caption-side" and now? So maybe we can drop epubCaptionSide?

Do they expose element.style.EpubCaptionSide (with a capital E)?
Comment 14 Sam Weinig 2020-10-15 10:10:05 PDT
Created attachment 411453 [details]
Patch
Comment 15 Sam Weinig 2020-10-15 10:12:37 PDT
Created attachment 411454 [details]
Patch
Comment 16 Sam Sneddon [:gsnedders] 2020-10-15 10:33:14 PDT
(In reply to Sam Weinig from comment #13)
> (In reply to Sam Sneddon [:gsnedders] from comment #11)
> > (In reply to Sam Weinig from comment #8)
> > > - We currently support things like "element.style.epubCaptionSide", where
> > > epub has a lowercase "e". This seems to be non-standard, with the standard
> > > suggesting this should be "element.style.EpubCaptionSide".
> > 
> > While Chrome used to expose epubCaptionSide, they seem to only expose
> > "-epub-caption-side" and now? So maybe we can drop epubCaptionSide?
> 
> Do they expose element.style.EpubCaptionSide (with a capital E)?

https://wpt.fyi/results/css/css-conditional/js/CSS-supports-CSSStyleDeclaration.html?label=pr_head&max-count=1&pr=26086 shows they only support -epub-caption-side and not EpubCaptionSide. (Plz review the PR!)
Comment 17 Sam Weinig 2020-10-15 11:11:23 PDT
(In reply to Sam Sneddon [:gsnedders] from comment #16)
> (In reply to Sam Weinig from comment #13)
> > (In reply to Sam Sneddon [:gsnedders] from comment #11)
> > > (In reply to Sam Weinig from comment #8)
> > > > - We currently support things like "element.style.epubCaptionSide", where
> > > > epub has a lowercase "e". This seems to be non-standard, with the standard
> > > > suggesting this should be "element.style.EpubCaptionSide".
> > > 
> > > While Chrome used to expose epubCaptionSide, they seem to only expose
> > > "-epub-caption-side" and now? So maybe we can drop epubCaptionSide?
> > 
> > Do they expose element.style.EpubCaptionSide (with a capital E)?
> 
> https://wpt.fyi/results/css/css-conditional/js/CSS-supports-
> CSSStyleDeclaration.html?label=pr_head&max-count=1&pr=26086 shows they only
> support -epub-caption-side and not EpubCaptionSide. (Plz review the PR!)

Hey Sam, I'm not exactly sure what you mean by review the PR. I don't think I am reviewer on that project. Can anyone review things?
Comment 18 Sam Weinig 2020-10-15 12:56:45 PDT
Created attachment 411475 [details]
Patch
Comment 19 Sam Weinig 2020-10-15 13:09:33 PDT
Split out bindings mangling changes into 217776.
Comment 20 Sam Weinig 2020-10-15 13:46:27 PDT
Created attachment 411481 [details]
Patch
Comment 21 Darin Adler 2020-10-15 15:27:42 PDT
Comment on attachment 411481 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=411481&action=review

> Source/WebCore/DerivedSources.make:1422
> +    CSSStyleDeclaration+PropertyNames.idl \

Maybe we should use $(CSS_PROPERTY_NAME_FILES) here to make this rule a little less long.

> Source/WebCore/bindings/scripts/CodeGeneratorJS.pm:3967
> +    return $param if $param =~ /^CSSOM/;

Maybe we should switch to this approach for some of the other prefixes later?

> Source/WebCore/css/CSSStyleDeclaration.cpp:309
> +    String stringValue = WTF::switchOn(value, [&] (const auto& input) {

auto?

> Source/WebCore/css/CSSStyleDeclaration.h:75
> +    ExceptionOr<void> setPropertyValueInternal(CSSPropertyID, String);

How did you decide on String vs. const String& here?

> Source/WebCore/css/CSSStyleDeclaration.h:77
> +    ExceptionOr<void> setPropertyValueInternalForPosOrPixelPrefixed(CSSPropertyID, Variant<double, String>);

How did you decide on Variant vs. const Variant& here?

> LayoutTests/ChangeLog:13
> +        Remove tests for iteration order, which is not standardized, and not consistent among
> +        browsers.

Makes me a little sad; since someone could rely on the order by accident, wouldn’t there be some value in standardizing it, working towards being consistent among browsers some day, and testing that it matches what we propose for the standard?
Comment 22 Sam Sneddon [:gsnedders] 2020-10-15 15:48:36 PDT
(In reply to Darin Adler from comment #21)

> Makes me a little sad; since someone could rely on the order by accident,
> wouldn’t there be some value in standardizing it, working towards being
> consistent among browsers some day, and testing that it matches what we
> propose for the standard?

This is partly covered by https://github.com/heycam/webidl/issues/432 and partly by CSSOM not defining what order the attributes are generated in.
Comment 23 Darin Adler 2020-10-15 16:04:43 PDT
When I say "removing tests makes me a little sad", it’s more than just annoyed that we don’t have order specified, and the risk that posts for interoperability. It’s also that I like tests to help us keep our behavior stable, which does not require that the behavior be specified or standardized. So that part of removing the tests makes me sad too. Standards are very important, but they don’t necessarily constrain what we should test!
Comment 24 Darin Adler 2020-10-15 16:04:57 PDT
posts -> poses
Comment 25 Sam Weinig 2020-10-15 16:12:42 PDT
(In reply to Darin Adler from comment #21)
> Comment on attachment 411481 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=411481&action=review
> 
> > Source/WebCore/DerivedSources.make:1422
> > +    CSSStyleDeclaration+PropertyNames.idl \
> 
> Maybe we should use $(CSS_PROPERTY_NAME_FILES) here to make this rule a
> little less long.

Good idea.

> 
> > Source/WebCore/bindings/scripts/CodeGeneratorJS.pm:3967
> > +    return $param if $param =~ /^CSSOM/;
> 
> Maybe we should switch to this approach for some of the other prefixes later?

Yeah. We need to make this more straightforward.

> 
> > Source/WebCore/css/CSSStyleDeclaration.cpp:309
> > +    String stringValue = WTF::switchOn(value, [&] (const auto& input) {
> 
> auto?

Done.

> 
> > Source/WebCore/css/CSSStyleDeclaration.h:75
> > +    ExceptionOr<void> setPropertyValueInternal(CSSPropertyID, String);
> 
> How did you decide on String vs. const String& here?
> 
> > Source/WebCore/css/CSSStyleDeclaration.h:77
> > +    ExceptionOr<void> setPropertyValueInternalForPosOrPixelPrefixed(CSSPropertyID, Variant<double, String>);
> 
> How did you decide on Variant vs. const Variant& here?

For both of these I don't have a good rule of thumb here. Currently the bindings always WTFMove() into implementation arguments, so it seemed like the right thing to do. But I would love to have a better rule / intuition on this.
Comment 26 Sam Weinig 2020-10-15 16:42:29 PDT
(In reply to Darin Adler from comment #23)
> When I say "removing tests makes me a little sad", it’s more than just
> annoyed that we don’t have order specified, and the risk that posts for
> interoperability. It’s also that I like tests to help us keep our behavior
> stable, which does not require that the behavior be specified or
> standardized. So that part of removing the tests makes me sad too. Standards
> are very important, but they don’t necessarily constrain what we should test!

I've been trying to come up with a way to test iteration order stability for WebKit that isn't a pain. The problem with many of the existing tests has been that each port needed separate results since some properties were enabled and some were not. I think maybe doing based on some of the Internal only interfaces that we expose for WebKitTestRunner might be a good way, as we could make sure to exercise all the variables. 

In this case, port specific properties were actually not the issue (though if I printed them all out it would be). But rather, the tests relied on false assumptions like nothing in the iteration order would sort below the string "0" (that was domListEnumeration.html) or that they should be sorted alphabetically, both because the old implementation explicitly provided a sorted list of properties. Now the implementation is using the same behavior we have for all other IDLs, which is things iterate in the order they are declared in the IDL.
Comment 27 Sam Weinig 2020-10-15 16:48:37 PDT
Created attachment 411509 [details]
Patch
Comment 28 Sam Weinig 2020-10-15 16:50:07 PDT
(In reply to Sam Weinig from comment #25)
> (In reply to Darin Adler from comment #21)
> > Comment on attachment 411481 [details]
> > Patch
> > 
> > View in context:
> > https://bugs.webkit.org/attachment.cgi?id=411481&action=review
> > 
> > > Source/WebCore/DerivedSources.make:1422
> > > +    CSSStyleDeclaration+PropertyNames.idl \
> > 
> > Maybe we should use $(CSS_PROPERTY_NAME_FILES) here to make this rule a
> > little less long.
> 
> Good idea.
> 

I couldn't quite work out how to make this work, my make-fu continues to be less than stellar. Will try to clean it up along with some others that are duplicated though.
Comment 29 EWS 2020-10-15 17:28:21 PDT
Committed r268564: <https://trac.webkit.org/changeset/268564>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 411509 [details].
Comment 30 Radar WebKit Bug Importer 2020-10-15 17:29:20 PDT
<rdar://problem/70359261>
Comment 31 Darin Adler 2020-10-15 17:43:14 PDT
(In reply to Sam Weinig from comment #26)
> things iterate in the order they are declared in the IDL

So our new form of test that should be not too hard to maintain would be a based on a list of property names in the order they should appear *allowing missing properties*. If you agree that a test is still valuable.
Comment 32 Darin Adler 2020-10-16 19:46:01 PDT
I can imagine a type of test where we list things in the order we expect to see them and use a trailing "?" to indicate items that may be omitted without failing the list. Then carefully design the test output so that it is unlikely to require different baselines even if there are some failures as long as they are the same failures.
Comment 33 Alexey Proskuryakov 2020-10-26 09:37:12 PDT
As mentioned on Slack, this change resulted in a substantial build time regression (1 minute for production builds).
Comment 34 Sam Weinig 2020-10-26 10:24:49 PDT
(In reply to Alexey Proskuryakov from comment #33)
> As mentioned on Slack, this change resulted in a substantial build time
> regression (1 minute for production builds).

The regression has been partially addressed by https://trac.webkit.org/changeset/268957/webkit and https://trac.webkit.org/changeset/268962/webkit.

I am waiting for credentials to sync so I can get more data.
Comment 35 Alexey Proskuryakov 2020-11-02 19:23:42 PST
This also made WebCore 9% larger.
Comment 36 WebKit Commit Bot 2020-11-03 10:43:20 PST
Re-opened since this is blocked by bug 218525
Comment 37 Emilio Cobos Álvarez (:emilio) 2021-02-11 10:58:55 PST
Should this reland now that the blocking bug is fixed?
Comment 38 Emilio Cobos Álvarez (:emilio) 2021-02-11 10:59:54 PST
Ah lol, blocking bug was fixed by revert :-)
Comment 39 Sam Weinig 2021-02-27 14:08:05 PST
Filed https://bugs.webkit.org/show_bug.cgi?id=222517, to re-land this change behind an #ifdef to allow iteration on it in the tree without negatively affecting compile time or binary size.

Once landed, we can iterate on reducing the regression and once it is gone, enable it for real.
Comment 40 Sam Weinig 2021-02-27 15:13:44 PST
(In reply to Sam Weinig from comment #39)
> Filed https://bugs.webkit.org/show_bug.cgi?id=222517, to re-land this change
> behind an #ifdef to allow iteration on it in the tree without negatively
> affecting compile time or binary size.
> 
> Once landed, we can iterate on reducing the regression and once it is gone,
> enable it for real.

Will use https://bugs.webkit.org/show_bug.cgi?id=222518 to track finding a solution that does not regress things.
Comment 41 Sam Weinig 2021-04-12 10:43:17 PDT
This is now fixed with <https://commits.webkit.org/236379@main>.