Bug 23946 - WebKit does not enumerate over CSS properties in HTMLElement.style
Summary: WebKit does not enumerate over CSS properties in HTMLElement.style
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: DOM (show other bugs)
Version: 525.x (Safari 3.2)
Hardware: PC OS X 10.5
: P2 Normal
Assignee: Alexander Pavlov (apavlov)
URL:
Keywords: InRadar
: 37570 (view as bug list)
Depends on:
Blocks:
 
Reported: 2009-02-13 00:31 PST by Lea Verou
Modified: 2011-12-12 07:17 PST (History)
14 users (show)

See Also:


Attachments
Testcase for bug #23946 (819 bytes, text/html)
2009-02-13 00:32 PST, Lea Verou
no flags Details
Patch (11.03 KB, patch)
2011-11-25 05:47 PST, Alexander Pavlov (apavlov)
no flags Details | Formatted Diff | Diff
Patch (11.48 KB, patch)
2011-11-29 01:52 PST, Alexander Pavlov (apavlov)
no flags Details | Formatted Diff | Diff
Patch (13.19 KB, patch)
2011-11-30 05:53 PST, Alexander Pavlov (apavlov)
no flags Details | Formatted Diff | Diff
Patch (13.14 KB, patch)
2011-11-30 23:50 PST, Alexander Pavlov (apavlov)
no flags Details | Formatted Diff | Diff
[PATCH] Implemented Identifier caching (14.11 KB, patch)
2011-12-08 06:20 PST, Alexander Pavlov (apavlov)
no flags Details | Formatted Diff | Diff
[PATCH] Restored property name sorting (14.65 KB, patch)
2011-12-08 07:11 PST, Alexander Pavlov (apavlov)
no flags Details | Formatted Diff | Diff
[PATCH] Update JSC exports to fix compilability on Win and Mac (18.41 KB, patch)
2011-12-09 02:22 PST, Alexander Pavlov (apavlov)
darin: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Lea Verou 2009-02-13 00:31:48 PST
I was surprised that I couldn't find this bug already reported. Anyway, here goes:
Webkit based browsers (like Apple Safari and Google Chrome) do not list the supported CSS properties when enumerating over the style object of an element. They don't even list the CSS properties that have been set.
However, the condition (property in element.style) returns true if the property is supported.
I guess for some reason the CSS properties have the dontEnum flag?

In all non-webkit browsers the test case works as expected.
Comment 1 Lea Verou 2009-02-13 00:32:44 PST
Created attachment 27644 [details]
Testcase for bug #23946
Comment 2 Lea Verou 2009-02-13 01:04:18 PST
Comment on attachment 27644 [details]
Testcase for bug #23946

><!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
><HTML><HEAD>
>
>
><META content="text/html; charset=iso-8859-7" http-equiv="Content-Type"/>
><TITLE>Test case for webkit bug</TITLE>
>
></HEAD><BODY style="border: 3px solid white; padding: 20px; background: beige none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 600px; -moz-border-radius-topleft: 20px; -moz-border-radius-topright: 20px; -moz-border-radius-bottomright: 20px; -moz-border-radius-bottomleft: 20px;" linkifying="true" linkifycurrent="0" linkifymax="0">
><DIV style="overflow: auto; height: 400px;">
><SCRIPT type="text/javascript">
>	for (var i in document.body.style) document.write(i + '&lt;br /&gt;');
></SCRIPT>0<BR/>1<BR/>2<BR/>3<BR/>4<BR/>5<BR/>6<BR/>7<BR/>8<BR/>9<BR/>10<BR/>11<BR/>12<BR/>13<BR/>14<BR/>15<BR/>16<BR/>17<BR/>18<BR/>19<BR/>20<BR/>21<BR/>22<BR/>23<BR/>24<BR/>25<BR/>26<BR/>27<BR/>28<BR/>29<BR/>30<BR/>31<BR/>32<BR/>33<BR/>34<BR/>35<BR/>36<BR/>37<BR/>38<BR/>39<BR/>40<BR/>41<BR/>42<BR/>43<BR/>44<BR/>length<BR/>cssText<BR/>getPropertyValue<BR/>getPropertyCSSValue<BR/>removeProperty<BR/>getPropertyPriority<BR/>setProperty<BR/>item<BR/>parentRule<BR/>azimuth<BR/>background<BR/>backgroundAttachment<BR/>backgroundColor<BR/>backgroundImage<BR/>backgroundPosition<BR/>backgroundRepeat<BR/>border<BR/>borderCollapse<BR/>borderColor<BR/>borderSpacing<BR/>borderStyle<BR/>borderTop<BR/>borderRight<BR/>borderBottom<BR/>borderLeft<BR/>borderTopColor<BR/>borderRightColor<BR/>borderBottomColor<BR/>borderLeftColor<BR/>borderTopStyle<BR/>borderRightStyle<BR/>borderBottomStyle<BR/>borderLeftStyle<BR/>borderTopWidth<BR/>borderRightWidth<BR/>borderBottomWidth<BR/>borderLeftWidth<BR/>borderWidth<BR/>bottom<BR/>captionSide<BR/>clear<BR/>clip<BR/>color<BR/>content<BR/>counterIncrement<BR/>counterReset<BR/>cue<BR/>cueAfter<BR/>cueBefore<BR/>cursor<BR/>direction<BR/>display<BR/>elevation<BR/>emptyCells<BR/>cssFloat<BR/>font<BR/>fontFamily<BR/>fontSize<BR/>fontSizeAdjust<BR/>fontStretch<BR/>fontStyle<BR/>fontVariant<BR/>fontWeight<BR/>height<BR/>left<BR/>letterSpacing<BR/>lineHeight<BR/>listStyle<BR/>listStyleImage<BR/>listStylePosition<BR/>listStyleType<BR/>margin<BR/>marginTop<BR/>marginRight<BR/>marginBottom<BR/>marginLeft<BR/>markerOffset<BR/>marks<BR/>maxHeight<BR/>maxWidth<BR/>minHeight<BR/>minWidth<BR/>orphans<BR/>outline<BR/>outlineColor<BR/>outlineStyle<BR/>outlineWidth<BR/>overflow<BR/>padding<BR/>paddingTop<BR/>paddingRight<BR/>paddingBottom<BR/>paddingLeft<BR/>page<BR/>pageBreakAfter<BR/>pageBreakBefore<BR/>pageBreakInside<BR/>pause<BR/>pauseAfter<BR/>pauseBefore<BR/>pitch<BR/>pitchRange<BR/>position<BR/>quotes<BR/>richness<BR/>right<BR/>size<BR/>speak<BR/>speakHeader<BR/>speakNumeral<BR/>speakPunctuation<BR/>speechRate<BR/>stress<BR/>tableLayout<BR/>textAlign<BR/>textDecoration<BR/>textIndent<BR/>textShadow<BR/>textTransform<BR/>top<BR/>unicodeBidi<BR/>verticalAlign<BR/>visibility<BR/>voiceFamily<BR/>volume<BR/>whiteSpace<BR/>widows<BR/>width<BR/>wordSpacing<BR/>zIndex<BR/>MozAppearance<BR/>MozBackgroundClip<BR/>MozBackgroundInlinePolicy<BR/>MozBackgroundOrigin<BR/>MozBinding<BR/>MozBorderBottomColors<BR/>MozBorderLeftColors<BR/>MozBorderRightColors<BR/>MozBorderTopColors<BR/>MozBorderRadius<BR/>MozBorderRadiusTopleft<BR/>MozBorderRadiusTopright<BR/>MozBorderRadiusBottomleft<BR/>MozBorderRadiusBottomright<BR/>MozBoxAlign<BR/>MozBoxDirection<BR/>MozBoxFlex<BR/>MozBoxOrient<BR/>MozBoxOrdinalGroup<BR/>MozBoxPack<BR/>MozBoxSizing<BR/>MozColumnCount<BR/>MozColumnWidth<BR/>MozColumnGap<BR/>MozFloatEdge<BR/>MozForceBrokenImageIcon<BR/>MozImageRegion<BR/>MozMarginEnd<BR/>MozMarginStart<BR/>MozOpacity<BR/>MozOutline<BR/>MozOutlineColor<BR/>MozOutlineRadius<BR/>MozOutlineRadiusTopleft<BR/>MozOutlineRadiusTopright<BR/>MozOutlineRadiusBottomleft<BR/>MozOutlineRadiusBottomright<BR/>MozOutlineStyle<BR/>MozOutlineWidth<BR/>MozOutlineOffset<BR/>MozPaddingEnd<BR/>MozPaddingStart<BR/>MozUserFocus<BR/>MozUserInput<BR/>MozUserModify<BR/>MozUserSelect<BR/>opacity<BR/>outlineOffset<BR/>overflowX<BR/>overflowY<BR/>imeMode<BR/>MozBorderEnd<BR/>MozBorderEndColor<BR/>MozBorderEndStyle<BR/>MozBorderEndWidth<BR/>MozBorderStart<BR/>MozBorderStartColor<BR/>MozBorderStartStyle<BR/>MozBorderStartWidth<BR/>
></DIV>
><SCRIPT type="text/javascript">
>	document.write("'margin' in document.body.style is " + ('margin' in document.body.style));
></SCRIPT>'margin' in document.body.style is true
></BODY><html:div xmlns:html="http://www.w3.org/1999/xhtml" id="_firebugConsole" style="display: none;" FirebugVersion="1.3X.3b1"/></HTML>
Comment 3 Lea Verou 2009-02-13 01:06:52 PST
Comment on attachment 27644 [details]
Testcase for bug #23946

The script file that is included in the <head> is completely irrelevant with the bug testcase and was just forgotten there by accident. I can't seem to find a way to replace this attachment with a corrected file.
Comment 4 Mark Rowe (bdash) 2009-02-13 01:53:30 PST
<rdar://problem/6584331>
Comment 5 Alexey Proskuryakov 2010-04-16 11:20:32 PDT
*** Bug 37570 has been marked as a duplicate of this bug. ***
Comment 6 Alexander Pavlov (apavlov) 2011-11-25 05:47:30 PST
Created attachment 116607 [details]
Patch
Comment 7 Alexey Proskuryakov 2011-11-28 12:15:06 PST
Comment on attachment 116607 [details]
Patch

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

> Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp:203
> +    for (unsigned i = 0, length = static_cast<CSSStyleDeclaration*>(thisObject->impl())->length(); i < length; ++i)
> +        propertyNames.add(Identifier::from(exec, i));

It would be good to also test that we return these indices here.

> Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp:207
> +    Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
> +
> +    for (int i = 0; i < numCSSProperties; ++i)
> +        propertyNames.add(Identifier(exec, stringToUString(jsPropertyNameStrings[i])));

What tests that base properties and ones from jsPropertyNameStrings come in this order?

> LayoutTests/fast/css/style-enumerate-properties.html:15
> +        for (var p in document.body.style) {
> +            if (p.indexOf("border") === 0)
> +                document.write(p + "<br />");

This test will fail whenever we add another property starting with "border". Please add explicit pass/fail criteria, so that a person looking at failure results wouldn't be confused.
Comment 8 Alexander Pavlov (apavlov) 2011-11-28 20:50:18 PST
(In reply to comment #7)
> (From update of attachment 116607 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=116607&action=review
> 
> > Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp:203
> > +    for (unsigned i = 0, length = static_cast<CSSStyleDeclaration*>(thisObject->impl())->length(); i < length; ++i)
> > +        propertyNames.add(Identifier::from(exec, i));
> 
> It would be good to also test that we return these indices here.

Will do.

> > Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp:207
> > +    Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
> > +
> > +    for (int i = 0; i < numCSSProperties; ++i)
> > +        propertyNames.add(Identifier(exec, stringToUString(jsPropertyNameStrings[i])));
> 
> What tests that base properties and ones from jsPropertyNameStrings come in this order?

I'm afraid I don't quite understand what you mean by "this order". Do you mean that we should test the fact that the proper object properties/methods go first and then the JS property names? AFAIK the specification does not mandate any order on the getOwnPropertyNames() result, so these might as well be swapped without any loss of consistency.

> > LayoutTests/fast/css/style-enumerate-properties.html:15
> > +        for (var p in document.body.style) {
> > +            if (p.indexOf("border") === 0)
> > +                document.write(p + "<br />");
> 
> This test will fail whenever we add another property starting with "border". Please add explicit pass/fail criteria, so that a person looking at failure results wouldn't be confused.

You are correct, I was going to check the full set of properties first, but then came up with the same idea and decided to confine the set to border-related properties. In general, no longhand property list can be considered stable. Do you think it is sufficient to only check the presence of a couple of well-known properties in the style?
Comment 9 Alexey Proskuryakov 2011-11-28 21:04:46 PST
> I'm afraid I don't quite understand what you mean by "this order".

What I mean is: what test will fail is the quoted lined were swapped? We presumably aim to be compatible with Firefox here.

> Do you think it is sufficient to only check the presence of a couple of well-known properties in the style?

I asked to spell out pass/fail criteria in test output (in a <p> element), so that it would be easy to understand why the test "failed" in the future. Checking for ac couple of well-known properties seems fine, too.
Comment 10 Alexander Pavlov (apavlov) 2011-11-29 01:52:12 PST
Created attachment 116923 [details]
Patch
Comment 11 Alexander Pavlov (apavlov) 2011-11-29 03:05:52 PST
(In reply to comment #9)
> > I'm afraid I don't quite understand what you mean by "this order".
> 
> What I mean is: what test will fail is the quoted lined were swapped? We presumably aim to be compatible with Firefox here.

I get the point now. In Firefox, the numeric properties go first, then the CSS-mapped ones, but in no particular ("partially sorted") order, then the rest. I have changed the binding code to follow this.

> > Do you think it is sufficient to only check the presence of a couple of well-known properties in the style?
> 
> I asked to spell out pass/fail criteria in test output (in a <p> element), so that it would be easy to understand why the test "failed" in the future. Checking for ac couple of well-known properties seems fine, too.

Done.
Comment 12 Alexey Proskuryakov 2011-11-29 08:53:19 PST
Looks good to me. One thing I'm slightly surprised about is that a new generated list of names was needed - we certainly do a lot with these property names already. Perhaps someone else CC'ed on this bug could do another review pass.
Comment 13 Darin Adler 2011-11-29 15:47:45 PST
Comment on attachment 116923 [details]
Patch

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

> Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp:202
> +    for (unsigned i = 0, length = static_cast<CSSStyleDeclaration*>(thisObject->impl())->length(); i < length; ++i)

The typecast is not needed here. The result of thisObject->impl() is already a CSSStyleDeclaration. I’m not sure why the generated code included it.

The initialization of length here is not consistent with our usual style. We normally would just do it separately outside the loop. I wonder if we should do this more often, or frown on it.

> Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp:203
> +        propertyNames.add(Identifier::from(exec, i));

This is terribly inefficient, but since it’s the same idiom already used and is also used for JavaScript arrays then I suppose it’s what we want for now at least.

> Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp:206
> +    for (int i = 0; i < numCSSProperties; ++i)
> +        propertyNames.add(Identifier(exec, stringToUString(jsPropertyNameStrings[i])));

These are const char*, not WTF strings, the call to stringToUString can and should omitted. The use of stringToUString forces additional unneeded memory allocation.

Exposing the names in the order they appeared in the CSSPropertyNames.in source file does not seem like a good idea. We should expose them in some order that is consistent and does not reflect the peculiarities of our source code. I would suggest alphabetical order if we can’t think of anything else.

If we actually want this to be efficient we should be creating an array of identifiers one time only and then reusing the same identifiers in the future. Converting from const char* every time doesn’t seem helpful.

> Source/WebCore/bindings/v8/custom/V8CSSStyleDeclarationCustom.cpp:159
> +    // We know that "filter" is present in the list but should not be provided in the enumeration.
> +    // See a comment in the V8CSSStyleDeclaration::namedPropertyGetter() implementation.

I don’t understand why this special rule to omit filter is in V8 but not in the other JavaScript binding, especially considering the comment in namedPropertyGetter implies it is there. I don’t understand why there is no test for it. I suspect this rule about "filter" was removed long ago but was left behind in V8 for not good reason.

> Source/WebCore/css/makeprop.pl:166
> +  $name =~ s/(\S)-(.)/$1@{[uc($2)]}/g;
> +  $name =~ s/^-//;
> +  print HEADER "\"$name\",\n";
> +}
> +print HEADER "};\n";

I think it would be better to not change the contents of this file at all. Instead we could use the existing array of const char* and the first time it’s needed we could build an array of JSC::Identifier one time inside the bindings code and then reuse that each time instead of doing it over and over again.

If we do want to keep this, then I suggest we sort the array here, since we only use it for enumeration and so the order is not important.

I think (.)-(.) would work fine; I don’t think you need the \S there.

> LayoutTests/fast/css/style-enumerate-properties-expected.txt:3
> +Test for https://bugs.webkit.org/show_bug.cgi?id=23946 Webkit does not enumerate over CSS properties in HTMLElement.style - checks that the style contains exactly one numeric property "0" (for "text-decoration") and named properties "textDecoration", "border", "font", and "cssText".
> +
> +PASSED

Tests should show what they are testing, not just say PASSED.

> LayoutTests/fast/css/style-enumerate-properties.html:25
> +          if (!(p in style)) {
> +                console.textContent = "Property '" + p + "' not found!";
> +                return;
> +            }

Better style would be to use the shouldBe macros and do shouldBe for each property so the test output would show what it’s testing.

This test does not cover the order of the properties. It should.

This test does not cover any properties with more then two words in their names, and it should.

> LayoutTests/fast/css/style-enumerate-properties.html:34
> +        Webkit does not enumerate over CSS properties in HTMLElement.style</i> - checks that the style contains exactly one numeric property "0" (for "text-decoration") and named properties "textDecoration", "border", "font", and "cssText".

WebKit has a capital K in its name.

> LayoutTests/fast/dom/script-tests/domListEnumeration.js:176
> +// More properties can be added soon. Plus, Chromium hides the "filter" property.

This comment is more confusing than helpful. It’s not clear how either of these is relevant to the next line of code. I realize that you are justifying the use of >= rather than == for the test, but only because I am reading the whole patch. The comment alone does not make it clear.

> LayoutTests/fast/dom/script-tests/domListEnumeration.js:177
> +shouldBeGreaterThanOrEqual("resultArray.length", "376");

Where did the 376 number come from? Is it right even if SVG is turned off? I think you should just not check the resultArray’s length at all.
Comment 14 Alexander Pavlov (apavlov) 2011-11-30 05:50:40 PST
Thanks for the profound review, Darin. Attaching a fixed patch shortly.

(In reply to comment #13)
> (From update of attachment 116923 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=116923&action=review
> 
> > Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp:202
> > +    for (unsigned i = 0, length = static_cast<CSSStyleDeclaration*>(thisObject->impl())->length(); i < length; ++i)
> 
> The typecast is not needed here. The result of thisObject->impl() is already a CSSStyleDeclaration. I’m not sure why the generated code included it.

Fixed.

> The initialization of length here is not consistent with our usual style. We normally would just do it separately outside the loop. I wonder if we should do this more often, or frown on it.

Initialized length outside the loop for now, yet I'm not sure if the length computation should be extracted into a variable at all, given that usually the length is on the order of hundreds and this method gets invoked relatively rarely.

> > Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp:203
> > +        propertyNames.add(Identifier::from(exec, i));
> 
> This is terribly inefficient, but since it’s the same idiom already used and is also used for JavaScript arrays then I suppose it’s what we want for now at least.

Agreed, and since I'm not that familiar with JSC, I can't think of anything better.

> > Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp:206
> > +    for (int i = 0; i < numCSSProperties; ++i)
> > +        propertyNames.add(Identifier(exec, stringToUString(jsPropertyNameStrings[i])));
> 
> These are const char*, not WTF strings, the call to stringToUString can and should omitted. The use of stringToUString forces additional unneeded memory allocation.

Fixed.

> Exposing the names in the order they appeared in the CSSPropertyNames.in source file does not seem like a good idea. We should expose them in some order that is consistent and does not reflect the peculiarities of our source code. I would suggest alphabetical order if we can’t think of anything else.
> 
> If we actually want this to be efficient we should be creating an array of identifiers one time only and then reusing the same identifiers in the future. Converting from const char* every time doesn’t seem helpful.

Implemented caching of UStrings, yet caching of Identifiers seems impossible to me, as they require an ExecState/global state to get constructed. I'd be grateful if you could give me an insight on this.

> > Source/WebCore/bindings/v8/custom/V8CSSStyleDeclarationCustom.cpp:159
> > +    // We know that "filter" is present in the list but should not be provided in the enumeration.
> > +    // See a comment in the V8CSSStyleDeclaration::namedPropertyGetter() implementation.
> 
> I don’t understand why this special rule to omit filter is in V8 but not in the other JavaScript binding, especially considering the comment in namedPropertyGetter implies it is there. I don’t understand why there is no test for it. I suspect this rule about "filter" was removed long ago but was left behind in V8 for not good reason.

Good catch. I will fix this in another change shortly, given that the CSS filters are getting the momentum. But I don't feel like fixing this in this (orthogonal) change is a good idea, and I don't want to break the code consistency (the "filter" property will be there in the list but will evaluate to undefined).

> > Source/WebCore/css/makeprop.pl:166
> > +  $name =~ s/(\S)-(.)/$1@{[uc($2)]}/g;
> > +  $name =~ s/^-//;
> > +  print HEADER "\"$name\",\n";
> > +}
> > +print HEADER "};\n";
> 
> I think it would be better to not change the contents of this file at all. Instead we could use the existing array of const char* and the first time it’s needed we could build an array of JSC::Identifier one time inside the bindings code and then reuse that each time instead of doing it over and over again.

I believe we should do all transformations we can at build time, especially given that Perl has great capabilities for regexp operations.

> If we do want to keep this, then I suggest we sort the array here, since we only use it for enumeration and so the order is not important.

Sorting implemented.

> I think (.)-(.) would work fine; I don’t think you need the \S there.

Thanks, fixed.

> > LayoutTests/fast/css/style-enumerate-properties-expected.txt:3
> > +Test for https://bugs.webkit.org/show_bug.cgi?id=23946 Webkit does not enumerate over CSS properties in HTMLElement.style - checks that the style contains exactly one numeric property "0" (for "text-decoration") and named properties "textDecoration", "border", "font", and "cssText".
> > +
> > +PASSED
> 
> Tests should show what they are testing, not just say PASSED.

Made use of shouldBe which is quite verbose.

> > LayoutTests/fast/css/style-enumerate-properties.html:25
> > +          if (!(p in style)) {
> > +                console.textContent = "Property '" + p + "' not found!";
> > +                return;
> > +            }
> 
> Better style would be to use the shouldBe macros and do shouldBe for each property so the test output would show what it’s testing.

Done.

> This test does not cover the order of the properties. It should.

I'm not sure how to check this best. For now, the test checks that the first 100 CSS-mapped properties are sorted alphabetically, but I'm not sure this is the right approach. Any ideas are welcome.

> This test does not cover any properties with more then two words in their names, and it should.

Fixed.

> > LayoutTests/fast/css/style-enumerate-properties.html:34
> > +        Webkit does not enumerate over CSS properties in HTMLElement.style</i> - checks that the style contains exactly one numeric property "0" (for "text-decoration") and named properties "textDecoration", "border", "font", and "cssText".
> 
> WebKit has a capital K in its name.

Fixed bug name.

> > LayoutTests/fast/dom/script-tests/domListEnumeration.js:176
> > +// More properties can be added soon. Plus, Chromium hides the "filter" property.
> 
> This comment is more confusing than helpful. It’s not clear how either of these is relevant to the next line of code. I realize that you are justifying the use of >= rather than == for the test, but only because I am reading the whole patch. The comment alone does not make it clear.
> 
> > LayoutTests/fast/dom/script-tests/domListEnumeration.js:177
> > +shouldBeGreaterThanOrEqual("resultArray.length", "376");
> 
> Where did the 376 number come from? Is it right even if SVG is turned off? I think you should just not check the resultArray’s length at all.

Removed this check altogether.
Comment 15 Alexander Pavlov (apavlov) 2011-11-30 05:53:23 PST
Created attachment 117178 [details]
Patch
Comment 16 Alexander Pavlov (apavlov) 2011-11-30 23:50:57 PST
Created attachment 117354 [details]
Patch
Comment 17 Alexander Pavlov (apavlov) 2011-12-07 09:22:39 PST
@reviewers: anyone to have a look please? The comments have been addressed.
Comment 18 Darin Adler 2011-12-07 09:29:11 PST
Comment on attachment 117354 [details]
Patch

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

Looks good. I’d still like to see a little more refinement.

> Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp:211
> +    DEFINE_STATIC_LOCAL(Vector<UString>, jsPropertyNames, ());
> +    if (jsPropertyNames.isEmpty()) {
> +        jsPropertyNames.reserveInitialCapacity(numCSSProperties);
> +        for (int i = 0; i < numCSSProperties; ++i)
> +            jsPropertyNames.append(UString(jsPropertyNameStrings[i]));
> +    }

This should be Identifier[numCSSProperties], not Vector<UString>. The Identifier constructor takes a JSGlobalData*, not an ExecState*. The ExecState* constructor is just a convenience cover that uses the ExecState to find the JSGlobalData. All WebCore use of JavaScript shares a single JSGlobalData; to oversimplify, it’s basically a per-thread data structure. So it’s safe to construct this array only once with whatever ExecState you have that one time. And there is no reason to use a Vector for something we are not going to resize.

Also, since we are doing this only one time, we could consider writing the code to convert the CSS style of property name string into the JavaScript binding style and avoid having a separate table.
Comment 19 Alexander Pavlov (apavlov) 2011-12-08 06:20:09 PST
Created attachment 118379 [details]
[PATCH] Implemented Identifier caching
Comment 20 Alexander Pavlov (apavlov) 2011-12-08 07:11:06 PST
Created attachment 118385 [details]
[PATCH] Restored property name sorting
Comment 21 Alexander Pavlov (apavlov) 2011-12-09 02:22:17 PST
Created attachment 118549 [details]
[PATCH] Update JSC exports to fix compilability on Win and Mac
Comment 22 Darin Adler 2011-12-09 10:00:09 PST
Comment on attachment 118549 [details]
[PATCH] Update JSC exports to fix compilability on Win and Mac

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

Seems OK to land like this. Still room for improvement either before or after landing.

> Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp:206
> +    static Identifier* jsPropertyIdentifiers = 0;

I don’t think you need the "js" prefix on this variable name.

> Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp:211
> +        std::sort(jsPropertyNames.begin(), jsPropertyNames.end(), stringCompare);

Our usual style in WebKit code is to put "using namespace std" at the top of the file rather than qualifying function names at the call site.

> Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp:217
> +        for (int i = 0; i < numCSSProperties; ++i) {
> +            String jsPropertyName = jsPropertyNames.at(i);
> +            jsPropertyIdentifiers[i] = Identifier(&exec->globalData(), jsPropertyName.characters(), jsPropertyName.length());
> +        }

The idiom here is slightly peculiar and unnecessarily inefficient. I would have written this:

    for (int i = 0; i < numCSSProperties; ++i)
        jsPropertyIdentifiers[i] = Identifier(exec, jsPropertyNames[i].impl());

This would use the buffers already allocated for the strings rather than reallocating each one. Since this is one-time code, it’s not critical, but I think my version of the code is already more readable because it’s more brief.

> Source/WebCore/css/makeprop.pl:119
> +String getJSPropertyName(const char* cssPropertyName)

We normally try to avoid abbreviations and use words for variable names. This function uses the names p, isFirstChar, ch, and nextCh, all of which are abbreviations.

> Source/WebCore/css/makeprop.pl:121
> +    StringBuilder result;

Since the maximum length of any property name is known at compile time, this could just use a local char array and construct the String from that. It need not use StringBuilder at all.

> Source/WebCore/css/makeprop.pl:123
> +    bool isFirstChar = true;

There is no need for the isFirstChar boolean. You can do the same check by comparing p - 2 with cssPropertyName inside the loop.

> Source/WebCore/css/makeprop.pl:124
> +    while (char ch = *(p++)) {

Since *p++ is idiomatic, I think it’s better to leave off the parentheses.

> Source/WebCore/css/makeprop.pl:129
> +            ch = !isFirstChar ? (nextCh - 0x20) : nextCh;

Just doing the - 0x20 here is not really all that great. I would suggest using toASCIILower instead for clarity even though it’s slightly less efficient.

> Source/WebCore/css/makeprop.pl:149
> +#include <wtf/text/WTFString.h>

If you move the inline function out of the header file then you can just forward-declare instead of including this header.

> Source/WebCore/css/makeprop.pl:185
> +String getJSPropertyName(const char*);

The use of get in this function name is consistent with the function above, but not normal WebKit naming.

It’s strange to have this take a const char*. I would be more logical to have it take a CSSPropertyID to match the function above it. If it’s only going to take const char* then there is no good reason to put the code here auto-generated, and it can instead go into a normal source file.

> Source/WebCore/css/makeprop.pl:186
> +static inline bool stringCompare(const String& first, const String& second) { return codePointCompare(first, second) < 0; }

This function does not belong here. A basic string comparison function like this should be in WTFString.h. Also, it should have a name making clear how it differs from other functions. I suggest including the words “less than” in the function name.

A function in a header file, even an inline one, should not be marked “static”. That should be left off so it will get external linkage.
Comment 23 Darin Adler 2011-12-09 10:02:15 PST
Comment on attachment 118549 [details]
[PATCH] Update JSC exports to fix compilability on Win and Mac

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

>> Source/WebCore/css/makeprop.pl:185
>> +String getJSPropertyName(const char*);
> 
> The use of get in this function name is consistent with the function above, but not normal WebKit naming.
> 
> It’s strange to have this take a const char*. I would be more logical to have it take a CSSPropertyID to match the function above it. If it’s only going to take const char* then there is no good reason to put the code here auto-generated, and it can instead go into a normal source file.

The normal source file I would suggest as a home for this would be CSSStyleDeclaration.h/cpp.
Comment 24 Alexander Pavlov (apavlov) 2011-12-12 04:45:50 PST
(In reply to comment #22)
> (From update of attachment 118549 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=118549&action=review
> 
> Seems OK to land like this. Still room for improvement either before or after landing.
> 
> > Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp:206
> > +    static Identifier* jsPropertyIdentifiers = 0;
> 
> I don’t think you need the "js" prefix on this variable name.

Fixed

> > Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp:211
> > +        std::sort(jsPropertyNames.begin(), jsPropertyNames.end(), stringCompare);
> 
> Our usual style in WebKit code is to put "using namespace std" at the top of the file rather than qualifying function names at the call site.

Fixed

> > Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp:217
> > +        for (int i = 0; i < numCSSProperties; ++i) {
> > +            String jsPropertyName = jsPropertyNames.at(i);
> > +            jsPropertyIdentifiers[i] = Identifier(&exec->globalData(), jsPropertyName.characters(), jsPropertyName.length());
> > +        }
> 
> The idiom here is slightly peculiar and unnecessarily inefficient. I would have written this:
> 
>     for (int i = 0; i < numCSSProperties; ++i)
>         jsPropertyIdentifiers[i] = Identifier(exec, jsPropertyNames[i].impl());
> 
> This would use the buffers already allocated for the strings rather than reallocating each one. Since this is one-time code, it’s not critical, but I think my version of the code is already more readable because it’s more brief.

Fixed

> > Source/WebCore/css/makeprop.pl:119
> > +String getJSPropertyName(const char* cssPropertyName)
> 
> We normally try to avoid abbreviations and use words for variable names. This function uses the names p, isFirstChar, ch, and nextCh, all of which are abbreviations.

Fixed

> > Source/WebCore/css/makeprop.pl:121
> > +    StringBuilder result;
> 
> Since the maximum length of any property name is known at compile time, this could just use a local char array and construct the String from that. It need not use StringBuilder at all.

Fixed

> > Source/WebCore/css/makeprop.pl:123
> > +    bool isFirstChar = true;
> 
> There is no need for the isFirstChar boolean. You can do the same check by comparing p - 2 with cssPropertyName inside the loop.

Fixed

> > Source/WebCore/css/makeprop.pl:124
> > +    while (char ch = *(p++)) {
> 
> Since *p++ is idiomatic, I think it’s better to leave off the parentheses.

Fixed

> > Source/WebCore/css/makeprop.pl:129
> > +            ch = !isFirstChar ? (nextCh - 0x20) : nextCh;
> 
> Just doing the - 0x20 here is not really all that great. I would suggest using toASCIILower instead for clarity even though it’s slightly less efficient.

Fixed (toASCIIUpper)

> > Source/WebCore/css/makeprop.pl:149
> > +#include <wtf/text/WTFString.h>
> 
> If you move the inline function out of the header file then you can just forward-declare instead of including this header.

Fixed

> > Source/WebCore/css/makeprop.pl:185
> > +String getJSPropertyName(const char*);
> 
> The use of get in this function name is consistent with the function above, but not normal WebKit naming.

When in doubt, use the style found around... These can be fixed together if need be.

> It’s strange to have this take a const char*. I would be more logical to have it take a CSSPropertyID to match the function above it. If it’s only going to take const char* then there is no good reason to put the code here auto-generated, and it can instead go into a normal source file.

Using CSSPropertyID instead of const char* (and hence, not moving it into CSSStyleDeclaration.*)

> > Source/WebCore/css/makeprop.pl:186
> > +static inline bool stringCompare(const String& first, const String& second) { return codePointCompare(first, second) < 0; }
> 
> This function does not belong here. A basic string comparison function like this should be in WTFString.h. Also, it should have a name making clear how it differs from other functions. I suggest including the words “less than” in the function name.

Placed codePointCompareLessThan into WTFString.h.

> A function in a header file, even an inline one, should not be marked “static”. That should be left off so it will get external linkage.

Sorry, fixed.

Will land shortly with these fixes applied.
Comment 25 Alexander Pavlov (apavlov) 2011-12-12 05:24:56 PST
Committed r102570: <http://trac.webkit.org/changeset/102570>
Comment 26 Alexander Pavlov (apavlov) 2011-12-12 06:46:43 PST
Committed r102578: <http://trac.webkit.org/changeset/102578>
Comment 27 Alexander Pavlov (apavlov) 2011-12-12 07:17:19 PST
(In reply to comment #26)
> Committed r102578: <http://trac.webkit.org/changeset/102578>

This is the effective commit, as r102570 was reverted due to a SnowLeopard builder breakage.