#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.
}
}
-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;
}