| Index: Source/core/html/HTMLCollection.cpp | 
| diff --git a/Source/core/html/HTMLCollection.cpp b/Source/core/html/HTMLCollection.cpp | 
| index 74a2ccf0becf9cf5c154c9dea46a34c189ff9430..cb25f06e0965dfcdf2fc2fa4e7c93ef8b1b661cc 100644 | 
| --- a/Source/core/html/HTMLCollection.cpp | 
| +++ b/Source/core/html/HTMLCollection.cpp | 
| @@ -24,7 +24,7 @@ | 
| #include "core/html/HTMLCollection.h" | 
|  | 
| #include "HTMLNames.h" | 
| -#include "core/dom/ClassNodeList.h" | 
| +#include "core/dom/ClassCollection.h" | 
| #include "core/dom/ElementTraversal.h" | 
| #include "core/dom/NodeList.h" | 
| #include "core/dom/NodeRareData.h" | 
| @@ -40,6 +40,9 @@ using namespace HTMLNames; | 
| static bool shouldOnlyIncludeDirectChildren(CollectionType type) | 
| { | 
| switch (type) { | 
| +    case ClassCollectionType: | 
| +    case TagCollectionType: | 
| +    case HTMLTagCollectionType: | 
| case DocAll: | 
| case DocAnchors: | 
| case DocApplets: | 
| @@ -63,10 +66,7 @@ static bool shouldOnlyIncludeDirectChildren(CollectionType type) | 
| case TableTBodies: | 
| return true; | 
| case ChildNodeListType: | 
| -    case ClassNodeListType: | 
| case NameNodeListType: | 
| -    case TagNodeListType: | 
| -    case HTMLTagNodeListType: | 
| case RadioNodeListType: | 
| case RadioImgNodeListType: | 
| case LabelsNodeListType: | 
| @@ -91,6 +91,9 @@ static NodeListRootType rootTypeFromCollectionType(CollectionType type) | 
| case DocumentNamedItems: | 
| case FormControls: | 
| return NodeListIsRootedAtDocument; | 
| +    case ClassCollectionType: | 
| +    case TagCollectionType: | 
| +    case HTMLTagCollectionType: | 
| case NodeChildren: | 
| case TableTBodies: | 
| case TSectionRows: | 
| @@ -102,10 +105,7 @@ static NodeListRootType rootTypeFromCollectionType(CollectionType type) | 
| case MapAreas: | 
| return NodeListIsRootedAtNode; | 
| case ChildNodeListType: | 
| -    case ClassNodeListType: | 
| case NameNodeListType: | 
| -    case TagNodeListType: | 
| -    case HTMLTagNodeListType: | 
| case RadioNodeListType: | 
| case RadioImgNodeListType: | 
| case LabelsNodeListType: | 
| @@ -118,6 +118,8 @@ static NodeListRootType rootTypeFromCollectionType(CollectionType type) | 
| static NodeListInvalidationType invalidationTypeExcludingIdAndNameAttributes(CollectionType type) | 
| { | 
| switch (type) { | 
| +    case TagCollectionType: | 
| +    case HTMLTagCollectionType: | 
| case DocImages: | 
| case DocEmbeds: | 
| case DocForms: | 
| @@ -146,11 +148,10 @@ static NodeListInvalidationType invalidationTypeExcludingIdAndNameAttributes(Col | 
| return InvalidateOnIdNameAttrChange; | 
| case FormControls: | 
| return InvalidateForFormControls; | 
| +    case ClassCollectionType: | 
| +        return InvalidateOnClassAttrChange; | 
| case ChildNodeListType: | 
| -    case ClassNodeListType: | 
| case NameNodeListType: | 
| -    case TagNodeListType: | 
| -    case HTMLTagNodeListType: | 
| case RadioNodeListType: | 
| case RadioImgNodeListType: | 
| case LabelsNodeListType: | 
| @@ -175,9 +176,11 @@ PassRefPtr<HTMLCollection> HTMLCollection::create(ContainerNode* base, Collectio | 
|  | 
| HTMLCollection::~HTMLCollection() | 
| { | 
| -    // HTMLNameCollection removes cache by itself. | 
| -    if (type() != WindowNamedItems && type() != DocumentNamedItems) | 
| +    // HTMLNameCollection, ClassCollection and TagCollection remove cache by themselves. | 
| +    if (type() != WindowNamedItems && type() != DocumentNamedItems && type() != ClassCollectionType | 
| +        && type() != HTMLTagCollectionType && type() != TagCollectionType) { | 
| ownerNode()->nodeLists()->removeCacheWithAtomicName(this, type()); | 
| +    } | 
| } | 
|  | 
| void HTMLCollection::invalidateCache() const | 
| @@ -192,7 +195,24 @@ inline bool isMatchingElement(const NodeListType&, const Element&); | 
| template <> inline bool isMatchingElement(const HTMLCollection& htmlCollection, const Element& element) | 
| { | 
| CollectionType type = htmlCollection.type(); | 
| -    if (!element.isHTMLElement() && !(type == DocAll || type == NodeChildren || type == WindowNamedItems)) | 
| + | 
| +    // These collections apply to any kind of Elements, not just HTMLElements. | 
| +    switch (type) { | 
| +    case DocAll: | 
| +    case NodeChildren: | 
| +        return true; | 
| +    case ClassCollectionType: | 
| +        return static_cast<const ClassCollection&>(htmlCollection).elementMatches(element); | 
| +    case TagCollectionType: | 
| +        return static_cast<const TagCollection&>(htmlCollection).elementMatches(element); | 
| +    case HTMLTagCollectionType: | 
| +        return static_cast<const HTMLTagCollection&>(htmlCollection).elementMatches(element); | 
| +    default: | 
| +        break; | 
| +    } | 
| + | 
| +    // The following only applies to HTMLElements. | 
| +    if (!element.isHTMLElement()) | 
| return false; | 
|  | 
| switch (type) { | 
| @@ -229,18 +249,17 @@ template <> inline bool isMatchingElement(const HTMLCollection& htmlCollection, | 
| return (element.hasLocalName(aTag) || element.hasLocalName(areaTag)) && element.fastHasAttribute(hrefAttr); | 
| case DocAnchors: | 
| return element.hasLocalName(aTag) && element.fastHasAttribute(nameAttr); | 
| +    case ClassCollectionType: | 
| +    case TagCollectionType: | 
| +    case HTMLTagCollectionType: | 
| case DocAll: | 
| case NodeChildren: | 
| -        return true; | 
| case FormControls: | 
| case DocumentNamedItems: | 
| case TableRows: | 
| case WindowNamedItems: | 
| case ChildNodeListType: | 
| -    case ClassNodeListType: | 
| case NameNodeListType: | 
| -    case TagNodeListType: | 
| -    case HTMLTagNodeListType: | 
| case RadioNodeListType: | 
| case RadioImgNodeListType: | 
| case LabelsNodeListType: | 
| @@ -254,16 +273,6 @@ template <> inline bool isMatchingElement(const LiveNodeList& nodeList, const El | 
| return nodeList.nodeMatches(element); | 
| } | 
|  | 
| -template <> inline bool isMatchingElement(const HTMLTagNodeList& nodeList, const Element& element) | 
| -{ | 
| -    return nodeList.nodeMatchesInlined(element); | 
| -} | 
| - | 
| -template <> inline bool isMatchingElement(const ClassNodeList& nodeList, const Element& element) | 
| -{ | 
| -    return nodeList.nodeMatchesInlined(element); | 
| -} | 
| - | 
| static Node* previousNode(const Node& base, const Node& previous, bool onlyIncludeDirectChildren) | 
| { | 
| return onlyIncludeDirectChildren ? previous.previousSibling() : NodeTraversal::previous(previous, &base); | 
| @@ -362,10 +371,6 @@ inline Node* LiveNodeList::traverseToFirstElement(const ContainerNode& root) con | 
| switch (type()) { | 
| case ChildNodeListType: | 
| return root.firstChild(); | 
| -    case HTMLTagNodeListType: | 
| -        return firstMatchingElement(static_cast<const HTMLTagNodeList&>(*this), root); | 
| -    case ClassNodeListType: | 
| -        return firstMatchingElement(static_cast<const ClassNodeList&>(*this), root); | 
| default: | 
| return firstMatchingElement(static_cast<const LiveNodeList&>(*this), root); | 
| } | 
| @@ -378,10 +383,6 @@ inline Node* LiveNodeList::traverseForwardToOffset(unsigned offset, Node& curren | 
| switch (type()) { | 
| case ChildNodeListType: | 
| return traverseSiblingsForwardToOffset(offset, currentNode, currentOffset); | 
| -    case HTMLTagNodeListType: | 
| -        return traverseMatchingElementsForwardToOffset(static_cast<const HTMLTagNodeList&>(*this), offset, toElement(currentNode), currentOffset, root); | 
| -    case ClassNodeListType: | 
| -        return traverseMatchingElementsForwardToOffset(static_cast<const ClassNodeList&>(*this), offset, toElement(currentNode), currentOffset, root); | 
| default: | 
| return traverseMatchingElementsForwardToOffset(*this, offset, toElement(currentNode), currentOffset, root); | 
| } | 
|  |