summaryrefslogtreecommitdiff
path: root/Source/WebCore/html/HTMLCollection.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/html/HTMLCollection.h')
-rw-r--r--Source/WebCore/html/HTMLCollection.h252
1 files changed, 177 insertions, 75 deletions
diff --git a/Source/WebCore/html/HTMLCollection.h b/Source/WebCore/html/HTMLCollection.h
index 17c81c7e1..643a2e702 100644
--- a/Source/WebCore/html/HTMLCollection.h
+++ b/Source/WebCore/html/HTMLCollection.h
@@ -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
@@ -20,110 +20,212 @@
*
*/
-#ifndef HTMLCollection_h
-#define HTMLCollection_h
+#pragma once
#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 {
class Element;
-class HTMLCollection : public ScriptWrappable, public RefCounted<HTMLCollection> {
+class CollectionNamedElementCache {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- static PassRefPtr<HTMLCollection> create(ContainerNode& 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; }
- // DOM API
- unsigned length() const;
- Node* item(unsigned offset) const;
- virtual Node* namedItem(const AtomicString& name) const;
- PassRefPtr<NodeList> tags(const String&);
+ void appendToIdCache(const AtomicString& id, Element&);
+ void appendToNameCache(const AtomicString& name, Element&);
+ void didPopulate();
- // Non-DOM API
- bool hasNamedItem(const AtomicString& name) const;
- void namedItems(const AtomicString& name, Vector<Ref<Element>>&) const;
-
- 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();
- else if (*attrName == HTMLNames::idAttr || *attrName == HTMLNames::nameAttr)
- invalidateIdNameCacheMaps();
- }
- virtual void invalidateCache() const;
- void invalidateIdNameCacheMaps() 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; }
+ size_t memoryCost() const;
-protected:
- enum ElementTraversalType { NormalTraversal, CustomForwardOnlyTraversal };
- HTMLCollection(ContainerNode& base, CollectionType, ElementTraversalType = NormalTraversal);
+private:
+ typedef HashMap<AtomicStringImpl*, Vector<Element*>> StringToElementsMap;
+
+ const Vector<Element*>* find(const StringToElementsMap&, const AtomicString& key) const;
+ void append(StringToElementsMap&, const AtomicString& key, Element&);
- virtual void updateNameCache() const;
+ StringToElementsMap m_idMap;
+ StringToElementsMap m_nameMap;
+ Vector<AtomicString> m_propertyNames;
- typedef HashMap<AtomicStringImpl*, OwnPtr<Vector<Element*>>> NodeCacheMap;
- Vector<Element*>* idCache(const AtomicString& name) const { return m_idCache.get(name.impl()); }
- Vector<Element*>* nameCache(const AtomicString& name) const { return m_nameCache.get(name.impl()); }
- void appendIdCache(const AtomicString& name, Element* element) const { append(m_idCache, name, element); }
- void appendNameCache(const AtomicString& name, Element* element) const { append(m_nameCache, name, element); }
+#if !ASSERT_DISABLED
+ bool m_didPopulate { false };
+#endif
+};
+
+// HTMLCollection subclasses NodeList to maintain legacy ObjC API compatibility.
+class HTMLCollection : public NodeList {
+public:
+ virtual ~HTMLCollection();
- Document& document() const { return m_ownerNode->document(); }
+ // DOM API
+ 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();
+
+ // Non-DOM API
+ Vector<Ref<Element>> namedItems(const AtomicString& name) const;
+ size_t memoryCost() const override;
+
+ 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&);
- bool isItemRefElementsCacheValid() const { return m_isItemRefElementsCacheValid; }
- void setItemRefElementsCacheValid() const { m_isItemRefElementsCacheValid = true; }
+ bool hasNamedElementCache() const;
- NodeListRootType rootType() const { return static_cast<NodeListRootType>(m_rootType); }
+protected:
+ HTMLCollection(ContainerNode& base, CollectionType);
- bool hasNameCache() const { return m_isNameCacheValid; }
- void setHasNameCache() const { m_isNameCacheValid = true; }
+ virtual void updateNamedElementCache() const;
+ WEBCORE_EXPORT Element* namedItemSlow(const AtomicString& name) const;
-private:
- static void append(NodeCacheMap&, const AtomicString&, Element*);
+ void setNamedItemCache(std::unique_ptr<CollectionNamedElementCache>) const;
+ const CollectionNamedElementCache& namedItemCaches() const;
- 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;
- Ref<ContainerNode> m_ownerNode;
+ enum RootType { IsRootedAtNode, IsRootedAtDocument };
+ static RootType rootTypeFromCollectionType(CollectionType);
- mutable CollectionIndexCache<HTMLCollection, Element> m_indexCache;
+ Ref<ContainerNode> m_ownerNode;
- const unsigned m_rootType : 2;
- const unsigned m_invalidationType : 4;
- const unsigned m_shouldOnlyIncludeDirectChildren : 1;
+ mutable std::unique_ptr<CollectionNamedElementCache> m_namedElementCache;
- mutable unsigned m_isNameCacheValid : 1;
const unsigned m_collectionType : 5;
- const unsigned m_usesCustomForwardOnlyTraversal : 1;
- mutable unsigned m_isItemRefElementsCacheValid : 1;
-
- mutable NodeCacheMap m_idCache;
- mutable NodeCacheMap m_nameCache;
+ const unsigned m_invalidationType : 4;
+ const unsigned m_rootType : 1;
};
-} // namespace
-
+inline ContainerNode& HTMLCollection::rootNode() const
+{
+ if (isRootedAtDocument() && ownerNode().isConnected())
+ 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 m_ownerNode;
+}
+
+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()