Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / html / HTMLCollection.h
index d6a0535..b7f4f78 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 #ifndef HTMLCollection_h
 #define HTMLCollection_h
 
-#include "Node.h"
-#include "CollectionType.h"
-#include <wtf/Forward.h>
+#include "CollectionIndexCache.h"
+#include "HTMLNames.h"
+#include "LiveNodeList.h"
+#include "ScriptWrappable.h"
 #include <wtf/HashMap.h>
-#include <wtf/PassOwnPtr.h>
-#include <wtf/Vector.h>
 
 namespace WebCore {
 
-class Document;
 class Element;
-class NodeList;
 
-class HTMLCollection {
+class CollectionNamedElementCache {
 public:
-    static PassOwnPtr<HTMLCollection> create(Node* base, CollectionType);
-    virtual ~HTMLCollection();
+    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 appendToIdCache(const AtomicString& id, Element&);
+    void appendToNameCache(const AtomicString& name, Element&);
+    void didPopulate();
+
+    size_t memoryCost() const;
+
+private:
+    typedef HashMap<AtomicStringImpl*, Vector<Element*>> StringToElementsMap;
+
+    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
+};
 
-    void ref() { m_base->ref(); }
-    void deref() { m_base->deref(); }
+// HTMLCollection subclasses NodeList to maintain legacy ObjC API compatibility.
+class HTMLCollection : public NodeList {
+public:
+    virtual ~HTMLCollection();
 
     // DOM API
-    unsigned length() const;
-    virtual Node* item(unsigned index) 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<RefPtr<Node> >&) const;
-    bool hasAnyItem() const
-    {
-        invalidateCacheIfNeeded();
-        return (m_cache.hasLength && m_cache.length) || m_cache.current || item(0);
-    }
-    bool hasExactlyOneItem() const
-    {
-        invalidateCacheIfNeeded();
-        return (m_cache.hasLength && m_cache.length == 1) || (m_cache.current && !itemAfter(m_cache.current)) || (item(0) && !item(1));
-    }
-
-    Node* base() const { return m_base; }
-    CollectionType type() const { return static_cast<CollectionType>(m_type); }
-
-    void clearCache();
-    void invalidateCacheIfNeeded() const;
+    Vector<Ref<Element>> namedItems(const AtomicString& name) const;
+    virtual size_t memoryCost() const override;
+
+    bool isRootedAtDocument() const;
+    NodeListInvalidationType invalidationType() const;
+    CollectionType type() const;
+    ContainerNode& ownerNode() const;
+    ContainerNode& rootNode() const;
+    void invalidateCacheForAttribute(const QualifiedName* attributeName);
+    virtual void invalidateCache(Document&);
+
+    bool hasNamedElementCache() const;
+
 protected:
-    HTMLCollection(Node* base, CollectionType);
-
-    virtual void updateNameCache() const;
-    virtual Element* itemAfter(Element*) const;
-
-    typedef HashMap<AtomicStringImpl*, OwnPtr<Vector<Element*> > > NodeCacheMap;
-    static void append(NodeCacheMap&, const AtomicString&, Element*);
-
-    mutable struct {
-        NodeCacheMap idCache;
-        NodeCacheMap nameCache;
-        uint64_t version;
-        Element* current;
-        unsigned position;
-        unsigned length;
-        int elementsArrayPosition;
-        bool hasLength;
-        bool hasNameCache;
-
-        void clear()
-        {
-            idCache.clear();
-            nameCache.clear();
-            version = 0;
-            current = 0;
-            position = 0;
-            length = 0;
-            elementsArrayPosition = 0;
-            hasLength = false;
-            hasNameCache = false;
-        }
-    } m_cache;
+    HTMLCollection(ContainerNode& base, CollectionType);
 
-private:
-    bool checkForNameMatch(Element*, bool checkName, const AtomicString& name) const;
+    virtual void updateNamedElementCache() const;
+    Element* namedItemSlow(const AtomicString& name) const;
 
-    virtual unsigned calcLength() const;
+    void setNamedItemCache(std::unique_ptr<CollectionNamedElementCache>) const;
+    const CollectionNamedElementCache& namedItemCaches() const;
 
-    bool isAcceptableElement(Element*) const;
+    Document& document() const;
 
-    bool m_includeChildren : 1;
-    unsigned m_type : 5; // CollectionType
+    void invalidateNamedElementCache(Document&) const;
 
-    Node* m_base;
-};
+    enum RootType { IsRootedAtNode, IsRootedAtDocument };
+    static RootType rootTypeFromCollectionType(CollectionType);
+
+    Ref<ContainerNode> m_ownerNode;
 
-} // namespace
+    mutable std::unique_ptr<CollectionNamedElementCache> m_namedElementCache;
+
+    const unsigned m_collectionType : 5;
+    const unsigned m_invalidationType : 4;
+    const unsigned m_rootType : 1;
+};
 
+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