Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1372)

Unified Diff: third_party/WebKit/Source/core/dom/NthIndexCache.cpp

Issue 1655993005: Only cache nth-indices when child count > 32. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Renamed constant Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/WebKit/Source/core/dom/NthIndexCache.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/core/dom/NthIndexCache.cpp
diff --git a/third_party/WebKit/Source/core/dom/NthIndexCache.cpp b/third_party/WebKit/Source/core/dom/NthIndexCache.cpp
index a039019abecbb93d6e2a5b6d1fcaf045d0d1549d..de8c37d0d3c90b9aee8cb24fa768942f4e76328b 100644
--- a/third_party/WebKit/Source/core/dom/NthIndexCache.cpp
+++ b/third_party/WebKit/Source/core/dom/NthIndexCache.cpp
@@ -24,20 +24,146 @@ NthIndexCache::~NthIndexCache()
m_document->setNthIndexCache(nullptr);
}
-NthIndexData& NthIndexCache::ensureNthIndexDataFor(Node& parent)
+namespace {
+
+// Generating the cached nth-index counts when the number of children
+// exceeds this count. This number is picked based on testing
+// querySelectorAll for :nth-child(3n+2) and :nth-of-type(3n+2) on an
+// increasing number of children.
+
+const unsigned kCachedSiblingCountLimit = 32;
+
+unsigned uncachedNthChildIndex(Element& element)
+{
+ int index = 1;
+ for (const Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(*sibling))
+ index++;
+
+ return index;
+}
+
+unsigned uncachedNthLastChildIndex(Element& element)
+{
+ int index = 1;
+ for (const Element* sibling = ElementTraversal::nextSibling(element); sibling; sibling = ElementTraversal::nextSibling(*sibling))
+ ++index;
+ return index;
+}
+
+unsigned uncachedNthOfTypeIndex(Element& element, unsigned& siblingCount)
+{
+ int index = 1;
+ const QualifiedName& tag = element.tagQName();
+ for (const Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(*sibling)) {
+ if (sibling->tagQName() == tag)
+ ++index;
+ ++siblingCount;
+ }
+ return index;
+}
+
+unsigned uncachedNthLastOfTypeIndex(Element& element, unsigned& siblingCount)
+{
+ int index = 1;
+ const QualifiedName& tag = element.tagQName();
+ for (const Element* sibling = ElementTraversal::nextSibling(element); sibling; sibling = ElementTraversal::nextSibling(*sibling)) {
+ if (sibling->tagQName() == tag)
+ ++index;
+ ++siblingCount;
+ }
+ return index;
+}
+
+} // namespace
+
+unsigned NthIndexCache::nthChildIndex(Element& element)
+{
+ if (element.isPseudoElement())
+ return 1;
+ ASSERT(element.parentNode());
+ NthIndexCache* nthIndexCache = element.document().nthIndexCache();
+ NthIndexData* nthIndexData = nullptr;
+ if (nthIndexCache && nthIndexCache->m_parentMap)
+ nthIndexData = nthIndexCache->m_parentMap->get(element.parentNode());
+ if (nthIndexData)
+ return nthIndexData->nthIndex(element);
+ unsigned index = uncachedNthChildIndex(element);
+ if (nthIndexCache && index > kCachedSiblingCountLimit)
+ nthIndexCache->cacheNthIndexDataForParent(element);
+ return index;
+}
+
+unsigned NthIndexCache::nthLastChildIndex(Element& element)
+{
+ if (element.isPseudoElement())
+ return 1;
+ ASSERT(element.parentNode());
+ NthIndexCache* nthIndexCache = element.document().nthIndexCache();
+ NthIndexData* nthIndexData = nullptr;
+ if (nthIndexCache && nthIndexCache->m_parentMap)
+ nthIndexData = nthIndexCache->m_parentMap->get(element.parentNode());
+ if (nthIndexData)
+ return nthIndexData->nthLastIndex(element);
+ unsigned index = uncachedNthLastChildIndex(element);
+ if (nthIndexCache && index > kCachedSiblingCountLimit)
+ nthIndexCache->cacheNthIndexDataForParent(element);
+ return index;
+}
+
+NthIndexData* NthIndexCache::nthTypeIndexDataForParent(Element& element) const
+{
+ ASSERT(element.parentNode());
+ if (!m_parentMapForType)
+ return nullptr;
+ if (const IndexByType* map = m_parentMapForType->get(element.parentNode()))
+ return map->get(element.tagName());
+ return nullptr;
+}
+
+unsigned NthIndexCache::nthOfTypeIndex(Element& element)
+{
+ if (element.isPseudoElement())
+ return 1;
+ NthIndexCache* nthIndexCache = element.document().nthIndexCache();
+ if (nthIndexCache) {
+ if (NthIndexData* nthIndexData = nthIndexCache->nthTypeIndexDataForParent(element))
+ return nthIndexData->nthOfTypeIndex(element);
+ }
+ unsigned siblingCount = 0;
+ unsigned index = uncachedNthOfTypeIndex(element, siblingCount);
+ if (nthIndexCache && siblingCount > kCachedSiblingCountLimit)
+ nthIndexCache->cacheNthOfTypeIndexDataForParent(element);
+ return index;
+}
+
+unsigned NthIndexCache::nthLastOfTypeIndex(Element& element)
{
+ if (element.isPseudoElement())
+ return 1;
+ NthIndexCache* nthIndexCache = element.document().nthIndexCache();
+ if (nthIndexCache) {
+ if (NthIndexData* nthIndexData = nthIndexCache->nthTypeIndexDataForParent(element))
+ return nthIndexData->nthLastOfTypeIndex(element);
+ }
+ unsigned siblingCount = 0;
+ unsigned index = uncachedNthLastOfTypeIndex(element, siblingCount);
+ if (nthIndexCache && siblingCount > kCachedSiblingCountLimit)
+ nthIndexCache->cacheNthOfTypeIndexDataForParent(element);
+ return index;
+}
+
+void NthIndexCache::cacheNthIndexDataForParent(Element& element)
+{
+ ASSERT(element.parentNode());
if (!m_parentMap)
m_parentMap = adoptPtrWillBeNoop(new ParentMap());
- ParentMap::AddResult addResult = m_parentMap->add(&parent, nullptr);
- if (addResult.isNewEntry)
- addResult.storedValue->value = adoptPtrWillBeNoop(new NthIndexData());
-
- ASSERT(addResult.storedValue->value);
- return *addResult.storedValue->value;
+ ParentMap::AddResult addResult = m_parentMap->add(element.parentNode(), nullptr);
+ ASSERT(addResult.isNewEntry);
+ addResult.storedValue->value = adoptPtrWillBeNoop(new NthIndexData(*element.parentNode()));
}
-NthIndexCache::IndexByType& NthIndexCache::ensureTypeIndexMap(Node& parent)
+NthIndexCache::IndexByType& NthIndexCache::ensureTypeIndexMap(ContainerNode& parent)
{
if (!m_parentMapForType)
m_parentMapForType = adoptPtrWillBeNoop(new ParentMapForType());
@@ -50,20 +176,17 @@ NthIndexCache::IndexByType& NthIndexCache::ensureTypeIndexMap(Node& parent)
return *addResult.storedValue->value;
}
-NthIndexData& NthIndexCache::nthIndexDataWithTagName(Element& element)
+void NthIndexCache::cacheNthOfTypeIndexDataForParent(Element& element)
{
+ ASSERT(element.parentNode());
IndexByType::AddResult addResult = ensureTypeIndexMap(*element.parentNode()).add(element.tagName(), nullptr);
- if (addResult.isNewEntry)
- addResult.storedValue->value = adoptPtrWillBeNoop(new NthIndexData());
- return *addResult.storedValue->value;
+ ASSERT(addResult.isNewEntry);
+ addResult.storedValue->value = adoptPtrWillBeNoop(new NthIndexData(*element.parentNode(), element.tagQName()));
}
-unsigned NthIndexData::nthIndex(Element& element)
+unsigned NthIndexData::nthIndex(Element& element) const
{
- if (element.isPseudoElement())
- return 1;
- if (!m_count)
- return cacheNthIndices(element);
+ ASSERT(!element.isPseudoElement());
unsigned index = 0;
for (Element* sibling = &element; sibling; sibling = ElementTraversal::previousSibling(*sibling), index++) {
@@ -74,14 +197,12 @@ unsigned NthIndexData::nthIndex(Element& element)
return index;
}
-unsigned NthIndexData::nthIndexOfType(Element& element, const QualifiedName& type)
+unsigned NthIndexData::nthOfTypeIndex(Element& element) const
{
- if (element.isPseudoElement())
- return 1;
- if (!m_count)
- return cacheNthIndicesOfType(element, type);
+ ASSERT(!element.isPseudoElement());
+
unsigned index = 0;
- for (Element* sibling = &element; sibling; sibling = ElementTraversal::previousSibling(*sibling, HasTagName(type)), index++) {
+ for (Element* sibling = &element; sibling; sibling = ElementTraversal::previousSibling(*sibling, HasTagName(element.tagQName())), index++) {
auto it = m_elementIndexMap.find(sibling);
if (it != m_elementIndexMap.end())
return it->value + index;
@@ -89,27 +210,18 @@ unsigned NthIndexData::nthIndexOfType(Element& element, const QualifiedName& typ
return index;
}
-unsigned NthIndexData::nthLastIndex(Element& element)
+unsigned NthIndexData::nthLastIndex(Element& element) const
{
- if (element.isPseudoElement())
- return 1;
- unsigned index = nthIndex(element);
- return m_count - index + 1;
+ return m_count - nthIndex(element) + 1;
}
-unsigned NthIndexData::nthLastIndexOfType(Element& element, const QualifiedName& type)
+unsigned NthIndexData::nthLastOfTypeIndex(Element& element) const
{
- if (element.isPseudoElement())
- return 1;
- unsigned index = nthIndexOfType(element, type);
- return m_count - index + 1;
+ return m_count - nthOfTypeIndex(element) + 1;
}
-unsigned NthIndexData::cacheNthIndices(Element& element)
+NthIndexData::NthIndexData(ContainerNode& parent)
{
- ASSERT(!element.isPseudoElement());
- ASSERT(m_elementIndexMap.isEmpty());
- unsigned index = 0;
// The frequency at which we cache the nth-index for a set of siblings.
// A spread value of 3 means every third Element will have its nth-index cached.
// Using a spread value > 1 is done to save memory. Looking up the nth-index will
@@ -117,22 +229,16 @@ unsigned NthIndexData::cacheNthIndices(Element& element)
// elements will be traversed.
const unsigned spread = 3;
unsigned count = 0;
- for (Element* sibling = ElementTraversal::firstChild(*element.parentNode()); sibling; sibling = ElementTraversal::nextSibling(*sibling)) {
+ for (Element* sibling = ElementTraversal::firstChild(parent); sibling; sibling = ElementTraversal::nextSibling(*sibling)) {
if (!(++count % spread))
m_elementIndexMap.add(sibling, count);
- if (sibling == &element)
- index = count;
}
- ASSERT(count && index);
+ ASSERT(count);
m_count = count;
- return index;
}
-unsigned NthIndexData::cacheNthIndicesOfType(Element& element, const QualifiedName& type)
+NthIndexData::NthIndexData(ContainerNode& parent, const QualifiedName& type)
{
- ASSERT(!element.isPseudoElement());
- ASSERT(m_elementIndexMap.isEmpty());
- unsigned index = 0;
// The frequency at which we cache the nth-index of type for a set of siblings.
// A spread value of 3 means every third Element of its type will have its nth-index cached.
// Using a spread value > 1 is done to save memory. Looking up the nth-index of its type will
@@ -140,15 +246,12 @@ unsigned NthIndexData::cacheNthIndicesOfType(Element& element, const QualifiedNa
// will be equal to find 'spread' elements in the sibling set.
const unsigned spread = 3;
unsigned count = 0;
- for (Element* sibling = ElementTraversal::firstChild(*element.parentNode(), HasTagName(type)); sibling; sibling = ElementTraversal::nextSibling(*sibling, HasTagName(type))) {
+ for (Element* sibling = ElementTraversal::firstChild(parent, HasTagName(type)); sibling; sibling = ElementTraversal::nextSibling(*sibling, HasTagName(type))) {
if (!(++count % spread))
m_elementIndexMap.add(sibling, count);
- if (sibling == &element)
- index = count;
}
- ASSERT(count && index);
+ ASSERT(count);
m_count = count;
- return index;
}
DEFINE_TRACE(NthIndexData)
« no previous file with comments | « third_party/WebKit/Source/core/dom/NthIndexCache.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698