Commit dfff1021 authored by ch.dumez@samsung.com's avatar ch.dumez@samsung.com

Move HTMLCollection's id / name cache to a new NamedItemCache class

Move HTMLCollection's id / name cache to a new class. HTML's collection
m_hasValidIdNameCache, m_idCache and m_nameCache members were replaced by a
single OwnPtr that holds an instance of NamedItemCache when populated.

Most HTMLCollections do not have a valid namedItemCache so we end up saving
some memory. This also makes the code a bit clearer.

This patch is based on the following WebKit revision by rniwa@webkit.org:
http://trac.webkit.org/changeset/164772

R=

Review URL: https://codereview.chromium.org/215073003

git-svn-id: svn://svn.chromium.org/blink/trunk@170592 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 5a57c0d7
......@@ -50,15 +50,16 @@ Element* HTMLAllCollection::namedItemWithIndex(const AtomicString& name, unsigne
{
updateIdNameCache();
if (Vector<Element*>* cache = idCache(name)) {
if (index < cache->size())
return cache->at(index);
index -= cache->size();
const NamedItemCache& cache = namedItemCache();
if (Vector<Element*>* elements = cache.getElementsById(name)) {
if (index < elements->size())
return elements->at(index);
index -= elements->size();
}
if (Vector<Element*>* cache = nameCache(name)) {
if (index < cache->size())
return cache->at(index);
if (Vector<Element*>* elements = cache.getElementsByName(name)) {
if (index < elements->size())
return elements->at(index);
}
return 0;
......
......@@ -162,7 +162,6 @@ HTMLCollection::HTMLCollection(ContainerNode& ownerNode, CollectionType type, It
: LiveNodeListBase(ownerNode, rootTypeFromCollectionType(type), invalidationTypeExcludingIdAndNameAttributes(type), type)
, m_overridesItemAfter(itemAfterOverrideType == OverridesItemAfter)
, m_shouldOnlyIncludeDirectChildren(shouldTypeOnlyIncludeDirectChildren(type))
, m_hasValidIdNameCache(false)
{
ScriptWrappable::init(this);
}
......@@ -387,11 +386,12 @@ Element* HTMLCollection::namedItem(const AtomicString& name) const
// that are allowed a name attribute.
updateIdNameCache();
Vector<Element*>* idResults = idCache(name);
const NamedItemCache& cache = namedItemCache();
Vector<Element*>* idResults = cache.getElementsById(name);
if (idResults && !idResults->isEmpty())
return idResults->first();
Vector<Element*>* nameResults = nameCache(name);
Vector<Element*>* nameResults = cache.getElementsByName(name);
if (nameResults && !nameResults->isEmpty())
return nameResults->first();
......@@ -443,19 +443,18 @@ void HTMLCollection::updateIdNameCache() const
if (hasValidIdNameCache())
return;
NamedItemCache& cache = createNamedItemCache();
ContainerNode& root = rootNode();
for (Element* element = traverseToFirstElement(root); element; element = traverseNextElement(*element, root)) {
const AtomicString& idAttrVal = element->getIdAttribute();
if (!idAttrVal.isEmpty())
appendIdCache(idAttrVal, element);
cache.addElementWithId(idAttrVal, element);
if (!element->isHTMLElement())
continue;
const AtomicString& nameAttrVal = element->getNameAttribute();
if (!nameAttrVal.isEmpty() && idAttrVal != nameAttrVal && (type() != DocAll || nameShouldBeVisibleInDocumentAll(toHTMLElement(*element))))
appendNameCache(nameAttrVal, element);
cache.addElementWithName(nameAttrVal, element);
}
setHasValidIdNameCache();
}
void HTMLCollection::namedItems(const AtomicString& name, Vector<RefPtr<Element> >& result) const
......@@ -466,8 +465,9 @@ void HTMLCollection::namedItems(const AtomicString& name, Vector<RefPtr<Element>
updateIdNameCache();
Vector<Element*>* idResults = idCache(name);
Vector<Element*>* nameResults = nameCache(name);
const NamedItemCache& cache = namedItemCache();
Vector<Element*>* idResults = cache.getElementsById(name);
Vector<Element*>* nameResults = cache.getElementsByName(name);
for (unsigned i = 0; idResults && i < idResults->size(); ++i)
result.append(idResults->at(i));
......@@ -476,12 +476,4 @@ void HTMLCollection::namedItems(const AtomicString& name, Vector<RefPtr<Element>
result.append(nameResults->at(i));
}
void HTMLCollection::append(NodeCacheMap& map, const AtomicString& key, Element* element)
{
OwnPtr<Vector<Element*> >& vector = map.add(key.impl(), nullptr).storedValue->value;
if (!vector)
vector = adoptPtr(new Vector<Element*>);
vector->append(element);
}
} // namespace WebCore
......@@ -65,33 +65,54 @@ public:
protected:
HTMLCollection(ContainerNode& base, CollectionType, ItemAfterOverrideType);
class NamedItemCache {
public:
Vector<Element*>* getElementsById(const AtomicString& id) const { return m_idCache.get(id.impl()); }
Vector<Element*>* getElementsByName(const AtomicString& name) const { return m_nameCache.get(name.impl()); }
void addElementWithId(const AtomicString& id, Element* element) { addElementToMap(m_idCache, id, element); }
void addElementWithName(const AtomicString& name, Element* element) { addElementToMap(m_nameCache, name, element); }
private:
typedef HashMap<StringImpl*, OwnPtr<Vector<Element*> > > StringToElementsMap;
static void addElementToMap(StringToElementsMap& map, const AtomicString& key, Element* element)
{
OwnPtr<Vector<Element*> >& vector = map.add(key.impl(), nullptr).storedValue->value;
if (!vector)
vector = adoptPtr(new Vector<Element*>);
vector->append(element);
}
StringToElementsMap m_idCache;
StringToElementsMap m_nameCache;
};
bool overridesItemAfter() const { return m_overridesItemAfter; }
virtual Element* virtualItemAfter(Element*) const;
bool shouldOnlyIncludeDirectChildren() const { return m_shouldOnlyIncludeDirectChildren; }
virtual void supportedPropertyNames(Vector<String>& names);
virtual void updateIdNameCache() const;
bool hasValidIdNameCache() const { return m_hasValidIdNameCache; }
void setHasValidIdNameCache() const
bool hasValidIdNameCache() const { return m_namedItemCache; }
NamedItemCache& createNamedItemCache() const
{
ASSERT(!m_hasValidIdNameCache);
m_hasValidIdNameCache = true;
ASSERT(!m_namedItemCache);
document().incrementNodeListWithIdNameCacheCount();
m_namedItemCache = adoptPtr(new NamedItemCache);
return *m_namedItemCache;
}
NamedItemCache& namedItemCache() const
{
ASSERT(m_namedItemCache);
return *m_namedItemCache;
}
typedef HashMap<StringImpl*, 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); }
private:
Element* traverseNextElement(Element& previous, const ContainerNode& root) const;
static void append(NodeCacheMap&, const AtomicString&, Element*);
void invalidateIdNameCacheMaps(Document* oldDocument = 0) const
{
if (!m_hasValidIdNameCache)
if (!hasValidIdNameCache())
return;
// Make sure we decrement the NodeListWithIdNameCache count from
......@@ -99,22 +120,18 @@ private:
// is moved to a new document.
unregisterIdNameCacheFromDocument(oldDocument ? *oldDocument : document());
m_idCache.clear();
m_nameCache.clear();
m_hasValidIdNameCache = false;
m_namedItemCache.clear();
}
void unregisterIdNameCacheFromDocument(Document& document) const
{
ASSERT(m_hasValidIdNameCache);
ASSERT(hasValidIdNameCache());
document.decrementNodeListWithIdNameCacheCount();
}
const unsigned m_overridesItemAfter : 1;
const unsigned m_shouldOnlyIncludeDirectChildren : 1;
mutable unsigned m_hasValidIdNameCache : 1;
mutable NodeCacheMap m_idCache;
mutable NodeCacheMap m_nameCache;
mutable OwnPtr<NamedItemCache> m_namedItemCache;
mutable CollectionIndexCache<HTMLCollection, Element> m_collectionIndexCache;
friend class LiveNodeListBase;
......
......@@ -153,6 +153,7 @@ void HTMLFormControlsCollection::updateIdNameCache() const
if (hasValidIdNameCache())
return;
NamedItemCache& cache = createNamedItemCache();
HashSet<StringImpl*> foundInputElements;
const Vector<FormAssociatedElement*>& elementsArray = formControlElements();
......@@ -164,11 +165,11 @@ void HTMLFormControlsCollection::updateIdNameCache() const
const AtomicString& idAttrVal = element->getIdAttribute();
const AtomicString& nameAttrVal = element->getNameAttribute();
if (!idAttrVal.isEmpty()) {
appendIdCache(idAttrVal, element);
cache.addElementWithId(idAttrVal, element);
foundInputElements.add(idAttrVal.impl());
}
if (!nameAttrVal.isEmpty() && idAttrVal != nameAttrVal) {
appendNameCache(nameAttrVal, element);
cache.addElementWithName(nameAttrVal, element);
foundInputElements.add(nameAttrVal.impl());
}
}
......@@ -181,13 +182,11 @@ void HTMLFormControlsCollection::updateIdNameCache() const
const AtomicString& idAttrVal = element->getIdAttribute();
const AtomicString& nameAttrVal = element->getNameAttribute();
if (!idAttrVal.isEmpty() && !foundInputElements.contains(idAttrVal.impl()))
appendIdCache(idAttrVal, element);
cache.addElementWithId(idAttrVal, element);
if (!nameAttrVal.isEmpty() && idAttrVal != nameAttrVal && !foundInputElements.contains(nameAttrVal.impl()))
appendNameCache(nameAttrVal, element);
cache.addElementWithName(nameAttrVal, element);
}
}
setHasValidIdNameCache();
}
void HTMLFormControlsCollection::namedGetter(const AtomicString& name, bool& radioNodeListEnabled, RefPtr<RadioNodeList>& radioNodeList, bool& elementEnabled, RefPtr<Element>& element)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment