Unify ways to cache named item in HTMLCollections
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 7 May 2013 00:20:05 +0000 (00:20 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 7 May 2013 00:20:05 +0000 (00:20 +0000)
https://bugs.webkit.org/show_bug.cgi?id=115584

Reviewed by Antti Koivisto.

Refactor the code to share the same infrastructure for both id and name attributes maps.

Also get rid of shouldRegisterAsNamedItem and shouldRegisterAsExtraNamedItem from various Element subclasses
as these member functions were duplicating the information in HTMLNameCollection.cpp. Nevertheless, HTMLImageElement
and HTMLObjectElement still update HTMLDocument's window and document name getter maps when their presence as named
item changes due to an attribute change and children changes respectively.

* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::namedItemGetter): Use windowNamedItemMap().containsSingle() instead of collection->hasExactlyOneItem() to
avoid instantiating HTMLCollection until we know for sure we're returning multiple items.
(WebCore::JSDOMWindow::getOwnPropertySlot): Call windowNamedItemMap().contains() instead of document->hasNamedItem()
since the latter has been removed.
(WebCore::JSDOMWindow::getOwnPropertySlotByIndex): Ditto.
(WebCore::JSDOMWindow::getOwnPropertyDescriptor): Ditto.

* bindings/js/JSHTMLDocumentCustom.cpp:
(WebCore::JSHTMLDocument::canGetItemsForName): Call documentNamedItemMap().contains() instead of
document->hasExtraNamedItem() since the latter has been removed.
(WebCore::JSHTMLDocument::nameGetter): Use documentNamedItemMap().containsSingle() instead of
collection->hasExactlyOneItem() to avoid instantiating HTMLCollection when we're returning the first item.

* dom/Document.cpp:
(WebCore::Document::windowNamedItems): Instantiate WindowNameCollection, which is a subclass of HTMLNameCollection,
instead of HTMLNameCollection since the latter class no longer has a public constructor.
(WebCore::Document::documentNamedItems): Ditto; instantiate DocumentNameCollection.

* dom/DocumentOrderedMap.cpp:
(WebCore::keyMatchesName): Added for name attribute.
(WebCore::keyMatchesWindowNamedItem): Added for window name getter.
(WebCore::keyMatchesDocumentNamedItem): Added for document name getter.
(WebCore::DocumentOrderedMap::getElementByName): Added for name attribute.
(WebCore::DocumentOrderedMap::getElementByWindowNamedItem): Added for window name getter.
(WebCore::DocumentOrderedMap::getElementByDocumentNamedItem): Added for document name getter.

* dom/DocumentOrderedMap.h:
(WebCore::DocumentOrderedMap::containsSingle): Added.
(WebCore::DocumentOrderedMap::containsMultiple): Fixed the bug that containsMultiple returns true even when
the duplicate count has been reduced to 1. Unfortunately this behavior change is not testable because the old code
worked properly (though less efficient) even if this function returned a wrong value.

* dom/Element.cpp:
(WebCore::Element::insertedInto):
(WebCore::Element::removedFrom):
(WebCore::Element::updateName): Added. Updates TreeScope's name attribute map as well as HTMLDocument's window name
and document name maps.
(WebCore::Element::updateId): Added the code to update HTMLDocument's window name and document name maps.

* dom/Element.h:
(Element): Removed shouldRegisterAsNamedItem, shouldRegisterAsExtraNamedItem, updateNamedItemRegistration, and
updateExtraNamedItemRegistration as they're no longer used.

* dom/TreeScope.cpp:
(SameSizeAsTreeScope):
(WebCore::TreeScope::getElementByName): Added.
(WebCore::TreeScope::addElementByName): Added.
(WebCore::TreeScope::removeElementByName): Added.

* dom/TreeScope.h:
(WebCore::TreeScope::hasElementWithName): Added.
(WebCore::TreeScope::containsMultipleElementsWithName): Added.

* html/HTMLAppletElement.h:
(HTMLAppletElement):

* html/HTMLCollection.cpp:
(WebCore::isMatchingElement): Use HTMLNameCollection subclasses' nodeMatches.
(WebCore::HTMLCollection::namedItem): Added a fast path for named item.
(WebCore::HTMLCollection::hasNamedItem): Use namedItem to avoid the work in the fast path.

* html/HTMLCollection.h:
(HTMLCollection): Removed checkForNameMatch.
* html/HTMLDocument.cpp:
(WebCore): Removed various member functions related to m_namedItemCounts and m_extraNamedItemCounts.

* html/HTMLDocument.h:
(WebCore::HTMLDocument::documentNamedItemMap): Added.
(WebCore::HTMLDocument::windowNamedItemMap): Added.
(HTMLDocument): Replaced m_namedItemCounts and m_extraNamedItemCounts by m_documentNamedItem and m_windowNamedItem.
Note that they're not one to one.

* html/HTMLEmbedElement.h:
(HTMLEmbedElement):

* html/HTMLFormElement.h:
(HTMLFormElement):

* html/HTMLIFrameElement.cpp: Removed the code to track the element's name since we already do this in Element.
(WebCore::HTMLIFrameElement::parseAttribute):

* html/HTMLIFrameElement.h:
(HTMLIFrameElement):

* html/HTMLImageElement.cpp:
(WebCore::HTMLImageElement::parseAttribute): Update the HTMLDocument's maps when the name attribute's existence
changes its presence on window and document name getters in turn. This behavior change, again, appears to be
untestable due to the old being more graceful when DocumentOrderedMap returned a wrong value.

* html/HTMLImageElement.h:

* html/HTMLNameCollection.cpp:
(WebCore::HTMLNameCollection::HTMLNameCollection): No longer overrides itemAfter. This enables backwards traversals
of the tree along with other optimizations in HTMLCollection.

(WebCore::WindowNameCollection::nodeMatchesIfNameAttributeMatch): Added. Used in Element::updateName to determine
whether add() or remove() should be called on HTMLDocument's maps.
(WebCore::WindowNameCollection::nodeMatches): Added.

(WebCore::DocumentNameCollection::nodeMatchesIfIdAttributeMatch): Added. Used in Element::updateName to determine
whether add() or remove() should be called on HTMLDocument's maps.
(WebCore::DocumentNameCollection::nodeMatchesIfNameAttributeMatch): Ditto.
(WebCore::DocumentNameCollection::nodeMatches): Added.

* html/HTMLNameCollection.h:
(HTMLNameCollection): Removed create since this class shouldn't be instantiated on its own.

(WebCore::WindowNameCollection): Added.
(WebCore::WindowNameCollection::create): Added.
(WebCore::WindowNameCollection::nodeMatches): Added.
(WebCore::WindowNameCollection::nodeMatchesIfIdAttributeMatch): Added.
(WebCore::WindowNameCollection::WindowNameCollection): Added.
(WebCore::DocumentNameCollection): Added.
(WebCore::DocumentNameCollection::create): Added.
(WebCore::DocumentNameCollection::nodeMatches): Added.
(WebCore::DocumentNameCollection::DocumentNameCollection): Added.

* html/HTMLObjectElement.cpp:
(WebCore::HTMLObjectElement::updateDocNamedItem): Update both window and document getter maps of HTMLDocument when
the visibility of this element changes due to the DOM mutations in the subtree.

* html/HTMLObjectElement.h:
(WebCore::HTMLObjectElement):
(WebCore::toHTMLObjectElement): Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@149652 268f45cc-cd09-0410-ab3c-d52691b4dbfc

25 files changed:
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSDOMWindowCustom.cpp
Source/WebCore/bindings/js/JSHTMLDocumentCustom.cpp
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/DocumentOrderedMap.cpp
Source/WebCore/dom/DocumentOrderedMap.h
Source/WebCore/dom/Element.cpp
Source/WebCore/dom/Element.h
Source/WebCore/dom/TreeScope.cpp
Source/WebCore/dom/TreeScope.h
Source/WebCore/html/HTMLAppletElement.h
Source/WebCore/html/HTMLCollection.cpp
Source/WebCore/html/HTMLCollection.h
Source/WebCore/html/HTMLDocument.cpp
Source/WebCore/html/HTMLDocument.h
Source/WebCore/html/HTMLEmbedElement.h
Source/WebCore/html/HTMLFormElement.h
Source/WebCore/html/HTMLIFrameElement.cpp
Source/WebCore/html/HTMLIFrameElement.h
Source/WebCore/html/HTMLImageElement.cpp
Source/WebCore/html/HTMLImageElement.h
Source/WebCore/html/HTMLNameCollection.cpp
Source/WebCore/html/HTMLNameCollection.h
Source/WebCore/html/HTMLObjectElement.cpp
Source/WebCore/html/HTMLObjectElement.h

index dfbe278ca4f89dfa47591eae9466053cd00613d4..dd73dd4ce88abbae21da0f2193c1196cbb02fb3c 100644 (file)
@@ -1,3 +1,143 @@
+2013-05-06  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Unify ways to cache named item in HTMLCollections
+        https://bugs.webkit.org/show_bug.cgi?id=115584
+
+        Reviewed by Antti Koivisto.
+
+        Refactor the code to share the same infrastructure for both id and name attributes maps.
+
+        Also get rid of shouldRegisterAsNamedItem and shouldRegisterAsExtraNamedItem from various Element subclasses
+        as these member functions were duplicating the information in HTMLNameCollection.cpp. Nevertheless, HTMLImageElement
+        and HTMLObjectElement still update HTMLDocument's window and document name getter maps when their presence as named
+        item changes due to an attribute change and children changes respectively.
+
+        * bindings/js/JSDOMWindowCustom.cpp:
+        (WebCore::namedItemGetter): Use windowNamedItemMap().containsSingle() instead of collection->hasExactlyOneItem() to
+        avoid instantiating HTMLCollection until we know for sure we're returning multiple items.
+        (WebCore::JSDOMWindow::getOwnPropertySlot): Call windowNamedItemMap().contains() instead of document->hasNamedItem()
+        since the latter has been removed.
+        (WebCore::JSDOMWindow::getOwnPropertySlotByIndex): Ditto.
+        (WebCore::JSDOMWindow::getOwnPropertyDescriptor): Ditto.
+
+        * bindings/js/JSHTMLDocumentCustom.cpp:
+        (WebCore::JSHTMLDocument::canGetItemsForName): Call documentNamedItemMap().contains() instead of
+        document->hasExtraNamedItem() since the latter has been removed.
+        (WebCore::JSHTMLDocument::nameGetter): Use documentNamedItemMap().containsSingle() instead of
+        collection->hasExactlyOneItem() to avoid instantiating HTMLCollection when we're returning the first item.
+
+        * dom/Document.cpp:
+        (WebCore::Document::windowNamedItems): Instantiate WindowNameCollection, which is a subclass of HTMLNameCollection,
+        instead of HTMLNameCollection since the latter class no longer has a public constructor.
+        (WebCore::Document::documentNamedItems): Ditto; instantiate DocumentNameCollection.
+
+        * dom/DocumentOrderedMap.cpp:
+        (WebCore::keyMatchesName): Added for name attribute.
+        (WebCore::keyMatchesWindowNamedItem): Added for window name getter.
+        (WebCore::keyMatchesDocumentNamedItem): Added for document name getter.
+        (WebCore::DocumentOrderedMap::getElementByName): Added for name attribute.
+        (WebCore::DocumentOrderedMap::getElementByWindowNamedItem): Added for window name getter.
+        (WebCore::DocumentOrderedMap::getElementByDocumentNamedItem): Added for document name getter.
+
+        * dom/DocumentOrderedMap.h:
+        (WebCore::DocumentOrderedMap::containsSingle): Added.
+        (WebCore::DocumentOrderedMap::containsMultiple): Fixed the bug that containsMultiple returns true even when
+        the duplicate count has been reduced to 1. Unfortunately this behavior change is not testable because the old code
+        worked properly (though less efficient) even if this function returned a wrong value.
+
+        * dom/Element.cpp:
+        (WebCore::Element::insertedInto):
+        (WebCore::Element::removedFrom):
+        (WebCore::Element::updateName): Added. Updates TreeScope's name attribute map as well as HTMLDocument's window name
+        and document name maps.
+        (WebCore::Element::updateId): Added the code to update HTMLDocument's window name and document name maps.
+
+        * dom/Element.h:
+        (Element): Removed shouldRegisterAsNamedItem, shouldRegisterAsExtraNamedItem, updateNamedItemRegistration, and
+        updateExtraNamedItemRegistration as they're no longer used.
+
+        * dom/TreeScope.cpp:
+        (SameSizeAsTreeScope):
+        (WebCore::TreeScope::getElementByName): Added.
+        (WebCore::TreeScope::addElementByName): Added.
+        (WebCore::TreeScope::removeElementByName): Added.
+
+        * dom/TreeScope.h:
+        (WebCore::TreeScope::hasElementWithName): Added.
+        (WebCore::TreeScope::containsMultipleElementsWithName): Added.
+
+        * html/HTMLAppletElement.h:
+        (HTMLAppletElement):
+
+        * html/HTMLCollection.cpp:
+        (WebCore::isMatchingElement): Use HTMLNameCollection subclasses' nodeMatches.
+        (WebCore::HTMLCollection::namedItem): Added a fast path for named item.
+        (WebCore::HTMLCollection::hasNamedItem): Use namedItem to avoid the work in the fast path.
+
+        * html/HTMLCollection.h:
+        (HTMLCollection): Removed checkForNameMatch.
+        * html/HTMLDocument.cpp:
+        (WebCore): Removed various member functions related to m_namedItemCounts and m_extraNamedItemCounts.
+
+        * html/HTMLDocument.h:
+        (WebCore::HTMLDocument::documentNamedItemMap): Added.
+        (WebCore::HTMLDocument::windowNamedItemMap): Added.
+        (HTMLDocument): Replaced m_namedItemCounts and m_extraNamedItemCounts by m_documentNamedItem and m_windowNamedItem.
+        Note that they're not one to one.
+
+        * html/HTMLEmbedElement.h:
+        (HTMLEmbedElement):
+
+        * html/HTMLFormElement.h:
+        (HTMLFormElement):
+
+        * html/HTMLIFrameElement.cpp: Removed the code to track the element's name since we already do this in Element.
+        (WebCore::HTMLIFrameElement::parseAttribute):
+
+        * html/HTMLIFrameElement.h:
+        (HTMLIFrameElement):
+
+        * html/HTMLImageElement.cpp:
+        (WebCore::HTMLImageElement::parseAttribute): Update the HTMLDocument's maps when the name attribute's existence
+        changes its presence on window and document name getters in turn. This behavior change, again, appears to be
+        untestable due to the old being more graceful when DocumentOrderedMap returned a wrong value.
+
+        * html/HTMLImageElement.h:
+
+        * html/HTMLNameCollection.cpp:
+        (WebCore::HTMLNameCollection::HTMLNameCollection): No longer overrides itemAfter. This enables backwards traversals
+        of the tree along with other optimizations in HTMLCollection.
+
+        (WebCore::WindowNameCollection::nodeMatchesIfNameAttributeMatch): Added. Used in Element::updateName to determine
+        whether add() or remove() should be called on HTMLDocument's maps.
+        (WebCore::WindowNameCollection::nodeMatches): Added.
+
+        (WebCore::DocumentNameCollection::nodeMatchesIfIdAttributeMatch): Added. Used in Element::updateName to determine
+        whether add() or remove() should be called on HTMLDocument's maps.
+        (WebCore::DocumentNameCollection::nodeMatchesIfNameAttributeMatch): Ditto.
+        (WebCore::DocumentNameCollection::nodeMatches): Added.
+
+        * html/HTMLNameCollection.h:
+        (HTMLNameCollection): Removed create since this class shouldn't be instantiated on its own.
+
+        (WebCore::WindowNameCollection): Added.
+        (WebCore::WindowNameCollection::create): Added.
+        (WebCore::WindowNameCollection::nodeMatches): Added.
+        (WebCore::WindowNameCollection::nodeMatchesIfIdAttributeMatch): Added.
+        (WebCore::WindowNameCollection::WindowNameCollection): Added.
+        (WebCore::DocumentNameCollection): Added.
+        (WebCore::DocumentNameCollection::create): Added.
+        (WebCore::DocumentNameCollection::nodeMatches): Added.
+        (WebCore::DocumentNameCollection::DocumentNameCollection): Added.
+
+        * html/HTMLObjectElement.cpp:
+        (WebCore::HTMLObjectElement::updateDocNamedItem): Update both window and document getter maps of HTMLDocument when
+        the visibility of this element changes due to the DOM mutations in the subtree.
+
+        * html/HTMLObjectElement.h:
+        (WebCore::HTMLObjectElement):
+        (WebCore::toHTMLObjectElement): Added.
+
 2013-05-06  Andreas Kling  <akling@apple.com>
 
         Flaky Test: fast/frames/crash-remove-iframe-during-object-beforeload.html
index c9bd75d1e072b5bf95137c4ecd2f872e8cbb3d8a..725e895ccfacb62cde13f2b9abd26ff0da690df6 100644 (file)
@@ -95,10 +95,19 @@ static JSValue namedItemGetter(ExecState* exec, JSValue slotBase, PropertyName p
     ASSERT(document);
     ASSERT(document->isHTMLDocument());
 
-    RefPtr<HTMLCollection> collection = document->windowNamedItems(propertyNameToAtomicString(propertyName));
-    if (collection->hasExactlyOneItem())
-        return toJS(exec, thisObj, collection->item(0));
-    return toJS(exec, thisObj, WTF::getPtr(collection));
+    AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName);
+    if (!atomicPropertyName || !toHTMLDocument(document)->windowNamedItemMap().contains(atomicPropertyName))
+        return jsUndefined();
+
+    if (UNLIKELY(!toHTMLDocument(document)->windowNamedItemMap().containsSingle(atomicPropertyName))) {
+        RefPtr<HTMLCollection> collection = document->windowNamedItems(atomicPropertyName);
+        ASSERT(!collection->isEmpty());
+        ASSERT(!collection->hasExactlyOneItem());
+        return toJS(exec, thisObj->globalObject(), WTF::getPtr(collection));
+    }
+
+    Node* node = toHTMLDocument(document)->windowNamedItemMap().getElementByWindowNamedItem(atomicPropertyName, document);
+    return toJS(exec, thisObj->globalObject(), node);
 }
 
 bool JSDOMWindow::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
@@ -238,7 +247,7 @@ bool JSDOMWindow::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName
     Document* document = thisObject->impl()->frame()->document();
     if (document->isHTMLDocument()) {
         AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName);
-        if (atomicPropertyName && (toHTMLDocument(document)->hasNamedItem(atomicPropertyName) || document->hasElementWithId(atomicPropertyName))) {
+        if (atomicPropertyName && toHTMLDocument(document)->windowNamedItemMap().contains(atomicPropertyName)) {
             slot.setCustom(thisObject, namedItemGetter);
             return true;
         }
@@ -314,7 +323,7 @@ bool JSDOMWindow::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsig
     Document* document = thisObject->impl()->frame()->document();
     if (document->isHTMLDocument()) {
         AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName);
-        if (atomicPropertyName && (toHTMLDocument(document)->hasNamedItem(atomicPropertyName) || document->hasElementWithId(atomicPropertyName))) {
+        if (atomicPropertyName && toHTMLDocument(document)->windowNamedItemMap().contains(atomicPropertyName)) {
             slot.setCustom(thisObject, namedItemGetter);
             return true;
         }
@@ -385,7 +394,7 @@ bool JSDOMWindow::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Pr
     Document* document = thisObject->impl()->frame()->document();
     if (document->isHTMLDocument()) {
         AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName);
-        if (atomicPropertyName && (toHTMLDocument(document)->hasNamedItem(atomicPropertyName) || document->hasElementWithId(atomicPropertyName))) {
+        if (atomicPropertyName && toHTMLDocument(document)->windowNamedItemMap().contains(atomicPropertyName)) {
             PropertySlot slot;
             slot.setCustom(thisObject, namedItemGetter);
             descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
index c3d19a60d10bd76960b6ef3505c32a6fb23c3833..4bdefa92f37e941bf815f49447a8f2289d2be4ef 100644 (file)
@@ -54,7 +54,7 @@ using namespace HTMLNames;
 bool JSHTMLDocument::canGetItemsForName(ExecState*, HTMLDocument* document, PropertyName propertyName)
 {
     AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName);
-    return atomicPropertyName && (document->hasNamedItem(atomicPropertyName) || document->hasExtraNamedItem(atomicPropertyName));
+    return atomicPropertyName && document->documentNamedItemMap().contains(atomicPropertyName);
 }
 
 JSValue JSHTMLDocument::nameGetter(ExecState* exec, JSValue slotBase, PropertyName propertyName)
@@ -62,22 +62,23 @@ JSValue JSHTMLDocument::nameGetter(ExecState* exec, JSValue slotBase, PropertyNa
     JSHTMLDocument* thisObj = jsCast<JSHTMLDocument*>(asObject(slotBase));
     HTMLDocument* document = toHTMLDocument(thisObj->impl());
 
-    RefPtr<HTMLCollection> collection = document->documentNamedItems(propertyNameToAtomicString(propertyName));
-
-    if (collection->isEmpty())
+    AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName);
+    if (!atomicPropertyName || !document->documentNamedItemMap().contains(atomicPropertyName))
         return jsUndefined();
 
-    if (collection->hasExactlyOneItem()) {
-        Node* node = collection->item(0);
-
-        Frame* frame;
-        if (node->hasTagName(iframeTag) && (frame = static_cast<HTMLIFrameElement*>(node)->contentFrame()))
-            return toJS(exec, frame);
+    if (UNLIKELY(!document->documentNamedItemMap().containsSingle(atomicPropertyName))) {
+        RefPtr<HTMLCollection> collection = document->documentNamedItems(atomicPropertyName);
+        ASSERT(!collection->isEmpty());
+        ASSERT(!collection->hasExactlyOneItem());
+        return toJS(exec, thisObj->globalObject(), WTF::getPtr(collection));
+    }
 
-        return toJS(exec, thisObj->globalObject(), node);
-    } 
+    Node* node = document->documentNamedItemMap().getElementByDocumentNamedItem(atomicPropertyName, document);
+    Frame* frame;
+    if (node->hasTagName(iframeTag) && (frame = static_cast<HTMLIFrameElement*>(node)->contentFrame()))
+        return toJS(exec, frame);
 
-    return toJS(exec, thisObj->globalObject(), WTF::getPtr(collection));
+    return toJS(exec, thisObj->globalObject(), node);
 }
 
 // Custom attributes
index 41559cdd9633d7a26cd89af5ee03348242678869..6e730971c33b27f4755d6e3c03a55e69c34088ce 100644 (file)
@@ -4419,12 +4419,12 @@ PassRefPtr<HTMLCollection> Document::all()
 
 PassRefPtr<HTMLCollection> Document::windowNamedItems(const AtomicString& name)
 {
-    return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLNameCollection>(this, WindowNamedItems, name);
+    return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<WindowNameCollection>(this, WindowNamedItems, name);
 }
 
 PassRefPtr<HTMLCollection> Document::documentNamedItems(const AtomicString& name)
 {
-    return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLNameCollection>(this, DocumentNamedItems, name);
+    return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<DocumentNameCollection>(this, DocumentNamedItems, name);
 }
 
 void Document::finishedParsing()
index 599e163bc53b07752296a02dcc05f99c6063a04c..e8e77f95fca46891c8214442cd854c312839b6a4 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "Element.h"
 #include "HTMLMapElement.h"
+#include "HTMLNameCollection.h"
 #include "HTMLNames.h"
 #include "NodeTraversal.h"
 #include "TreeScope.h"
@@ -46,6 +47,11 @@ inline bool keyMatchesId(AtomicStringImpl* key, Element* element)
     return element->getIdAttribute().impl() == key;
 }
 
+inline bool keyMatchesName(AtomicStringImpl* key, Element* element)
+{
+    return element->getNameAttribute().impl() == key;
+}
+
 inline bool keyMatchesMapName(AtomicStringImpl* key, Element* element)
 {
     return element->hasTagName(mapTag) && static_cast<HTMLMapElement*>(element)->getName().impl() == key;
@@ -61,6 +67,16 @@ inline bool keyMatchesLabelForAttribute(AtomicStringImpl* key, Element* element)
     return element->hasTagName(labelTag) && element->getAttribute(forAttr).impl() == key;
 }
 
+inline bool keyMatchesWindowNamedItem(AtomicStringImpl* key, Element* element)
+{
+    return WindowNameCollection::nodeMatches(element, key);
+}
+
+inline bool keyMatchesDocumentNamedItem(AtomicStringImpl* key, Element* element)
+{
+    return DocumentNameCollection::nodeMatches(element, key);
+}
+
 void DocumentOrderedMap::clear()
 {
     m_map.clear();
@@ -142,6 +158,11 @@ Element* DocumentOrderedMap::getElementById(AtomicStringImpl* key, const TreeSco
     return get<keyMatchesId>(key, scope);
 }
 
+Element* DocumentOrderedMap::getElementByName(AtomicStringImpl* key, const TreeScope* scope) const
+{
+    return get<keyMatchesName>(key, scope);
+}
+
 Element* DocumentOrderedMap::getElementByMapName(AtomicStringImpl* key, const TreeScope* scope) const
 {
     return get<keyMatchesMapName>(key, scope);
@@ -157,4 +178,14 @@ Element* DocumentOrderedMap::getElementByLabelForAttribute(AtomicStringImpl* key
     return get<keyMatchesLabelForAttribute>(key, scope);
 }
 
+Element* DocumentOrderedMap::getElementByWindowNamedItem(AtomicStringImpl* key, const TreeScope* scope) const
+{
+    return get<keyMatchesWindowNamedItem>(key, scope);
+}
+
+Element* DocumentOrderedMap::getElementByDocumentNamedItem(AtomicStringImpl* key, const TreeScope* scope) const
+{
+    return get<keyMatchesDocumentNamedItem>(key, scope);
+}
+
 } // namespace WebCore
index 1f9039e6143d38628dfa300ae986a01ee323c7d5..82961cc67a3efcca0c222491399a81bab2beb703 100644 (file)
@@ -47,12 +47,16 @@ public:
     void clear();
 
     bool contains(AtomicStringImpl*) const;
+    bool containsSingle(AtomicStringImpl*) const;
     bool containsMultiple(AtomicStringImpl*) const;
     // concrete instantiations of the get<>() method template
     Element* getElementById(AtomicStringImpl*, const TreeScope*) const;
+    Element* getElementByName(AtomicStringImpl*, const TreeScope*) const;
     Element* getElementByMapName(AtomicStringImpl*, const TreeScope*) const;
     Element* getElementByLowercasedMapName(AtomicStringImpl*, const TreeScope*) const;
     Element* getElementByLabelForAttribute(AtomicStringImpl*, const TreeScope*) const;
+    Element* getElementByWindowNamedItem(AtomicStringImpl*, const TreeScope*) const;
+    Element* getElementByDocumentNamedItem(AtomicStringImpl*, const TreeScope*) const;
 
     void checkConsistency() const;
 
@@ -68,6 +72,11 @@ private:
     mutable HashCountedSet<AtomicStringImpl*> m_duplicateCounts;
 };
 
+inline bool DocumentOrderedMap::containsSingle(AtomicStringImpl* id) const
+{
+    return (m_map.contains(id) ? 1 : 0) + m_duplicateCounts.count(id) == 1;
+}
+
 inline bool DocumentOrderedMap::contains(AtomicStringImpl* id) const
 {
     return m_map.contains(id) || m_duplicateCounts.contains(id);
@@ -75,7 +84,7 @@ inline bool DocumentOrderedMap::contains(AtomicStringImpl* id) const
 
 inline bool DocumentOrderedMap::containsMultiple(AtomicStringImpl* id) const
 {
-    return m_duplicateCounts.contains(id);
+    return (m_map.contains(id) ? 1 : 0) + m_duplicateCounts.count(id) > 1;
 }
 
 } // namespace WebCore
index 8e7cf0cd09ac7b08eaf7d5dcd8825f00bd12fec7..d324cb040e4b47dc9bf9a3aeba23481a129c109d 100644 (file)
@@ -52,6 +52,7 @@
 #include "HTMLFormControlsCollection.h"
 #include "HTMLFrameOwnerElement.h"
 #include "HTMLLabelElement.h"
+#include "HTMLNameCollection.h"
 #include "HTMLNames.h"
 #include "HTMLOptionsCollection.h"
 #include "HTMLParserIdioms.h"
@@ -1217,7 +1218,7 @@ Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertio
 
     const AtomicString& nameValue = getNameAttribute();
     if (!nameValue.isNull())
-        updateName(nullAtom, nameValue);
+        updateName(scope, nullAtom, nameValue);
 
     if (hasTagName(labelTag)) {
         if (scope->shouldCacheLabelsByForAttribute())
@@ -1260,7 +1261,7 @@ void Element::removedFrom(ContainerNode* insertionPoint)
 
         const AtomicString& nameValue = getNameAttribute();
         if (!nameValue.isNull())
-            updateName(nameValue, nullAtom);
+            updateName(insertionPoint->treeScope(), nameValue, nullAtom);
 
         if (hasTagName(labelTag)) {
             TreeScope* treeScope = insertionPoint->treeScope();
@@ -2659,14 +2660,45 @@ bool Element::hasNamedNodeMap() const
 
 inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName)
 {
-    if (!inDocument() || isInShadowTree())
+    if (!isInTreeScope())
         return;
 
     if (oldName == newName)
         return;
 
-    if (shouldRegisterAsNamedItem())
-        updateNamedItemRegistration(oldName, newName);
+    updateName(treeScope(), oldName, newName);
+}
+
+void Element::updateName(TreeScope* scope, const AtomicString& oldName, const AtomicString& newName)
+{
+    ASSERT(isInTreeScope());
+    ASSERT(oldName != newName);
+
+    if (!oldName.isEmpty())
+        scope->removeElementByName(oldName, this);
+    if (!newName.isEmpty())
+        scope->addElementByName(newName, this);
+
+    if (!inDocument())
+        return;
+    
+    Document* ownerDocument = document();
+    if (!ownerDocument->isHTMLDocument())
+        return;
+
+    if (WindowNameCollection::nodeMatchesIfNameAttributeMatch(this)) {
+        if (!oldName.isEmpty())
+            toHTMLDocument(ownerDocument)->windowNamedItemMap().remove(oldName.impl(), this);
+        if (!newName.isEmpty())
+            toHTMLDocument(ownerDocument)->windowNamedItemMap().add(newName.impl(), this);
+    }
+
+    if (DocumentNameCollection::nodeMatchesIfNameAttributeMatch(this)) {
+        if (!oldName.isEmpty())
+            toHTMLDocument(ownerDocument)->documentNamedItemMap().remove(oldName.impl(), this);
+        if (!newName.isEmpty())
+            toHTMLDocument(ownerDocument)->documentNamedItemMap().add(newName.impl(), this);
+    }
 }
 
 inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId)
@@ -2680,7 +2712,7 @@ inline void Element::updateId(const AtomicString& oldId, const AtomicString& new
     updateId(treeScope(), oldId, newId);
 }
 
-inline void Element::updateId(TreeScope* scope, const AtomicString& oldId, const AtomicString& newId)
+void Element::updateId(TreeScope* scope, const AtomicString& oldId, const AtomicString& newId)
 {
     ASSERT(isInTreeScope());
     ASSERT(oldId != newId);
@@ -2690,8 +2722,26 @@ inline void Element::updateId(TreeScope* scope, const AtomicString& oldId, const
     if (!newId.isEmpty())
         scope->addElementById(newId, this);
 
-    if (shouldRegisterAsExtraNamedItem())
-        updateExtraNamedItemRegistration(oldId, newId);
+    if (!inDocument())
+        return;
+
+    Document* ownerDocument = document();
+    if (!ownerDocument->isHTMLDocument())
+        return;
+
+    if (WindowNameCollection::nodeMatchesIfIdAttributeMatch(this)) {
+        if (!oldId.isEmpty())
+            toHTMLDocument(ownerDocument)->windowNamedItemMap().remove(oldId.impl(), this);
+        if (!newId.isEmpty())
+            toHTMLDocument(ownerDocument)->windowNamedItemMap().add(newId.impl(), this);
+    }
+
+    if (DocumentNameCollection::nodeMatchesIfIdAttributeMatch(this)) {
+        if (!oldId.isEmpty())
+            toHTMLDocument(ownerDocument)->documentNamedItemMap().remove(oldId.impl(), this);
+        if (!newId.isEmpty())
+            toHTMLDocument(ownerDocument)->documentNamedItemMap().add(newId.impl(), this);
+    }
 }
 
 void Element::updateLabel(TreeScope* scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
@@ -2756,31 +2806,6 @@ void Element::didRemoveAttribute(const QualifiedName& name)
     dispatchSubtreeModifiedEvent();
 }
 
-
-void Element::updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName)
-{
-    if (!document()->isHTMLDocument())
-        return;
-
-    if (!oldName.isEmpty())
-        toHTMLDocument(document())->removeNamedItem(oldName);
-
-    if (!newName.isEmpty())
-        toHTMLDocument(document())->addNamedItem(newName);
-}
-
-void Element::updateExtraNamedItemRegistration(const AtomicString& oldId, const AtomicString& newId)
-{
-    if (!document()->isHTMLDocument())
-        return;
-
-    if (!oldId.isEmpty())
-        toHTMLDocument(document())->removeExtraNamedItem(oldId);
-
-    if (!newId.isEmpty())
-        toHTMLDocument(document())->addExtraNamedItem(newId);
-}
-
 PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type)
 {
     if (HTMLCollection* collection = cachedHTMLCollection(type))
index a093056d5f940c80a1191f480472d5350b0153f9..8b34a5edc37c9bb74a35878792c13aa16ec64b17 100644 (file)
@@ -639,9 +639,6 @@ protected:
     virtual void didRecalcStyle(StyleChange);
     virtual PassRefPtr<RenderStyle> customStyleForRenderer();
 
-    virtual bool shouldRegisterAsNamedItem() const { return false; }
-    virtual bool shouldRegisterAsExtraNamedItem() const { return false; }
-
     void clearTabIndexExplicitlyIfNeeded();    
     void setTabIndexExplicitly(short);
     virtual bool supportsFocus() const OVERRIDE;
@@ -680,6 +677,7 @@ private:
     void updateId(const AtomicString& oldId, const AtomicString& newId);
     void updateId(TreeScope*, const AtomicString& oldId, const AtomicString& newId);
     void updateName(const AtomicString& oldName, const AtomicString& newName);
+    void updateName(TreeScope*, const AtomicString& oldName, const AtomicString& newName);
     void updateLabel(TreeScope*, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue);
 
     void scrollByUnits(int units, ScrollGranularity);
@@ -725,9 +723,6 @@ private:
 
     SpellcheckAttributeState spellcheckAttributeState() const;
 
-    void updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName);
-    void updateExtraNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName);
-
     void unregisterNamedFlowContentNode();
 
     void createUniqueElementData();
index 3fe26ea2469b9cc810086f5e02601adc473d8337..445b5fcb5ccaba60fe8f513314a39d0f75847a02 100644 (file)
@@ -58,7 +58,7 @@ namespace WebCore {
 
 struct SameSizeAsTreeScope {
     virtual ~SameSizeAsTreeScope();
-    void* pointers[8];
+    void* pointers[9];
     int ints[1];
 };
 
@@ -165,6 +165,29 @@ void TreeScope::removeElementById(const AtomicString& elementId, Element* elemen
     m_idTargetObserverRegistry->notifyObservers(elementId);
 }
 
+Element* TreeScope::getElementByName(const AtomicString& name) const
+{
+    if (name.isEmpty())
+        return 0;
+    if (!m_elementsByName)
+        return 0;
+    return m_elementsByName->getElementByName(name.impl(), this);
+}
+
+void TreeScope::addElementByName(const AtomicString& name, Element* element)
+{
+    if (!m_elementsByName)
+        m_elementsByName = adoptPtr(new DocumentOrderedMap);
+    m_elementsByName->add(name.impl(), element);
+}
+
+void TreeScope::removeElementByName(const AtomicString& name, Element* element)
+{
+    if (!m_elementsByName)
+        return;
+    m_elementsByName->remove(name.impl(), element);
+}
+
 Node* TreeScope::ancestorInThisScope(Node* node) const
 {
     while (node) {
index d1bef158dabbfe3ae83c39a802f693f335c6788f..8b76e50e34f39a2e1496aff87234103fa7095d5f 100644 (file)
@@ -61,6 +61,12 @@ public:
     void addElementById(const AtomicString& elementId, Element*);
     void removeElementById(const AtomicString& elementId, Element*);
 
+    Element* getElementByName(const AtomicString&) const;
+    bool hasElementWithName(AtomicStringImpl*) const;
+    bool containsMultipleElementsWithName(const AtomicString&) const;
+    void addElementByName(const AtomicString&, Element*);
+    void removeElementByName(const AtomicString&, Element*);
+
     Document* documentScope() const { return m_documentScope; }
 
     Node* ancestorInThisScope(Node*) const;
@@ -161,6 +167,7 @@ private:
     int m_guardRefCount;
 
     OwnPtr<DocumentOrderedMap> m_elementsById;
+    OwnPtr<DocumentOrderedMap> m_elementsByName;
     OwnPtr<DocumentOrderedMap> m_imageMapsByName;
     OwnPtr<DocumentOrderedMap> m_labelsByForAttribute;
 
@@ -180,6 +187,17 @@ inline bool TreeScope::containsMultipleElementsWithId(const AtomicString& id) co
     return m_elementsById && m_elementsById->containsMultiple(id.impl());
 }
 
+inline bool TreeScope::hasElementWithName(AtomicStringImpl* id) const
+{
+    ASSERT(id);
+    return m_elementsByName && m_elementsByName->contains(id);
+}
+
+inline bool TreeScope::containsMultipleElementsWithName(const AtomicString& name) const
+{
+    return m_elementsByName && m_elementsByName->containsMultiple(name.impl());
+}
+
 Node* nodeFromPoint(Document*, int x, int y, LayoutPoint* localPoint = 0);
 TreeScope* commonTreeScope(Node*, Node*);
 
index ac88a204fec5eef82f7e38c18ba30a30432477f9..d0e86c0f63a9fb521e8296d0cef179de49ea588d 100644 (file)
@@ -43,9 +43,6 @@ private:
     virtual void updateWidget(PluginCreationOption) OVERRIDE;
 
     bool canEmbedJava() const;
-
-    virtual bool shouldRegisterAsNamedItem() const OVERRIDE { return true; }
-    virtual bool shouldRegisterAsExtraNamedItem() const OVERRIDE { return true; }
 };
 
 }
index 4c2658237691e1afd9a8b34483bce879c9448bfb..36e1d5346f61157876f2d84ccea6f8f2a238597f 100644 (file)
@@ -26,6 +26,7 @@
 #include "ClassNodeList.h"
 #include "HTMLDocument.h"
 #include "HTMLElement.h"
+#include "HTMLNameCollection.h"
 #include "HTMLNames.h"
 #include "HTMLObjectElement.h"
 #include "HTMLOptionElement.h"
@@ -244,14 +245,16 @@ template <> inline bool isMatchingElement(const HTMLCollection* htmlCollection,
     case DocAll:
     case NodeChildren:
         return true;
+    case DocumentNamedItems:
+        return static_cast<const DocumentNameCollection*>(htmlCollection)->nodeMatches(element);
+    case WindowNamedItems:
+        return static_cast<const WindowNameCollection*>(htmlCollection)->nodeMatches(element);
 #if ENABLE(MICRODATA)
     case ItemProperties:
         return element->fastHasAttribute(itempropAttr);
 #endif
     case FormControls:
-    case DocumentNamedItems:
     case TableRows:
-    case WindowNamedItems:
     case ChildNodeListType:
     case ClassNodeListType:
     case NameNodeListType:
@@ -543,21 +546,6 @@ static inline bool nameShouldBeVisibleInDocumentAll(HTMLElement* element)
         || element->hasLocalName(selectTag);
 }
 
-bool HTMLCollection::checkForNameMatch(Element* element, bool checkName, const AtomicString& name) const
-{
-    if (!element->isHTMLElement())
-        return false;
-    
-    HTMLElement* e = toHTMLElement(element);
-    if (!checkName)
-        return e->getIdAttribute() == name;
-
-    if (type() == DocAll && !nameShouldBeVisibleInDocumentAll(e))
-        return false;
-
-    return e->getNameAttribute() == name && e->getIdAttribute() != name;
-}
-
 inline Element* firstMatchingChildElement(const HTMLCollection* nodeList, ContainerNode* root)
 {
     Element* element = ElementTraversal::firstWithin(root);
@@ -624,26 +612,41 @@ Node* HTMLCollection::namedItem(const AtomicString& name) const
     // that are allowed a name attribute.
 
     ContainerNode* root = rootContainerNode();
-    if (!root)
+    if (name.isEmpty() || !root)
         return 0;
 
-    unsigned arrayOffset = 0;
-    unsigned i = 0;
-    for (Element* element = traverseFirstElement(arrayOffset, root); element; element = traverseNextElement(arrayOffset, element, root)) {
-        if (checkForNameMatch(element, /* checkName */ false, name)) {
-            setItemCache(element, i, arrayOffset);
-            return element;
-        }
-        i++;
+    if (!overridesItemAfter()) {
+        TreeScope* treeScope = root->treeScope();
+        Element* candidate = 0;
+        if (treeScope->hasElementWithId(name.impl())) {
+            if (!treeScope->containsMultipleElementsWithId(name))
+                candidate = treeScope->getElementById(name);
+        } else if (treeScope->hasElementWithName(name.impl())) {
+            if (!treeScope->containsMultipleElementsWithName(name)) {
+                candidate = treeScope->getElementByName(name);
+                if (candidate && type() == DocAll && (!candidate->isHTMLElement() || !nameShouldBeVisibleInDocumentAll(toHTMLElement(candidate))))
+                    candidate = 0;
+            }
+        } else
+            return 0;
+
+        if (candidate
+            && isMatchingElement(this, candidate)
+            && (shouldOnlyIncludeDirectChildren() ? candidate->parentNode() == root : candidate->isDescendantOf(root)))
+            return candidate;
     }
 
-    i = 0;
-    for (Element* element = traverseFirstElement(arrayOffset, root); element; element = traverseNextElement(arrayOffset, element, root)) {
-        if (checkForNameMatch(element, /* checkName */ true, name)) {
-            setItemCache(element, i, arrayOffset);
-            return element;
-        }
-        i++;
+    // The pathological case. We need to walk the entire subtree.
+    updateNameCache();
+
+    if (Vector<Element*>* idResults = idCache(name)) {
+        if (idResults->size())
+            return idResults->at(0);
+    }
+
+    if (Vector<Element*>* nameResults = nameCache(name)) {
+        if (nameResults->size())
+            return nameResults->at(0);
     }
 
     return 0;
@@ -676,22 +679,8 @@ void HTMLCollection::updateNameCache() const
 
 bool HTMLCollection::hasNamedItem(const AtomicString& name) const
 {
-    if (name.isEmpty())
-        return false;
-
-    updateNameCache();
-
-    if (Vector<Element*>* cache = idCache(name)) {
-        if (!cache->isEmpty())
-            return true;
-    }
-
-    if (Vector<Element*>* cache = nameCache(name)) {
-        if (!cache->isEmpty())
-            return true;
-    }
-
-    return false;
+    // FIXME: We can do better when there are multiple elements of the same name.
+    return namedItem(name);
 }
 
 void HTMLCollection::namedItems(const AtomicString& name, Vector<RefPtr<Node> >& result) const
index a321179b1ba1e44601800916890e7e4d979f10d4..6ae1ee89959e33376d00668cb33cb55e8050eec5 100644 (file)
@@ -79,7 +79,6 @@ protected:
     void appendNameCache(const AtomicString& name, Element* element) const { append(m_nameCache, name, element); }
 
 private:
-    bool checkForNameMatch(Element*, bool checkName, const AtomicString& name) const;
     Element* traverseNextElement(unsigned& offsetInArray, Element* previous, ContainerNode* root) const;
 
     virtual bool isLiveNodeList() const OVERRIDE { ASSERT_NOT_REACHED(); return true; }
index 1c1bf2a4f6c56a3f61d939cfacd8c449e8619494..c2190d54173e3d105ca1420f7fa5b9d3f99ffc24 100644 (file)
@@ -295,44 +295,6 @@ PassRefPtr<Element> HTMLDocument::createElement(const AtomicString& name, Except
     return HTMLElementFactory::createHTMLElement(QualifiedName(nullAtom, name.lower(), xhtmlNamespaceURI), this, 0, false);
 }
 
-void HTMLDocument::addItemToMap(HashCountedSet<AtomicStringImpl*>& map, const AtomicString& name)
-{
-    if (name.isEmpty())
-        return;
-    map.add(name.impl());
-    if (Frame* f = frame())
-        f->script()->namedItemAdded(this, name);
-}
-
-void HTMLDocument::removeItemFromMap(HashCountedSet<AtomicStringImpl*>& map, const AtomicString& name)
-{
-    if (name.isEmpty())
-        return;
-    map.remove(name.impl());
-    if (Frame* f = frame())
-        f->script()->namedItemRemoved(this, name);
-}
-
-void HTMLDocument::addNamedItem(const AtomicString& name)
-{
-    addItemToMap(m_namedItemCounts, name);
-}
-
-void HTMLDocument::removeNamedItem(const AtomicString& name)
-{ 
-    removeItemFromMap(m_namedItemCounts, name);
-}
-
-void HTMLDocument::addExtraNamedItem(const AtomicString& name)
-{
-    addItemToMap(m_extraNamedItemCounts, name);
-}
-
-void HTMLDocument::removeExtraNamedItem(const AtomicString& name)
-{ 
-    removeItemFromMap(m_extraNamedItemCounts, name);
-}
-
 static void addLocalNameToSet(HashSet<AtomicStringImpl*>* set, const QualifiedName& qName)
 {
     set->add(qName.localName().impl());
index 514207258f62e6b5e81c36ebe2fe3f01dd179382..00627310938570476fd78c7cb78660a77378e03e 100644 (file)
@@ -69,13 +69,8 @@ public:
     void captureEvents();
     void releaseEvents();
 
-    void addNamedItem(const AtomicString& name);
-    void removeNamedItem(const AtomicString& name);
-    bool hasNamedItem(AtomicStringImpl* name);
-
-    void addExtraNamedItem(const AtomicString& name);
-    void removeExtraNamedItem(const AtomicString& name);
-    bool hasExtraNamedItem(AtomicStringImpl* name);
+    DocumentOrderedMap& documentNamedItemMap() { return m_documentNamedItem; }
+    DocumentOrderedMap& windowNamedItemMap() { return m_windowNamedItem; }
 
     static bool isCaseSensitiveAttribute(const QualifiedName&);
 
@@ -88,25 +83,10 @@ private:
     virtual bool isFrameSet() const;
     virtual PassRefPtr<DocumentParser> createParser();
 
-    void addItemToMap(HashCountedSet<AtomicStringImpl*>&, const AtomicString&);
-    void removeItemFromMap(HashCountedSet<AtomicStringImpl*>&, const AtomicString&);
-
-    HashCountedSet<AtomicStringImpl*> m_namedItemCounts;
-    HashCountedSet<AtomicStringImpl*> m_extraNamedItemCounts;
+    DocumentOrderedMap m_documentNamedItem;
+    DocumentOrderedMap m_windowNamedItem;
 };
 
-inline bool HTMLDocument::hasNamedItem(AtomicStringImpl* name)
-{
-    ASSERT(name);
-    return m_namedItemCounts.contains(name);
-}
-
-inline bool HTMLDocument::hasExtraNamedItem(AtomicStringImpl* name)
-{
-    ASSERT(name);
-    return m_extraNamedItemCounts.contains(name);
-}
-
 inline HTMLDocument* toHTMLDocument(Document* document)
 {
     ASSERT_WITH_SECURITY_IMPLICATION(!document || document->isHTMLDocument());
index 442dcb9ab110be94e0e8e14a062b831779d4e0d3..bb6eba1e4a8771516896a3315ae24c1991ca35bc 100644 (file)
@@ -55,8 +55,6 @@ private:
     virtual String itemValueText() const OVERRIDE;
     virtual void setItemValueText(const String&, ExceptionCode&) OVERRIDE;
 #endif
-
-    virtual bool shouldRegisterAsNamedItem() const OVERRIDE { return true; }
 };
 
 }
index bd9a252906d1d89119eff872ab42187ab3dd9259..ba9e2f2c712da075a052308d8c99d13e67b122ff 100644 (file)
@@ -125,8 +125,6 @@ private:
 
     virtual void didMoveToNewDocument(Document* oldDocument) OVERRIDE;
 
-    virtual bool shouldRegisterAsNamedItem() const OVERRIDE { return true; }
-
     virtual void copyNonAttributePropertiesFromElement(const Element&) OVERRIDE;
 
     void submit(Event*, bool activateSubmitButton, bool processingUserGesture, FormSubmissionTrigger);
index 8b017e6a860488fae920695e99b1753835287d90..222baeaa24cd161e7d4e199e79f99a8ffeed3916 100644 (file)
@@ -79,14 +79,7 @@ void HTMLIFrameElement::collectStyleForPresentationAttribute(const QualifiedName
 
 void HTMLIFrameElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
 {
-    if (name == nameAttr) {
-        if (inDocument() && document()->isHTMLDocument() && !isInShadowTree()) {
-            HTMLDocument* document = toHTMLDocument(this->document());
-            document->removeExtraNamedItem(m_name);
-            document->addExtraNamedItem(value);
-        }
-        m_name = value;
-    } else if (name == sandboxAttr) {
+    if (name == sandboxAttr) {
         String invalidTokens;
         setSandboxFlags(value.isNull() ? SandboxNone : SecurityContext::parseSandboxPolicy(value, invalidTokens));
         if (!invalidTokens.isNull())
@@ -109,21 +102,6 @@ RenderObject* HTMLIFrameElement::createRenderer(RenderArena* arena, RenderStyle*
     return new (arena) RenderIFrame(this);
 }
 
-Node::InsertionNotificationRequest HTMLIFrameElement::insertedInto(ContainerNode* insertionPoint)
-{
-    InsertionNotificationRequest result = HTMLFrameElementBase::insertedInto(insertionPoint);
-    if (insertionPoint->inDocument() && document()->isHTMLDocument() && !insertionPoint->isInShadowTree())
-        toHTMLDocument(document())->addExtraNamedItem(m_name);
-    return result;
-}
-
-void HTMLIFrameElement::removedFrom(ContainerNode* insertionPoint)
-{
-    HTMLFrameElementBase::removedFrom(insertionPoint);
-    if (insertionPoint->inDocument() && document()->isHTMLDocument() && !insertionPoint->isInShadowTree())
-        toHTMLDocument(document())->removeExtraNamedItem(m_name);
-}
-
 bool HTMLIFrameElement::shouldDisplaySeamlessly() const
 {
     return contentDocument() && contentDocument()->shouldDisplaySeamlesslyWithParent();
index 0cf5e173eaa8c39ac02f28d27a4dfa6c2dbbebf4..e8e090c5dbdc49d99c1ee940ed0624a1e9785a61 100644 (file)
@@ -41,9 +41,6 @@ private:
     virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
     virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
 
-    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
-    virtual void removedFrom(ContainerNode*) OVERRIDE;
-
     virtual bool rendererIsNeeded(const NodeRenderingContext&);
     virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
 
@@ -53,8 +50,6 @@ private:
     virtual String itemValueText() const OVERRIDE;
     virtual void setItemValueText(const String&, ExceptionCode&) OVERRIDE;
 #endif
-
-    AtomicString m_name;
 };
 
 } // namespace WebCore
index a1960224180ead9035e2ae45a329e56f4214d3a6..69dd80ac993923940030c73772016b57c2a01911 100644 (file)
@@ -124,8 +124,22 @@ void HTMLImageElement::parseAttribute(const QualifiedName& name, const AtomicStr
         BlendMode blendOp = BlendModeNormal;
         if (!parseCompositeAndBlendOperator(value, m_compositeOperator, blendOp))
             m_compositeOperator = CompositeSourceOver;
-    } else
+    } else {
+        if (name == nameAttr) {
+            bool willHaveName = !value.isNull();
+            if (hasName() != willHaveName && inDocument() && document()->isHTMLDocument()) {
+                HTMLDocument* document = toHTMLDocument(this->document());
+                const AtomicString& id = getIdAttribute();
+                if (!id.isEmpty()) {
+                    if (willHaveName)
+                        document->documentNamedItemMap().add(id.impl(), this);
+                    else
+                        document->documentNamedItemMap().remove(id.impl(), this);
+                }
+            }
+        }
         HTMLElement::parseAttribute(name, value);
+    }
 }
 
 String HTMLImageElement::altText() const
index 27fe2f7c1f329480dcf977cf2acdf3740b1e6a57..22bfe2f44f644d69510eef1c326ef0fa480dc5cc 100644 (file)
@@ -101,8 +101,6 @@ private:
 
     virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
     virtual void removedFrom(ContainerNode*) OVERRIDE;
-    virtual bool shouldRegisterAsNamedItem() const OVERRIDE { return true; }
-    virtual bool shouldRegisterAsExtraNamedItem() const OVERRIDE { return true; }
 
 #if ENABLE(MICRODATA)
     virtual String itemValueText() const OVERRIDE;
index 8ec32f4b3bcd71c1eeddc35cb7ec1887feb2e216..22088349588e6f283b0dfa76571a32d831f38397 100644 (file)
@@ -35,7 +35,7 @@ namespace WebCore {
 using namespace HTMLNames;
 
 HTMLNameCollection::HTMLNameCollection(Node* document, CollectionType type, const AtomicString& name)
-    : HTMLCollection(document, type, OverridesItemAfter)
+    : HTMLCollection(document, type, DoesNotOverrideItemAfter)
     , m_name(name)
 {
 }
@@ -49,58 +49,47 @@ HTMLNameCollection::~HTMLNameCollection()
     ownerNode()->nodeLists()->removeCacheWithAtomicName(this, type(), m_name);
 }
 
-Element* HTMLNameCollection::virtualItemAfter(unsigned& offsetInArray, Element* previous) const
+bool WindowNameCollection::nodeMatchesIfNameAttributeMatch(Element* element)
 {
-    ASSERT_UNUSED(offsetInArray, !offsetInArray);
-    ASSERT(previous != ownerNode());
+    return element->hasTagName(imgTag) || element->hasTagName(formTag) || element->hasTagName(appletTag)
+        || element->hasTagName(embedTag) || element->hasTagName(objectTag);
+}
 
-    Element* current;
-    if (!previous)
-        current = ElementTraversal::firstWithin(ownerNode());
-    else
-        current = ElementTraversal::next(previous, ownerNode());
+bool WindowNameCollection::nodeMatches(Element* element, const AtomicString& name)
+{
+    // Find only images, forms, applets, embeds and objects by name, but anything by id
+    if (nodeMatchesIfNameAttributeMatch(element) && element->getNameAttribute() == name)
+        return true;
+    return element->getIdAttribute() == name;
+}
 
-    for (; current; current = ElementTraversal::next(current, ownerNode())) {
-        switch (type()) {
-        case WindowNamedItems:
-            // find only images, forms, applets, embeds and objects by name, 
-            // but anything by id
-            if (current->hasTagName(imgTag)
-                || current->hasTagName(formTag)
-                || current->hasTagName(appletTag)
-                || current->hasTagName(embedTag)
-                || current->hasTagName(objectTag)) {
-                if (current->getNameAttribute() == m_name)
-                    return current;
-            }
-            if (current->getIdAttribute() == m_name)
-                return current;
-            break;
-        case DocumentNamedItems:
-            // find images, forms, applets, embeds, objects and iframes by name, 
-            // applets and object by id, and images by id but only if they have
-            // a name attribute (this very strange rule matches IE)
-            if (current->hasTagName(formTag) || current->hasTagName(embedTag) || current->hasTagName(iframeTag)) {
-                if (current->getNameAttribute() == m_name)
-                    return current;
-            } else if (current->hasTagName(appletTag)) {
-                if (current->getNameAttribute() == m_name || current->getIdAttribute() == m_name)
-                    return current;
-            } else if (current->hasTagName(objectTag)) {
-                if ((current->getNameAttribute() == m_name || current->getIdAttribute() == m_name)
-                    && static_cast<HTMLObjectElement*>(current)->isDocNamedItem())
-                    return current;
-            } else if (current->hasTagName(imgTag)) {
-                if (current->getNameAttribute() == m_name || (current->getIdAttribute() == m_name && current->hasName()))
-                    return current;
-            }
-            break;
-        default:
-            ASSERT_NOT_REACHED();
-        }
-    }
+bool DocumentNameCollection::nodeMatchesIfIdAttributeMatch(Element* element)
+{
+    // FIXME: we need to fix HTMLImageElement to update the hash map for us when name attribute has been removed.
+    return element->hasTagName(appletTag) || (element->hasTagName(objectTag) && toHTMLObjectElement(element)->isDocNamedItem())
+        || (element->hasTagName(imgTag) && element->hasName());
+}
 
-    return 0;
+bool DocumentNameCollection::nodeMatchesIfNameAttributeMatch(Element* element)
+{
+    return element->hasTagName(formTag) || element->hasTagName(embedTag) || element->hasTagName(iframeTag)
+        || element->hasTagName(appletTag) || (element->hasTagName(objectTag) && toHTMLObjectElement(element)->isDocNamedItem())
+        || element->hasTagName(imgTag);
+}
+
+bool DocumentNameCollection::nodeMatches(Element* element, const AtomicString& name)
+{
+    // Find images, forms, applets, embeds, objects and iframes by name, applets and object by id, and images by id
+    // but only if they have a name attribute (this very strange rule matches IE)
+    if (element->hasTagName(formTag) || element->hasTagName(embedTag) || element->hasTagName(iframeTag))
+        return element->getNameAttribute() == name;
+    if (element->hasTagName(appletTag))
+        return element->getNameAttribute() == name || element->getIdAttribute() == name;
+    if (element->hasTagName(objectTag))
+        return (element->getNameAttribute() == name || element->getIdAttribute() == name) && toHTMLObjectElement(element)->isDocNamedItem();
+    if (element->hasTagName(imgTag))
+        return element->getNameAttribute() == name || (element->getIdAttribute() == name && element->hasName());
+    return false;
 }
 
 }
index 1fb85b994055a1ace81898ab78a9a52975bdb61c..0be3e1003f7672f9da978ef73a576d35b5859e2a 100644 (file)
@@ -33,19 +33,54 @@ class Document;
 
 class HTMLNameCollection : public HTMLCollection {
 public:
-    static PassRefPtr<HTMLNameCollection> create(Node* document, CollectionType type, const AtomicString& name)
+    ~HTMLNameCollection();
+
+protected:
+    HTMLNameCollection(Node*, CollectionType, const AtomicString& name);
+
+    AtomicString m_name;
+};
+
+class WindowNameCollection : public HTMLNameCollection {
+public:
+    static PassRefPtr<WindowNameCollection> create(Node* document, CollectionType type, const AtomicString& name)
     {
-        return adoptRef(new HTMLNameCollection(document, type, name));
+        return adoptRef(new WindowNameCollection(document, type, name));
     }
 
-    ~HTMLNameCollection();
+    bool nodeMatches(Element* element) const { return nodeMatches(element, m_name); }
+
+    static bool nodeMatchesIfIdAttributeMatch(Element*) { return true; }
+    static bool nodeMatchesIfNameAttributeMatch(Element*);
+    static bool nodeMatches(Element*, const AtomicString&);
 
 private:
-    HTMLNameCollection(Node*, CollectionType, const AtomicString& name);
+    WindowNameCollection(Node* document, CollectionType type, const AtomicString& name)
+        : HTMLNameCollection(document, type, name)
+    {
+        ASSERT(type == WindowNamedItems);
+    }
+};
 
-    virtual Element* virtualItemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;
+class DocumentNameCollection : public HTMLNameCollection {
+public:
+    static PassRefPtr<DocumentNameCollection> create(Node* document, CollectionType type, const AtomicString& name)
+    {
+        return adoptRef(new DocumentNameCollection(document, type, name));
+    }
 
-    AtomicString m_name;
+    static bool nodeMatchesIfIdAttributeMatch(Element*);
+    static bool nodeMatchesIfNameAttributeMatch(Element*);
+    bool nodeMatches(Element* element) const { return nodeMatches(element, m_name); }
+
+    static bool nodeMatches(Element*, const AtomicString&);
+
+private:
+    DocumentNameCollection(Node* document, CollectionType type, const AtomicString& name)
+        : HTMLNameCollection(document, type, name)
+    {
+        ASSERT(type == DocumentNamedItems);
+    }
 };
 
 }
index f138a406517742ee7c1f79e8447d01d03616f113..3a205131f0221b05e16c4d58aa6ec1fda5861076 100644 (file)
@@ -439,14 +439,23 @@ void HTMLObjectElement::updateDocNamedItem()
             isNamedItem = false;
         child = child->nextSibling();
     }
-    if (isNamedItem != wasNamedItem && document()->isHTMLDocument()) {
+    if (isNamedItem != wasNamedItem && inDocument() && document()->isHTMLDocument()) {
         HTMLDocument* document = toHTMLDocument(this->document());
-        if (isNamedItem) {
-            document->addNamedItem(getNameAttribute());
-            document->addExtraNamedItem(getIdAttribute());
-        } else {
-            document->removeNamedItem(getNameAttribute());
-            document->removeExtraNamedItem(getIdAttribute());
+
+        const AtomicString& id = getIdAttribute();
+        if (!id.isEmpty()) {
+            if (isNamedItem)
+                document->documentNamedItemMap().add(id.impl(), this);
+            else
+                document->documentNamedItemMap().remove(id.impl(), this);
+        }
+
+        const AtomicString& name = getNameAttribute();
+        if (!name.isEmpty()) {
+            if (isNamedItem)
+                document->documentNamedItemMap().add(name.impl(), this);
+            else
+                document->documentNamedItemMap().remove(name.impl(), this);
         }
     }
     m_docNamedItem = isNamedItem;
index bf717da5551a35c7bf1877d833276ca77a9e6160..1b7ad91bfaf98fd566ff3ebe179a7afe102c2206 100644 (file)
@@ -106,14 +106,17 @@ private:
     virtual void setItemValueText(const String&, ExceptionCode&) OVERRIDE;
 #endif
 
-    virtual bool shouldRegisterAsNamedItem() const OVERRIDE { return isDocNamedItem(); }
-    virtual bool shouldRegisterAsExtraNamedItem() const OVERRIDE { return isDocNamedItem(); }
-
     String m_classId;
     bool m_docNamedItem : 1;
     bool m_useFallbackContent : 1;
 };
 
+inline HTMLObjectElement* toHTMLObjectElement(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->hasTagName(HTMLNames::objectTag));
+    return static_cast<HTMLObjectElement*>(node);
+}
+
 }
 
 #endif