Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / html / HTMLCollection.h
index 26f388f..b7f4f78 100644 (file)
 #define HTMLCollection_h
 
 #include "CollectionIndexCache.h"
-#include "CollectionType.h"
-#include "ContainerNode.h"
-#include "Document.h"
 #include "HTMLNames.h"
 #include "LiveNodeList.h"
 #include "ScriptWrappable.h"
-#include <wtf/Forward.h>
 #include <wtf/HashMap.h>
-#include <wtf/Vector.h>
 
 namespace WebCore {
 
@@ -40,136 +35,200 @@ class Element;
 
 class CollectionNamedElementCache {
 public:
-#ifndef ASSERT_DISABLED
-    CollectionNamedElementCache : m_didPopulateCalled(false) { }
-#endif
-
-    const Vector<Element*>* findElementsWithId(const AtomicString& id) const { return find(m_idToElementsMap, id); }
-    const Vector<Element*>* findElementsWithName(const AtomicString& name) const { return find(m_nameToElementsMap, name); }
+    const Vector<Element*>* findElementsWithId(const AtomicString& id) const;
+    const Vector<Element*>* findElementsWithName(const AtomicString& name) const;
+    const Vector<AtomicString>& propertyNames() const { return m_propertyNames; }
 
-    void appendIdCache(const AtomicString& id, Element* element) { return append(m_idToElementsMap, id, element); }
-    void appendNameCache(const AtomicString& name, Element* element)  { return append(m_nameToElementsMap, name, element); }
+    void appendToIdCache(const AtomicString& id, Element&);
+    void appendToNameCache(const AtomicString& name, Element&);
+    void didPopulate();
 
-    void didPopulate()
-    {
-#ifndef ASSERT_DISABLED
-        m_didPopulateCalled = true;
-#endif
-        if (size_t cost = memoryCost())
-            reportExtraMemoryCostForCollectionIndexCache(cost);
-    }
-    size_t memoryCost() const { return (m_idToElementsMap.size() + m_nameToElementsMap.size()) * sizeof(Element*); }
+    size_t memoryCost() const;
 
 private:
     typedef HashMap<AtomicStringImpl*, Vector<Element*>> StringToElementsMap;
 
-    const Vector<Element*>* find(const StringToElementsMap& map, const AtomicString& key) const
-    {
-#ifndef ASSERT_DISABLED
-        ASSERT(m_didPopulateCalled);
-#endif
-        auto it = map.find(key.impl());
-        return it != map.end() ? &it->value : nullptr;
-    }
-
-    static void append(StringToElementsMap& map, const AtomicString& key, Element* element)
-    {
-        map.add(key.impl(), Vector<Element*>()).iterator->value.append(element);
-    }
-
-    StringToElementsMap m_idToElementsMap;
-    StringToElementsMap m_nameToElementsMap;
-#ifndef ASSERT_DISABLED
-    bool m_didPopulateCalled;
+    const Vector<Element*>* find(const StringToElementsMap&, const AtomicString& key) const;
+    void append(StringToElementsMap&, const AtomicString& key, Element&);
+
+    StringToElementsMap m_idMap;
+    StringToElementsMap m_nameMap;
+    Vector<AtomicString> m_propertyNames;
+
+#if !ASSERT_DISABLED
+    bool m_didPopulate { false };
 #endif
 };
 
-class HTMLCollection : public ScriptWrappable, public RefCounted<HTMLCollection> {
+// HTMLCollection subclasses NodeList to maintain legacy ObjC API compatibility.
+class HTMLCollection : public NodeList {
 public:
-    static PassRefPtr<HTMLCollection> create(ContainerNode& base, CollectionType);
     virtual ~HTMLCollection();
 
     // DOM API
-    unsigned length() const;
-    Node* item(unsigned offset) const;
-    virtual Node* namedItem(const AtomicString& name) const;
-    PassRefPtr<NodeList> tags(const String&);
+    virtual Element* item(unsigned index) const override = 0; // Tighten return type from NodeList::item().
+    virtual Element* namedItem(const AtomicString& name) const = 0;
+    const Vector<AtomicString>& supportedPropertyNames();
+    RefPtr<NodeList> tags(const String&);
 
     // Non-DOM API
-    bool hasNamedItem(const AtomicString& name) const;
-    void namedItems(const AtomicString& name, Vector<Ref<Element>>&) const;
-    size_t memoryCost() const { return m_indexCache.memoryCost() + (m_namedElementCache ? m_namedElementCache->memoryCost() : 0); }
-
-    bool isRootedAtDocument() const { return m_rootType == NodeListIsRootedAtDocument; }
-    NodeListInvalidationType invalidationType() const { return static_cast<NodeListInvalidationType>(m_invalidationType); }
-    CollectionType type() const { return static_cast<CollectionType>(m_collectionType); }
-    ContainerNode& ownerNode() const { return const_cast<ContainerNode&>(m_ownerNode.get()); }
-    void invalidateCache(const QualifiedName* attrName) const
-    {
-        if (!attrName || shouldInvalidateTypeOnAttributeChange(invalidationType(), *attrName))
-            invalidateCache(document());
-        else if (hasNamedElementCache() && (*attrName == HTMLNames::idAttr || *attrName == HTMLNames::nameAttr))
-            invalidateNamedElementCache(document());
-    }
-    virtual void invalidateCache(Document&) const;
-
-    // For CollectionIndexCache
-    Element* collectionFirst() const;
-    Element* collectionLast() const;
-    Element* collectionTraverseForward(Element&, unsigned count, unsigned& traversedCount) const;
-    Element* collectionTraverseBackward(Element&, unsigned count) const;
-    bool collectionCanTraverseBackward() const { return !m_usesCustomForwardOnlyTraversal; }
-    void willValidateIndexCache() const { document().registerCollection(const_cast<HTMLCollection&>(*this)); }
-
-    bool hasNamedElementCache() const { return !!m_namedElementCache; }
-
-protected:
-    enum ElementTraversalType { NormalTraversal, CustomForwardOnlyTraversal };
-    HTMLCollection(ContainerNode& base, CollectionType, ElementTraversalType = NormalTraversal);
+    Vector<Ref<Element>> namedItems(const AtomicString& name) const;
+    virtual size_t memoryCost() const override;
 
-    virtual void updateNamedElementCache() const;
-
-    Document& document() const { return m_ownerNode->document(); }
+    bool isRootedAtDocument() const;
+    NodeListInvalidationType invalidationType() const;
+    CollectionType type() const;
+    ContainerNode& ownerNode() const;
     ContainerNode& rootNode() const;
-    bool usesCustomForwardOnlyTraversal() const { return m_usesCustomForwardOnlyTraversal; }
+    void invalidateCacheForAttribute(const QualifiedName* attributeName);
+    virtual void invalidateCache(Document&);
 
-    NodeListRootType rootType() const { return static_cast<NodeListRootType>(m_rootType); }
+    bool hasNamedElementCache() const;
+
+protected:
+    HTMLCollection(ContainerNode& base, CollectionType);
 
-    CollectionNamedElementCache& createNameItemCache() const
-    {
-        ASSERT(!m_namedElementCache);
-        m_namedElementCache = std::make_unique<CollectionNamedElementCache>();
-        document().collectionCachedIdNameMap(*this);
-        return *m_namedElementCache;
-    }
+    virtual void updateNamedElementCache() const;
+    Element* namedItemSlow(const AtomicString& name) const;
 
-    const CollectionNamedElementCache& namedItemCaches() const
-    {
-        ASSERT(!!m_namedElementCache);
-        return *m_namedElementCache;
-    }
+    void setNamedItemCache(std::unique_ptr<CollectionNamedElementCache>) const;
+    const CollectionNamedElementCache& namedItemCaches() const;
 
-private:
-    Element* iterateForPreviousElement(Element* current) const;
-    Element* firstElement(ContainerNode& root) const;
-    Element* traverseForward(Element& current, unsigned count, unsigned& traversedCount, ContainerNode& root) const;
+    Document& document() const;
 
-    virtual Element* customElementAfter(Element*) const { ASSERT_NOT_REACHED(); return nullptr; }
-    
     void invalidateNamedElementCache(Document&) const;
 
+    enum RootType { IsRootedAtNode, IsRootedAtDocument };
+    static RootType rootTypeFromCollectionType(CollectionType);
+
     Ref<ContainerNode> m_ownerNode;
 
-    mutable CollectionIndexCache<HTMLCollection, Element> m_indexCache;
     mutable std::unique_ptr<CollectionNamedElementCache> m_namedElementCache;
 
     const unsigned m_collectionType : 5;
     const unsigned m_invalidationType : 4;
     const unsigned m_rootType : 1;
-    const unsigned m_shouldOnlyIncludeDirectChildren : 1;
-    const unsigned m_usesCustomForwardOnlyTraversal : 1;
 };
 
-} // namespace
-
+inline ContainerNode& HTMLCollection::rootNode() const
+{
+    if (isRootedAtDocument() && ownerNode().inDocument())
+        return ownerNode().document();
+
+    return ownerNode();
+}
+
+inline const Vector<Element*>* CollectionNamedElementCache::findElementsWithId(const AtomicString& id) const
+{
+    return find(m_idMap, id);
+}
+
+inline const Vector<Element*>* CollectionNamedElementCache::findElementsWithName(const AtomicString& name) const
+{
+    return find(m_nameMap, name);
+}
+
+inline void CollectionNamedElementCache::appendToIdCache(const AtomicString& id, Element& element)
+{
+    append(m_idMap, id, element);
+}
+
+inline void CollectionNamedElementCache::appendToNameCache(const AtomicString& name, Element& element)
+{
+    append(m_nameMap, name, element);
+}
+
+inline size_t CollectionNamedElementCache::memoryCost() const
+{
+    return (m_idMap.size() + m_nameMap.size()) * sizeof(Element*) + m_propertyNames.size() * sizeof(AtomicString);
+}
+
+inline void CollectionNamedElementCache::didPopulate()
+{
+#if !ASSERT_DISABLED
+    m_didPopulate = true;
 #endif
+    if (size_t cost = memoryCost())
+        reportExtraMemoryAllocatedForCollectionIndexCache(cost);
+}
+
+inline const Vector<Element*>* CollectionNamedElementCache::find(const StringToElementsMap& map, const AtomicString& key) const
+{
+    ASSERT(m_didPopulate);
+    auto it = map.find(key.impl());
+    return it != map.end() ? &it->value : nullptr;
+}
+
+inline void CollectionNamedElementCache::append(StringToElementsMap& map, const AtomicString& key, Element& element)
+{
+    if (!m_idMap.contains(key.impl()) && !m_nameMap.contains(key.impl()))
+        m_propertyNames.append(key);
+    map.add(key.impl(), Vector<Element*>()).iterator->value.append(&element);
+}
+
+inline size_t HTMLCollection::memoryCost() const
+{
+    return m_namedElementCache ? m_namedElementCache->memoryCost() : 0;
+}
+
+inline bool HTMLCollection::isRootedAtDocument() const
+{
+    return m_rootType == IsRootedAtDocument;
+}
+
+inline NodeListInvalidationType HTMLCollection::invalidationType() const
+{
+    return static_cast<NodeListInvalidationType>(m_invalidationType);
+}
+
+inline CollectionType HTMLCollection::type() const
+{
+    return static_cast<CollectionType>(m_collectionType);
+}
+
+inline ContainerNode& HTMLCollection::ownerNode() const
+{
+    return const_cast<ContainerNode&>(m_ownerNode.get());
+}
+
+inline Document& HTMLCollection::document() const
+{
+    return m_ownerNode->document();
+}
+
+inline void HTMLCollection::invalidateCacheForAttribute(const QualifiedName* attributeName)
+{
+    if (!attributeName || shouldInvalidateTypeOnAttributeChange(invalidationType(), *attributeName))
+        invalidateCache(document());
+    else if (hasNamedElementCache() && (*attributeName == HTMLNames::idAttr || *attributeName == HTMLNames::nameAttr))
+        invalidateNamedElementCache(document());
+}
+
+inline bool HTMLCollection::hasNamedElementCache() const
+{
+    return !!m_namedElementCache;
+}
+
+inline void HTMLCollection::setNamedItemCache(std::unique_ptr<CollectionNamedElementCache> cache) const
+{
+    ASSERT(cache);
+    ASSERT(!m_namedElementCache);
+    cache->didPopulate();
+    m_namedElementCache = WTFMove(cache);
+    document().collectionCachedIdNameMap(*this);
+}
+
+inline const CollectionNamedElementCache& HTMLCollection::namedItemCaches() const
+{
+    ASSERT(!!m_namedElementCache);
+    return *m_namedElementCache;
+}
+
+} // namespace WebCore
+
+#define SPECIALIZE_TYPE_TRAITS_HTMLCOLLECTION(ClassName, Type) \
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ClassName) \
+    static bool isType(const WebCore::HTMLCollection& collection) { return collection.type() == WebCore::Type; } \
+SPECIALIZE_TYPE_TRAITS_END()
+
+#endif // HTMLCollection_h