This source file includes following definitions.
- collectElementIdentifierHashes
- pushParentStackFrame
- popParentStackFrame
- setupParentStack
- pushParent
- collectDescendantSelectorIdentifierHashes
- collectIdentifierHashes
#include "config.h"
#include "core/css/SelectorFilter.h"
#include "core/css/CSSSelector.h"
namespace WebCore {
enum { TagNameSalt = 13, IdAttributeSalt = 17, ClassAttributeSalt = 19 };
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();
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)
{
ASSERT(m_ancestorIdentifierFilter);
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();
collectElementIdentifierHashes(parent, parentFrame.identifierHashes);
size_t count = parentFrame.identifierHashes.size();
for (size_t i = 0; i < count; ++i)
m_ancestorIdentifierFilter->add(parentFrame.identifierHashes[i]);
}
void SelectorFilter::popParentStackFrame()
{
ASSERT(!m_parentStack.isEmpty());
ASSERT(m_ancestorIdentifierFilter);
const ParentStackFrame& parentFrame = m_parentStack.last();
size_t count = parentFrame.identifierHashes.size();
for (size_t i = 0; i < count; ++i)
m_ancestorIdentifierFilter->remove(parentFrame.identifierHashes[i]);
m_parentStack.removeLast();
if (m_parentStack.isEmpty()) {
ASSERT(m_ancestorIdentifierFilter->likelyEmpty());
m_ancestorIdentifierFilter.clear();
}
}
void SelectorFilter::setupParentStack(Element& parent)
{
ASSERT(m_parentStack.isEmpty() == !m_ancestorIdentifierFilter);
m_parentStack.shrink(0);
m_ancestorIdentifierFilter = adoptPtr(new BloomFilter<bloomFilterKeyBits>);
if (!parent.parentOrShadowHostNode()) {
pushParentStackFrame(parent);
return;
}
Vector<Element*, 30> ancestors;
for (Element* ancestor = &parent; ancestor; ancestor = ancestor->parentOrShadowHostElement())
ancestors.append(ancestor);
for (size_t n = ancestors.size(); n; --n)
pushParentStackFrame(*ancestors[n - 1]);
}
void SelectorFilter::pushParent(Element& parent)
{
ASSERT(m_ancestorIdentifierFilter);
if (m_parentStack.last().element != parent.parentOrShadowHostElement())
return;
pushParentStackFrame(parent);
}
static inline void collectDescendantSelectorIdentifierHashes(const CSSSelector& selector, unsigned*& hash)
{
switch (selector.m_match) {
case CSSSelector::Id:
if (!selector.value().isEmpty())
(*hash++) = selector.value().impl()->existingHash() * IdAttributeSalt;
break;
case CSSSelector::Class:
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;
break;
default:
break;
}
}
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();
bool skipOverSubselectors = true;
for (const CSSSelector* current = selector.tagHistory(); current; current = current->tagHistory()) {
switch (relation) {
case CSSSelector::SubSelector:
if (!skipOverSubselectors)
collectDescendantSelectorIdentifierHashes(*current, hash);
break;
case CSSSelector::DirectAdjacent:
case CSSSelector::IndirectAdjacent:
skipOverSubselectors = true;
break;
case CSSSelector::Descendant:
case CSSSelector::Child:
if (relationIsAffectedByPseudoContent) {
*identifierHashes = 0;
return;
}
case CSSSelector::ShadowPseudo:
case CSSSelector::ShadowDeep:
skipOverSubselectors = false;
collectDescendantSelectorIdentifierHashes(*current, hash);
break;
}
if (hash == end)
return;
relation = current->relation();
relationIsAffectedByPseudoContent = current->relationIsAffectedByPseudoContent();
}
*hash = 0;
}
}