Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / css / SelectorFilter.cpp
index 0530099..352ae8f 100644 (file)
 #include "core/css/SelectorFilter.h"
 
 #include "core/css/CSSSelector.h"
-#include "core/dom/Element.h"
 
 namespace WebCore {
 
 // Salt to separate otherwise identical string hashes so a class-selector like .article won't match <article> elements.
 enum { TagNameSalt = 13, IdAttributeSalt = 17, ClassAttributeSalt = 19 };
 
-static inline void collectElementIdentifierHashes(const Element* element, Vector<unsigned, 4>& identifierHashes)
+static inline void collectElementIdentifierHashes(const Element& element, Vector<unsigned, 4>& identifierHashes)
 {
-    identifierHashes.append(element->localName().impl()->existingHash() * TagNameSalt);
-    if (element->hasID())
-        identifierHashes.append(element->idForStyleResolution().impl()->existingHash() * IdAttributeSalt);
-    if (element->isStyledElement() && element->hasClass()) {
-        const SpaceSplitString& classNames = element->classNames();
+    identifierHashes.append(element.localName().impl()->existingHash() * TagNameSalt);
+    if (element.hasID())
+        identifierHashes.append(element.idForStyleResolution().impl()->existingHash() * IdAttributeSalt);
+    if (element.isStyledElement() && element.hasClass()) {
+        const SpaceSplitString& classNames = element.classNames();
         size_t count = classNames.size();
         for (size_t i = 0; i < count; ++i)
             identifierHashes.append(classNames[i].impl()->existingHash() * ClassAttributeSalt);
     }
 }
 
-void SelectorFilter::pushParentStackFrame(Element* parent)
+void SelectorFilter::pushParentStackFrame(Element& parent)
 {
     ASSERT(m_ancestorIdentifierFilter);
-    ASSERT(m_parentStack.isEmpty() || m_parentStack.last().element == parent->parentOrShadowHostElement());
-    ASSERT(!m_parentStack.isEmpty() || !parent->parentOrShadowHostElement());
+    ASSERT(m_parentStack.isEmpty() || m_parentStack.last().element == parent.parentOrShadowHostElement());
+    ASSERT(!m_parentStack.isEmpty() || !parent.parentOrShadowHostElement());
     m_parentStack.append(ParentStackFrame(parent));
     ParentStackFrame& parentFrame = m_parentStack.last();
     // Mix tags, class names and ids into some sort of weird bouillabaisse.
@@ -80,92 +79,94 @@ void SelectorFilter::popParentStackFrame()
     }
 }
 
-void SelectorFilter::setupParentStack(Element* parent)
+void SelectorFilter::setupParentStack(Element& parent)
 {
     ASSERT(m_parentStack.isEmpty() == !m_ancestorIdentifierFilter);
     // Kill whatever we stored before.
     m_parentStack.shrink(0);
     m_ancestorIdentifierFilter = adoptPtr(new BloomFilter<bloomFilterKeyBits>);
     // Fast version if parent is a root element:
-    if (!parent->parentOrShadowHostNode()) {
+    if (!parent.parentOrShadowHostNode()) {
         pushParentStackFrame(parent);
         return;
     }
     // Otherwise climb up the tree.
     Vector<Element*, 30> ancestors;
-    for (Element* ancestor = parent; ancestor; ancestor = ancestor->parentOrShadowHostElement())
+    for (Element* ancestor = &parent; ancestor; ancestor = ancestor->parentOrShadowHostElement())
         ancestors.append(ancestor);
     for (size_t n = ancestors.size(); n; --n)
-        pushParentStackFrame(ancestors[n - 1]);
+        pushParentStackFrame(*ancestors[n - 1]);
 }
 
-void SelectorFilter::pushParent(Element* parent)
+void SelectorFilter::pushParent(Element& parent)
 {
     ASSERT(m_ancestorIdentifierFilter);
     // We may get invoked for some random elements in some wacky cases during style resolve.
     // Pause maintaining the stack in this case.
-    if (m_parentStack.last().element != parent->parentOrShadowHostElement())
+    if (m_parentStack.last().element != parent.parentOrShadowHostElement())
         return;
     pushParentStackFrame(parent);
 }
 
-static inline void collectDescendantSelectorIdentifierHashes(const CSSSelector* selector, unsigned*& hash)
+static inline void collectDescendantSelectorIdentifierHashes(const CSSSelector& selector, unsigned*& hash)
 {
-    switch (selector->m_match) {
+    switch (selector.m_match) {
     case CSSSelector::Id:
-        if (!selector->value().isEmpty())
-            (*hash++) = selector->value().impl()->existingHash() * IdAttributeSalt;
+        if (!selector.value().isEmpty())
+            (*hash++) = selector.value().impl()->existingHash() * IdAttributeSalt;
         break;
     case CSSSelector::Class:
-        if (!selector->value().isEmpty())
-            (*hash++) = selector->value().impl()->existingHash() * ClassAttributeSalt;
+        if (!selector.value().isEmpty())
+            (*hash++) = selector.value().impl()->existingHash() * ClassAttributeSalt;
         break;
     case CSSSelector::Tag:
-        if (selector->tagQName().localName() != starAtom)
-            (*hash++) = selector->tagQName().localName().impl()->existingHash() * TagNameSalt;
+        if (selector.tagQName().localName() != starAtom)
+            (*hash++) = selector.tagQName().localName().impl()->existingHash() * TagNameSalt;
         break;
     default:
         break;
     }
 }
 
-void SelectorFilter::collectIdentifierHashes(const CSSSelector* selector, unsigned* identifierHashes, unsigned maximumIdentifierCount)
+void SelectorFilter::collectIdentifierHashes(const CSSSelector& selector, unsigned* identifierHashes, unsigned maximumIdentifierCount)
 {
     unsigned* hash = identifierHashes;
     unsigned* end = identifierHashes + maximumIdentifierCount;
-    CSSSelector::Relation relation = selector->relation();
-    bool relationIsAffectedByPseudoContent = selector->relationIsAffectedByPseudoContent();
+    CSSSelector::Relation relation = selector.relation();
+    bool relationIsAffectedByPseudoContent = selector.relationIsAffectedByPseudoContent();
 
     // Skip the topmost selector. It is handled quickly by the rule hashes.
     bool skipOverSubselectors = true;
-    for (selector = selector->tagHistory(); selector; selector = selector->tagHistory()) {
+    for (const CSSSelector* current = selector.tagHistory(); current; current = current->tagHistory()) {
         // Only collect identifiers that match ancestors.
         switch (relation) {
         case CSSSelector::SubSelector:
             if (!skipOverSubselectors)
-                collectDescendantSelectorIdentifierHashes(selector, hash);
+                collectDescendantSelectorIdentifierHashes(*current, hash);
             break;
         case CSSSelector::DirectAdjacent:
         case CSSSelector::IndirectAdjacent:
         case CSSSelector::ShadowPseudo:
-        case CSSSelector::ChildTree:
-        case CSSSelector::DescendantTree:
             skipOverSubselectors = true;
             break;
         case CSSSelector::Descendant:
         case CSSSelector::Child:
             if (relationIsAffectedByPseudoContent) {
-                skipOverSubselectors = true;
-                break;
+                // Disable fastRejectSelector.
+                *identifierHashes = 0;
+                return;
             }
+            // Fall through.
+        case CSSSelector::ChildTree:
+        case CSSSelector::DescendantTree:
             skipOverSubselectors = false;
-            collectDescendantSelectorIdentifierHashes(selector, hash);
+            collectDescendantSelectorIdentifierHashes(*current, hash);
             break;
         }
         if (hash == end)
             return;
-        relation = selector->relation();
-        relationIsAffectedByPseudoContent = selector->relationIsAffectedByPseudoContent();
+        relation = current->relation();
+        relationIsAffectedByPseudoContent = current->relationIsAffectedByPseudoContent();
     }
     *hash = 0;
 }