diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/html/HTMLCollection.h | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/html/HTMLCollection.h')
-rw-r--r-- | Source/WebCore/html/HTMLCollection.h | 252 |
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() |