Bug 20709 - Implement HTML 5's HTMLElement.classList property
: Implement HTML 5's HTMLElement.classList property
Status: RESOLVED FIXED
: WebKit
HTML DOM
: 528+ (Nightly build)
: All All
: P2 Normal
Assigned To:
: http://www.whatwg.org/specs/web-apps/...
:
: 31683 46509
: 66284
  Show dependency treegraph
 
Reported: 2008-09-07 17:54 PST by
Modified: 2011-08-16 02:06 PST (History)


Attachments
classList M1 (44.40 KB, patch)
2009-11-25 16:25 PST, Erik Arvidsson
no flags Review Patch | Details | Formatted Diff | Diff
Patch (56.30 KB, patch)
2010-08-13 12:44 PST, Erik Arvidsson
no flags Review Patch | Details | Formatted Diff | Diff
Patch (58.34 KB, patch)
2010-09-07 16:18 PST, Erik Arvidsson
no flags Review Patch | Details | Formatted Diff | Diff
Patch (56.16 KB, patch)
2010-09-07 18:21 PST, Erik Arvidsson
no flags Review Patch | Details | Formatted Diff | Diff
Patch (59.75 KB, patch)
2010-09-08 12:52 PST, Erik Arvidsson
no flags Review Patch | Details | Formatted Diff | Diff
Now with markDOMObjectWrapper and V8DOMWrapper::setHiddenWindowReference (63.26 KB, patch)
2010-09-17 18:08 PST, Erik Arvidsson
no flags Review Patch | Details | Formatted Diff | Diff
Patch (63.18 KB, patch)
2010-09-23 15:25 PST, Erik Arvidsson
no flags Review Patch | Details | Formatted Diff | Diff
Took care of Darin's comments and added a perf test for remove (70.46 KB, patch)
2010-09-23 18:30 PST, Erik Arvidsson
no flags Review Patch | Details | Formatted Diff | Diff
Trying to get this to build on GTK (72.30 KB, patch)
2010-09-24 09:55 PST, Erik Arvidsson
no flags Review Patch | Details | Formatted Diff | Diff
Taking care of Darin's comments (74.29 KB, patch)
2010-09-24 12:38 PST, Erik Arvidsson
no flags Review Patch | Details | Formatted Diff | Diff
Patch (73.75 KB, patch)
2010-09-27 14:49 PST, Erik Arvidsson
no flags Review Patch | Details | Formatted Diff | Diff
Patch for landing (73.72 KB, patch)
2010-09-27 15:35 PST, Erik Arvidsson
no flags Review Patch | Details | Formatted Diff | Diff


Note

You need to log in before you can comment on or make changes to this bug.


Description From 2008-09-07 17:54:12 PST
This will help speeding up a lot of code for developers.
http://www.w3.org/TR/html5/semantics.html#classlist
------- Comment #1 From 2009-05-12 16:26:36 PST -------
I'm interested in working on this.

How are CSS class names stored internally? For example if the class attribute is set to "a b c" is this stored as "a b c" or is it stored as a set with "a", "b" and "c"? If the former, is it worth changing it to a set internally in the case classList is accessed? The number of class names is usually pretty small (less than 10 in most cases) so maybe a vector is enough.
------- Comment #2 From 2009-06-16 06:45:45 PST -------
*** Bug 26358 has been marked as a duplicate of this bug. ***
------- Comment #3 From 2009-06-16 06:47:07 PST -------
See <http://www.whatwg.org/specs/web-apps/current-work/#domtokenlist-0> for the definition of the DOMTokenList interface, which the object returned by classList implements.
------- Comment #4 From 2009-06-16 06:51:28 PST -------
(In reply to comment #1)
> How are CSS class names stored internally? For example if the class attribute
> is set to "a b c" is this stored as "a b c" or is it stored as a set with "a",
> "b" and "c"?

It is stored as a Vector with 3 items: "a", "b", "c". The original order is preserved.

> If the former, is it worth changing it to a set internally in the
> case classList is accessed? The number of class names is usually pretty small
> (less than 10 in most cases) so maybe a vector is enough.

I agree that in the common case a Vector seems fine. We could switch to using a set if the number of classes crosses some threshold, but maybe that isn't worth it. If we used a set we'd still need to have a way of preserving the original ordering of the classes, as this is required for classList.item(n).

Another possibility would be to use ListHashSet <http://trac.webkit.org/browser/trunk/JavaScriptCore/wtf/ListHashSet.h>.
------- Comment #5 From 2009-06-16 06:53:10 PST -------
(In reply to comment #4)
> (In reply to comment #1)
> > How are CSS class names stored internally? For example if the class attribute
> > is set to "a b c" is this stored as "a b c" or is it stored as a set with "a",
> > "b" and "c"?
> 
> It is stored as a Vector with 3 items: "a", "b", "c". The original order is
> preserved.

You can see the implementation here: <http://trac.webkit.org/browser/trunk/WebCore/dom/ClassNames.h?rev=43365>.
------- Comment #6 From 2009-06-16 08:54:12 PST -------
Erik found some existing tests for classList: <http://simon.html5.org/test/html/dom/reflecting/DOMTokenList/>.
------- Comment #7 From 2009-06-16 09:01:05 PST -------
It looks like DOMTokenList provides a superset of ClassNames's functionality. Maybe a good way to go about this would be:

1) Rename ClassNames to DOMTokenList and ClassNamesData to DOMTokenListData
2) Expose the current functionality of DOMTokenList to JavaScript and add tests
3) Add the remaining DOMTokenList functionality (add, remove, toggle) and add tests
------- Comment #8 From 2009-08-12 17:58:20 PST -------
This feature was recently implemented in Gecko. You may be interested in the automated test [1] that could be easily transformed into a layout test. There are a few Gecko-isms that would need to be removed and you would need to provide is()/ok() implementations.

In the current spec the mutating methods (add/remove/toggle) are preserving whitespace. There was some discussions about an alternative approach of normalizing whitespace, which could make implementation more straightforward [2].
That change wasn't made for now, but if you think it would be better to go that way that's something that could be considered.

[1] http://hg.mozilla.org/mozilla-central/file/tip/content/base/test/test_classList.html
[2] http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2009-July/021653.html
------- Comment #9 From 2009-11-13 18:14:43 PST -------
I got something mostly working without any refactoring of ClassNames by just forwarding calls as needed. I'll upload a snapshot early next week before I start any refactoring.
------- Comment #10 From 2009-11-19 13:53:57 PST -------
The JSC bindins for HasIndexGetter in combination with ConvertNullStringTo=Null is broken so that the following fails in Safari (it works in Chromium):

document.body.className = 'x';
assertTrue(null === document.body.classList[10])

JSC generates code that checks the length and if the index is larger to or equal to the length it does not call the index getter.
------- Comment #11 From 2009-11-25 16:25:24 PST -------
Created an attachment (id=43876) [details]
classList M1

This patch does not refactor ClassNames but instead uses ClassNames. I wanted something that more or less works before I do the refactoring and this is a good milestone.

I have a couple of questions:

Currently ClassNames converts all class names to lower case in quirks mode. HTML5 clearly states that DOMTokenList is case sensitive. We could store the non case folded class names and only do the case folding at runtime if needed. The downside is that I don't want to make class name matching slower since it seems crucial that this is as fast as it can get because it is used for matching CSS selectors.

Should the classList member be moved to RareData? NamedMappedAttrMap?

Should classList() be on StyledElement instead of HTMLElement?

Should I include ObjC bindings?

Do I need to upgrade WebKit/mac/MigrateHeaders.make?
------- Comment #12 From 2010-08-13 12:44:54 PST -------
Created an attachment (id=64365) [details]
Patch
------- Comment #13 From 2010-08-13 14:48:39 PST -------
Attachment 64365 [details] did not build on gtk:
Build output: http://queues.webkit.org/results/3768133
------- Comment #14 From 2010-08-13 17:05:22 PST -------
(From update of attachment 64365 [details])
> -        typedef Vector<AtomicString, 8> StringVector;
>          String m_string;
> -        StringVector m_vector;
>          bool m_shouldFoldCase;
> +        bool m_folded;
> +        StringVector m_vector;
> +        StringVector m_vectorNoFold;

I am worried about the memory increase in adding a second vector here.  Have you done any memory benchmarking to make sure this doesn't regress things (eg. membuster)

> @@ -0,0 +1,151 @@
> +// Copyright (c) 2009 The Chromium Authors. All rights reserved.
> +// Use of this source code is governed by a BSD-style license that can be
> +// found in the LICENSE file.

This is an invalid license header.  Please see http://webkit.org/coding/contributing.html for more on this.


> +++ b/WebCore/html/ClassList.h
> @@ -0,0 +1,44 @@
> +// Copyright (c) 2009 The Chromium Authors. All rights reserved.
> +// Use of this source code is governed by a BSD-style license that can be
> +// found in the LICENSE file.

Here too. (There are more as well).

r-.
------- Comment #15 From 2010-08-16 09:37:42 PST -------
Thanks for the review. I'm going on vacation but I'll want to get this done as soon as I come back.

(In reply to comment #14)

> > +        StringVector m_vectorNoFold;
> 
> I am worried about the memory increase in adding a second vector here.  Have you done any memory benchmarking to make sure this doesn't regress things (eg. membuster)

This is also worrying me. My current plan is to revert all the changes to ClassNames. Then add a member to ElementRareData that points to the ClassList. The ClassList uses the ClassNames in standards mode for fast contains and item lookup. For quirks mode there are two options. One is to have an internal ClassNames copy and the other option is to operate straight on the class attribute string.
------- Comment #16 From 2010-09-07 16:18:33 PST -------
Created an attachment (id=66784) [details]
Patch
------- Comment #17 From 2010-09-07 16:21:41 PST -------
(From update of attachment 66784 [details])
It seems unnecessary to define an abstract base class DOMTokenList and do everything through virtual functions just because we might have another derived class in the future. The same thing came up with NamedNodeMap and we decided to just put the concrete implementation into the base and save abstraction for later. So investigate combining DOMTokenList and ClassList into a single class.
------- Comment #18 From 2010-09-07 16:25:32 PST -------
(In reply to comment #17)
> (From update of attachment 66784 [details] [details])
> It seems unnecessary to define an abstract base class DOMTokenList and do everything through virtual functions just because we might have another derived class in the future. The same thing came up with NamedNodeMap and we decided to just put the concrete implementation into the base and save abstraction for later. So investigate combining DOMTokenList and ClassList into a single class.

OK. I'll just fold it all into ClassList then. Should I rename the class to ClassListDOMTokenList?

(The dataset class that implements the DOMStringMap is called DatasetDOMStringMap.)
------- Comment #19 From 2010-09-07 17:04:27 PST -------
I looked at NamedNodeMap and now I understand what Darin meant. I'll rename ClassList to DOMTokenList.
------- Comment #20 From 2010-09-07 17:42:12 PST -------
Attachment 66784 [details] did not build on gtk:
Build output: http://queues.webkit.org/results/3938308
------- Comment #21 From 2010-09-07 18:21:10 PST -------
Created an attachment (id=66817) [details]
Patch
------- Comment #22 From 2010-09-07 19:23:10 PST -------
(From update of attachment 66817 [details])
View in context: https://bugs.webkit.org/attachment.cgi?id=66817&action=prettypatch

> WebCore/html/DOMTokenList.h:54
> +    virtual void ref();
> +    virtual void deref();
Per discussion in IRC, these should go away and this class should become RefCounted<DOMTokenList>

> WebCore/html/DOMTokenList.h:61
> +    virtual bool contains(const AtomicString& token, ExceptionCode&) const;
> +    virtual void add(const AtomicString& token, ExceptionCode& ec);
> +    virtual void remove(const AtomicString& token, ExceptionCode& ec);
> +    virtual bool toggle(const AtomicString& token, ExceptionCode& ec);
nit: don't need to name the ExceptionCode parameters here.  Arguably the AtomicString params could be unnamed as well (as they are in the Internal versions).
------- Comment #23 From 2010-09-07 21:45:36 PST -------
Attachment 66817 [details] did not build on gtk:
Build output: http://queues.webkit.org/results/3976276
------- Comment #24 From 2010-09-08 10:48:36 PST -------
I think I might just follow Weinig's work in 45358 after all.

I'm not arguing that his solution is better but we should be consistent.
------- Comment #25 From 2010-09-08 12:52:55 PST -------
Created an attachment (id=66931) [details]
Patch
------- Comment #26 From 2010-09-08 12:57:00 PST -------
The latest patch follows Sam Weinig's pattern from bug 45358.

It would be great if DOMTokenList and DOMStringMap would not keep the Element alive but I don't think this is that of a common scenario. Like Sam wrote in bug 45358 we have a lot of places where this pattern is used and yes it would be good to improve them all but maybe that can be done in a separate bug?
------- Comment #27 From 2010-09-08 12:58:01 PST -------
(From update of attachment 66931 [details])
View in context: https://bugs.webkit.org/attachment.cgi?id=66931&action=prettypatch

> WebCore/bindings/js/JSElementCustom.cpp:63
> +    markDOMObjectWrapper(markStack, globalData, element->optionalClassList());
Does this mean we'll eagerly create the classList object on every element that's wrapped from javascript?  It's not very optional in that case.  This seems a bit unfortunate.

Do you have to do anything for V8?

> WebCore/html/DOMTokenList.h:64
> +    virtual ~DOMTokenList() { }
> +
> +    virtual void ref();
> +    virtual void deref();
> +
> +    virtual unsigned length() const;
> +    virtual const AtomicString item(unsigned index) const;
> +    virtual bool contains(const AtomicString&, ExceptionCode&) const;
> +    virtual void add(const AtomicString&, ExceptionCode&);
> +    virtual void remove(const AtomicString&, ExceptionCode&);
> +    virtual bool toggle(const AtomicString&, ExceptionCode&);
> +    virtual String toString() const;
> +
> +    virtual void reset(const String&);
None of these should be virtual.
------- Comment #28 From 2010-09-08 13:15:59 PST -------
(In reply to comment #27)
> (From update of attachment 66931 [details] [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=66931&action=prettypatch
> 
> > WebCore/bindings/js/JSElementCustom.cpp:63
> > +    markDOMObjectWrapper(markStack, globalData, element->optionalClassList());
> Does this mean we'll eagerly create the classList object on every element that's wrapped from javascript?  It's not very optional in that case.  This seems a bit unfortunate.

No, optionalClassList does not create a DOMTokenList.

> Do you have to do anything for V8?

looking
------- Comment #29 From 2010-09-08 15:31:16 PST -------
Attachment 66931 [details] did not build on gtk:
Build output: http://queues.webkit.org/results/3914329
------- Comment #30 From 2010-09-17 18:08:37 PST -------
Created an attachment (id=67985) [details]
Now with markDOMObjectWrapper and V8DOMWrapper::setHiddenWindowReference
------- Comment #31 From 2010-09-17 21:00:06 PST -------
Attachment 67985 [details] did not build on gtk:
Build output: http://queues.webkit.org/results/4035060
------- Comment #32 From 2010-09-23 15:25:58 PST -------
Created an attachment (id=68606) [details]
Patch
------- Comment #33 From 2010-09-23 16:22:20 PST -------
(From update of attachment 68606 [details])
View in context: https://bugs.webkit.org/attachment.cgi?id=68606&action=review

Great work. Looks close to ready!

I am going to say review- but only because of the inefficient use of String here in the add and remove functions. If we add some test cases to prove we don’t have O(n^2) algorithms there then I think we’re ready to go.

> WebCore/dom/Element.cpp:1598
> +    if (hasRareData()) {
> +        ElementRareData* data = rareData();
> +        if (data && data->m_classList)
> +            data->m_classList->reset(newClassName);
> +    }

We’e normally use early return here:

    if (!hasRareData())
        return;
    ElementRareData* data = rareData();
    if (!data || !data->m_classList)
        return;
    data->m_classLiast->reset(newClassName);

But also, you could use optionalClassList for this:

    DOMTokenList* classList = optionalClassList();
    if (!classList)
        return;
    classList->reset(newClassName);

I think that’s the best way to write it. Or maybe even put that code in-line at the one call site and not have that function at all.

> WebCore/dom/StyledElement.cpp:224
> +    }
>      else {

Braces go on the same line as the else in the WebKit coding style.

> WebCore/html/DOMTokenList.cpp:38
> +namespace {
> +
> +bool validateToken(const AtomicString& token, ExceptionCode& ec)

WebKit code typically uses “static” to get internal linkage rather than an anonymous namespace, but perhaps this is something that we should change?

> WebCore/html/DOMTokenList.cpp:45
> +    const unsigned length = token.length();

WebKit code normally does not use const for local scalar variables. I see the attraction of doing so to state that a particular variable won’t change, but doing in sometimes and not others seems untidy, and it has no effect on generated code. I’d prefer that we not do it here, just to stay consistent.

> WebCore/html/DOMTokenList.cpp:62
> +        m_classNames = new SpaceSplitString(m_element->getAttribute(classAttr), false);

This can use fastGetAttribute.

> WebCore/html/DOMTokenList.cpp:91
> +     return containsInternal(token);

This line of code has an extra space.

> WebCore/html/DOMTokenList.cpp:108
> +    const AtomicString oldClassName(m_element->getAttribute(classAttr));

This can use const AtomicString& so it doesn’t ref and then deref.

This can use fastGetAttribute.

> WebCore/html/DOMTokenList.cpp:110
> +    if (oldClassName.isEmpty())
> +        m_element->setAttribute(classAttr, token);

Don’t we also want to do this when the old value consists entirely of whitespace? Is there a test case covering this?

> WebCore/html/DOMTokenList.cpp:112
> +        m_element->setAttribute(classAttr, oldClassName + " " + token);

This is the cleanest way to write the code, but it is slow and reallocates the string twice. You should use Vector<UChar> or StringBuilder for better efficiency.

> WebCore/html/DOMTokenList.cpp:133
> +    String output; // 3

Building up a String a character at a time is pathologically slow. We need to use Vector<UChar> instead of String here. I’d like to see a test case with a long class name or a class attribute with a lot of class names to verify the algorithm is not O(n^2).

> WebCore/html/DOMTokenList.cpp:185
> +    return m_element->getAttribute(classAttr);

Can use fastGetAttribute.

> WebCore/html/DOMTokenList.h:45
> +    ~DOMTokenList() { }

There is no need to explicitly declare and define this constructor.

> WebCore/html/DOMTokenList.idl:40
> +#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT
> +        [DontEnum] DOMString toString();
> +#endif

I don’t think this is the right way to make toString work. Isn’t it built in to the language already?
------- Comment #34 From 2010-09-23 17:10:11 PST -------
Attachment 68606 [details] did not build on gtk:
Build output: http://queues.webkit.org/results/4021142
------- Comment #35 From 2010-09-23 18:22:48 PST -------
(From update of attachment 68606 [details])
View in context: https://bugs.webkit.org/attachment.cgi?id=68606&action=review

I'm adding a perf test as well.

>> WebCore/dom/Element.cpp:1598
>> +    }
> 
> We’e normally use early return here:
> 
>     if (!hasRareData())
>         return;
>     ElementRareData* data = rareData();
>     if (!data || !data->m_classList)
>         return;
>     data->m_classLiast->reset(newClassName);
> 
> But also, you could use optionalClassList for this:
> 
>     DOMTokenList* classList = optionalClassList();
>     if (!classList)
>         return;
>     classList->reset(newClassName);
> 
> I think that’s the best way to write it. Or maybe even put that code in-line at the one call site and not have that function at all.

Removed and inlined.

>> WebCore/dom/StyledElement.cpp:224
>>      else {
> 
> Braces go on the same line as the else in the WebKit coding style.

Done.

>> WebCore/html/DOMTokenList.cpp:38
>> +bool validateToken(const AtomicString& token, ExceptionCode& ec)
> 
> WebKit code typically uses “static” to get internal linkage rather than an anonymous namespace, but perhaps this is something that we should change?

Changed to static.

>> WebCore/html/DOMTokenList.cpp:45
>> +    const unsigned length = token.length();
> 
> WebKit code normally does not use const for local scalar variables. I see the attraction of doing so to state that a particular variable won’t change, but doing in sometimes and not others seems untidy, and it has no effect on generated code. I’d prefer that we not do it here, just to stay consistent.

Done.

>> WebCore/html/DOMTokenList.cpp:62
>> +        m_classNames = new SpaceSplitString(m_element->getAttribute(classAttr), false);
> 
> This can use fastGetAttribute.

Done.

>> WebCore/html/DOMTokenList.cpp:91
>> +     return containsInternal(token);
> 
> This line of code has an extra space.

Done.

>> WebCore/html/DOMTokenList.cpp:108
>> +    const AtomicString oldClassName(m_element->getAttribute(classAttr));
> 
> This can use const AtomicString& so it doesn’t ref and then deref.
> 
> This can use fastGetAttribute.

Done.

>> WebCore/html/DOMTokenList.cpp:110
>> +        m_element->setAttribute(classAttr, token);
> 
> Don’t we also want to do this when the old value consists entirely of whitespace? Is there a test case covering this?

The token cannot contain whitespace and invalid tokens are covered by the test.

>> WebCore/html/DOMTokenList.cpp:112
>> +        m_element->setAttribute(classAttr, oldClassName + " " + token);
> 
> This is the cleanest way to write the code, but it is slow and reallocates the string twice. You should use Vector<UChar> or StringBuilder for better efficiency.

Changed to StringBuilder

>> WebCore/html/DOMTokenList.cpp:133
>> +    String output; // 3
> 
> Building up a String a character at a time is pathologically slow. We need to use Vector<UChar> instead of String here. I’d like to see a test case with a long class name or a class attribute with a lot of class names to verify the algorithm is not O(n^2).

Changed to Vector<UChar>

>> WebCore/html/DOMTokenList.cpp:185
>> +    return m_element->getAttribute(classAttr);
> 
> Can use fastGetAttribute.

Done.

>> WebCore/html/DOMTokenList.h:45
>> +    ~DOMTokenList() { }
> 
> There is no need to explicitly declare and define this constructor.

Done.

>> WebCore/html/DOMTokenList.idl:40
>> +#endif
> 
> I don’t think this is the right way to make toString work. Isn’t it built in to the language already?

This is how other toString cases are done. I assume it is just so that the toString method is only added to the JS bindings.
------- Comment #36 From 2010-09-23 18:30:47 PST -------
Created an attachment (id=68637) [details]
Took care of Darin's comments and added a perf test for remove
------- Comment #37 From 2010-09-23 23:31:04 PST -------
Attachment 68637 [details] did not build on gtk:
Build output: http://queues.webkit.org/results/4079094
------- Comment #38 From 2010-09-24 09:55:37 PST -------
Created an attachment (id=68696) [details]
Trying to get this to build on GTK
------- Comment #39 From 2010-09-24 10:02:55 PST -------
(From update of attachment 68606 [details])
View in context: https://bugs.webkit.org/attachment.cgi?id=68606&action=review

>>> WebCore/html/DOMTokenList.cpp:110
>>> +        m_element->setAttribute(classAttr, token);
>> 
>> Don’t we also want to do this when the old value consists entirely of whitespace? Is there a test case covering this?
> 
> The token cannot contain whitespace and invalid tokens are covered by the test.

I think you may have misunderstood my question. I was talking about oldClassName containing entirely whitespace, not the token containing whitespace.
------- Comment #40 From 2010-09-24 10:20:04 PST -------
(From update of attachment 68606 [details])
View in context: https://bugs.webkit.org/attachment.cgi?id=68606&action=review

>>>> WebCore/html/DOMTokenList.cpp:110
>>>> +        m_element->setAttribute(classAttr, token);
>>> 
>>> Don’t we also want to do this when the old value consists entirely of whitespace? Is there a test case covering this?
>> 
>> The token cannot contain whitespace and invalid tokens are covered by the test.
> 
> I think you may have misunderstood my question. I was talking about oldClassName containing entirely whitespace, not the token containing whitespace.

Indeed, I did misunderstand you.

Add needs some refinements though. Checking isEmpty is still a correct optimization. However, we should only add a space if the last character is not already a space.
------- Comment #41 From 2010-09-24 10:22:49 PST -------
(From update of attachment 68696 [details])
View in context: https://bugs.webkit.org/attachment.cgi?id=68696&action=review

Please consider my comments. You may want to do one more round of refinements before landing this.

> WebCore/html/DOMTokenList.cpp:60
> +    if (m_element->document()->inQuirksMode())
> +        m_classNames = new SpaceSplitString(m_element->fastGetAttribute(classAttr), false);

I’m surprised this compiles without an explicit adoptPtr. Soon I will be turning on the “script OwnPtr” flag and then the adoptPtr will definitely be needed. Please use adoptPtr here.

> WebCore/html/DOMTokenList.cpp:135
> +    const unsigned inputLength = input.length();

This is another use of const like the one I asked you to remove earlier.

> WebCore/html/DOMTokenList.cpp:137
> +    Vector<UChar> tokenVector;
> +    append(tokenVector, token);

We could easily write a function that compares a vector to an AtomicString so you would not have to copy the characters into a Vector. That function could go into AtomicString.h or for now could just be here in this source file and moved to AtomicString if we need it later.

> WebCore/html/DOMTokenList.cpp:138
> +    Vector<UChar> output; // 3

We could probably improve performance when doing this on a long string by calling reserveCapacity on output, guessing that its size will be inputLength. I don’t know exactly what it takes to remove excess capacity at String::adopt time but even if we don’t do that the performance tradeoff still might be good.

> WebCore/html/DOMTokenList.cpp:177
> +    if (!validateToken(token,  ec))

Extra space here after the comma.

> WebCore/html/DOMTokenList.cpp:196
> +    if (m_element->document()->inQuirksMode())
> +        m_classNames->set(newClassName, false);

I suggest having this do if (m_classNames) instead of if (inQuirksMode).

> WebCore/html/DOMTokenList.cpp:202
> +    if (m_element->document()->inQuirksMode())
> +        return m_classNames.get();

I suggest having this do if (m_classNames) instead of if (inQuirksMode).

> WebCore/html/DOMTokenList.h:42
> +        return new DOMTokenList(element);

This line of code should call adoptPtr.

> WebCore/html/DOMTokenList.h:61
> +    DOMTokenList(Element* element);

You should omit the argument name “element” here.

> WebCore/html/DOMTokenList.h:70
> +    OwnPtr<SpaceSplitString> m_classNames;

It might be better to name this in a way that makes it more clear it’s used only in a particular case. Even a name such as m_caseSensitiveClassNamesForQuirksMode would not be too crazy, given that this is only used in three places and it would be a mistake to use it anywhere else.

Given that SpaceSplitString already uses a pointer-to-implementation idiom, using an OwnPtr is unnecessary. In fact, it costs one extra memory block for no good reason. Another way to do this is to use have m_classNames be a SpaceSplitString.

If stop using OwnPtr, then my other comments above about switching to a null check of m_classNames would require adding an isNull() function to SpaceSplitString, which I think would be OK. Or you could check quirks mode each time as you are doing now.

If stop using OwnPtr, you won’t have to worry about adoptPtr in the constructor. Instead you would use the SpaceSplitString set function.
------- Comment #42 From 2010-09-24 10:24:03 PST -------
(From update of attachment 68696 [details])
View in context: https://bugs.webkit.org/attachment.cgi?id=68696&action=review

>> WebCore/html/DOMTokenList.cpp:60
>> +        m_classNames = new SpaceSplitString(m_element->fastGetAttribute(classAttr), false);
> 
> I’m surprised this compiles without an explicit adoptPtr. Soon I will be turning on the “script OwnPtr” flag and then the adoptPtr will definitely be needed. Please use adoptPtr here.

I mean “strict OwnPtr”!
------- Comment #43 From 2010-09-24 12:38:02 PST -------
Created an attachment (id=68732) [details]
Taking care of Darin's comments
------- Comment #44 From 2010-09-24 12:40:22 PST -------
Darin, do you mind taking another look? 

Would it be better to submit the operator== for AtomicString and Vector<UChar> in another patch first?
------- Comment #45 From 2010-09-24 12:45:01 PST -------
(From update of attachment 68732 [details])
View in context: https://bugs.webkit.org/attachment.cgi?id=68732&action=review

> WebCore/html/DOMTokenList.cpp:112
> +    if (!validateToken(token,  ec))

fixed locally

> WebCore/html/DOMTokenList.cpp:134
> +    if (!validateToken(token,  ec))

fixed locally
------- Comment #46 From 2010-09-24 14:30:43 PST -------
By moving the operator== to AtomicString it got a lot simpler. See bug 46509.
------- Comment #47 From 2010-09-24 18:31:34 PST -------
(From update of attachment 68732 [details])
View in context: https://bugs.webkit.org/attachment.cgi?id=68732&action=review

> WebCore/dom/StyledElement.cpp:224
> +        DOMTokenList* classList = optionalClassList();
> +        if (classList)

Putting the definition of the local variable inside the if would make this even clearer:

    if (DOMTokenList* classList = optionalClassList())
        classList->reset(newClassString);

> WebCore/html/DOMTokenList.cpp:37
> +bool operator==(const AtomicString& a, const Vector<UChar>& b)

Should be marked static so we get internal linkage.

> WebCore/html/DOMTokenList.cpp:43
> +    const UChar* chars = a.characters();

Please don't abbreviate this. Just use the word characters.

> WebCore/html/DOMTokenList.h:74
> +bool operator==(const AtomicString& a, const Vector<UChar>& b);
> +inline bool operator==(const Vector<UChar>& a, const AtomicString& b) { return b == a; }

Why is this declared in the header? I don’t think it’s reasonable to have this here as a public function. When I said it could be in DOMTokenList, I meant in the .cpp file. If we want to put it in the header then we need to find a more appropriate file.
------- Comment #48 From 2010-09-27 14:49:57 PST -------
Created an attachment (id=68962) [details]
Patch
------- Comment #49 From 2010-09-27 14:59:10 PST -------
(From update of attachment 68962 [details])
View in context: https://bugs.webkit.org/attachment.cgi?id=68962&action=review

> WebCore/html/DOMTokenList.h:31
> +#include <wtf/OwnPtr.h>

I don’t see any use of OwnPtr in this header, so there is no need to include OwnPtr.h.
------- Comment #50 From 2010-09-27 15:35:30 PST -------
Created an attachment (id=68979) [details]
Patch for landing
------- Comment #51 From 2010-09-27 16:12:22 PST -------
(From update of attachment 68979 [details])
Clearing flags on attachment: 68979

Committed r68440: <http://trac.webkit.org/changeset/68440>
------- Comment #52 From 2010-09-27 16:12:34 PST -------
All reviewed patches have been landed.  Closing bug.
------- Comment #53 From 2010-09-27 16:43:36 PST -------
http://trac.webkit.org/changeset/68440 might have broken Qt Linux Release
The following changes are on the blame list:
http://trac.webkit.org/changeset/68440
http://trac.webkit.org/changeset/68439
------- Comment #54 From 2010-09-27 22:44:02 PST -------
(In reply to comment #53)
> http://trac.webkit.org/changeset/68440 might have broken Qt Linux Release
> The following changes are on the blame list:
> http://trac.webkit.org/changeset/68440
> http://trac.webkit.org/changeset/68439

You guys shouldn't ignore this notice and burn always the Qt tree!
Qt specific expected files updated in http://trac.webkit.org/changeset/68488
------- Comment #55 From 2010-09-27 23:04:38 PST -------
(In reply to comment #54)
> (In reply to comment #53)
> > http://trac.webkit.org/changeset/68440 might have broken Qt Linux Release
> > The following changes are on the blame list:
> > http://trac.webkit.org/changeset/68440
> > http://trac.webkit.org/changeset/68439
> 
> You guys shouldn't ignore this notice and burn always the Qt tree!
> Qt specific expected files updated in http://trac.webkit.org/changeset/68488

I apologize. I'll make sure I wont neglect it again.
------- Comment #56 From 2010-09-27 23:09:43 PST -------
(In reply to comment #55)
> I apologize. I'll make sure I wont neglect it again.
Not problem. I realized you broke GTK bots too,
could you fix the GTK specific expected results?
(You should make similar changes, as I did on Qt.)
------- Comment #57 From 2010-09-27 23:34:11 PST -------
(In reply to comment #56)
> (In reply to comment #55)
> > I apologize. I'll make sure I wont neglect it again.
> Not problem. I realized you broke GTK bots too,
> could you fix the GTK specific expected results?
> (You should make similar changes, as I did on Qt.)

Will do (tomorrow morning). Thanks.
------- Comment #58 From 2010-09-28 05:05:07 PST -------
(In reply to comment #57)
> Will do (tomorrow morning). Thanks.

Done by Alex: http://trac.webkit.org/changeset/68501
------- Comment #59 From 2010-10-05 10:12:30 PST -------
Hi,

I'm interested in implementing HTML5 output element in WebKit. I happily realized that the DOMTokenList interface, which is used in the definition of the DOM interface of the output element, is implemented by this issue. However, unfortunately, the current implementation is tightly coupled to implement the classList property in spite of early patches weren't. So I couldn't employ the current DOMTokenList to implement output element. IMHO, we should decouple the classList property related implementation from the DOMTokenList class, like the implementation proposed in the early patches. I'd like to ask your opinions.
------- Comment #60 From 2010-10-05 10:24:41 PST -------
(In reply to comment #59)
> I'm interested in implementing HTML5 output element in WebKit. I happily realized that the DOMTokenList interface, which is used in the definition of the DOM interface of the output element, is implemented by this issue. However, unfortunately, the current implementation is tightly coupled to implement the classList property in spite of early patches weren't. So I couldn't employ the current DOMTokenList to implement output element. IMHO, we should decouple the classList property related implementation from the DOMTokenList class, like the implementation proposed in the early patches. I'd like to ask your opinions.

Yes, when we implement the output element we can refactor the DOMTokenList class so it serves both purposes. This should be straightforward.
------- Comment #61 From 2010-10-05 10:26:48 PST -------
(In reply to comment #60)
> Yes, when we implement the output element we can refactor the DOMTokenList class so it serves both purposes. This should be straightforward.

This refactoring will start by making all functions exposed to the DOMTokenList IDL file pure virtual ones in the DOMTokenList base, and then moving the body of the class into a new ClassList class, derived from DOMTokenList.

Then if there is any code that can be shared between the ClassList and whatever DOMTokenList needs to be used by the <output> implementation, we can move that up into the DOMTokenList class a function at a time.
------- Comment #62 From 2010-10-05 10:30:32 PST -------
(In reply to comment #59)
> I'm interested in implementing HTML5 output element in WebKit. I happily realized that the DOMTokenList interface, which is used in the definition of the DOM interface of the output element, is implemented by this issue. However, unfortunately, the current implementation is tightly coupled to implement the classList property...

This was done by design since classList is the only user of this today. When we add other users of DOMTokenList or SettableDOMTokenList it was understood that this would need to get refactored.

The only hard part of doing this refactoring is updating the myriad of build files :'(

I added you to bug 29363. Lets keep the discussion there.
------- Comment #63 From 2010-10-05 10:43:14 PST -------
Hi,

Thank you for your quick responses! Your comments definitely helpful for me. Although I'm going to be off this week, I'll start refactoring DOMTokenList class and implementing the output element next week. I'll keep the discussion on bug 29363.

Thanks,