bool SelectorChecker::checkOne(const CSSSelector& selector)
{
    switch (selector.match()) {
    case CSSSelector::Tag:
        {
            const AtomicString& localName = selector.tagQName().localName();
            return localName == starAtom || localName == m_element.localName();
        }
    case CSSSelector::Class:
        return m_element.hasClass() && m_element.classNames().contains(selector.value());
    case CSSSelector::Id:
        return m_element.hasID() && m_element.idForStyleResolution() == selector.value();
    case CSSSelector::Exact:
    case CSSSelector::Set:
        if (anyAttributeMatches(m_element, selector.match(), selector)) {
            m_matchedAttributeSelector = true;
            return true;
        }
        return false;
    case CSSSelector::PseudoClass:
        return checkPseudoClass(selector);
    // FIXME(sky): Remove pseudo elements completely.
    case CSSSelector::PseudoElement:
    case CSSSelector::Unknown:
        return false;
    }
    ASSERT_NOT_REACHED();
    return false;
}
Beispiel #2
0
static bool determineSelectorScopes(const CSSSelectorList& selectorList, HashSet<AtomicStringImpl*>& idScopes, HashSet<AtomicStringImpl*>& classScopes)
{
    for (CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
        CSSSelector* scopeSelector = 0;
        // This picks the widest scope, not the narrowest, to minimize the number of found scopes.
        for (CSSSelector* current = selector; current; current = current->tagHistory()) {
            // Prefer ids over classes.
            if (current->m_match == CSSSelector::Id)
                scopeSelector = current;
            else if (current->m_match == CSSSelector::Class && (!scopeSelector || scopeSelector->m_match != CSSSelector::Id))
                scopeSelector = current;
            CSSSelector::Relation relation = current->relation();
            if (relation != CSSSelector::Descendant && relation != CSSSelector::Child && relation != CSSSelector::SubSelector)
                break;
        }
        if (!scopeSelector)
            return false;
        ASSERT(scopeSelector->m_match == CSSSelector::Class || scopeSelector->m_match == CSSSelector::Id);
        if (scopeSelector->m_match == CSSSelector::Id)
            idScopes.add(scopeSelector->value().impl());
        else
            classScopes.add(scopeSelector->value().impl());
    }
    return true;
}
void extractClassIdOrTag(const CSSSelector& selector, Vector<AtomicString>& classes, AtomicString& id, AtomicString& tagName)
{
    if (selector.m_match == CSSSelector::Tag)
        tagName = selector.tagQName().localName();
    else if (selector.m_match == CSSSelector::Id)
        id = selector.value();
    else if (selector.m_match == CSSSelector::Class)
        classes.append(selector.value());
}
Beispiel #4
0
void RuleFeatureSet::extractInvalidationSetFeature(const CSSSelector& selector, InvalidationSetFeatures& features)
{
    if (selector.m_match == CSSSelector::Tag)
        features.tagName = selector.tagQName().localName();
    else if (selector.m_match == CSSSelector::Id)
        features.id = selector.value();
    else if (selector.m_match == CSSSelector::Class)
        features.classes.append(selector.value());
    else if (selector.isAttributeSelector())
        features.attributes.append(selector.attribute().localName());
    else if (selector.isCustomPseudoElement())
        features.customPseudoElement = true;
}
Beispiel #5
0
void RuleSet::addRule(StyleRule* rule, unsigned selectorIndex, AddRuleFlags addRuleFlags)
{
    RuleData ruleData(rule, selectorIndex, m_ruleCount++, addRuleFlags);

    collectFeaturesFromRuleData(m_features, ruleData);

    CSSSelector* selector = ruleData.selector();

    if (selector->m_match == CSSSelector::Id) {
        addToRuleSet(selector->value().impl(), m_idRules, ruleData);
        return;
    }
    if (selector->m_match == CSSSelector::Class) {
        addToRuleSet(selector->value().impl(), m_classRules, ruleData);
        return;
    }
    if (selector->isCustomPseudoElement()) {
        addToRuleSet(selector->value().impl(), m_shadowPseudoElementRules, ruleData);
        return;
    }
#if ENABLE(VIDEO_TRACK)
    if (selector->pseudoType() == CSSSelector::PseudoCue) {
        m_cuePseudoRules.append(ruleData);
        return;
    }
#endif
    if (SelectorChecker::isCommonPseudoClassSelector(selector)) {
        switch (selector->pseudoType()) {
        case CSSSelector::PseudoLink:
        case CSSSelector::PseudoVisited:
        case CSSSelector::PseudoAnyLink:
            m_linkPseudoClassRules.append(ruleData);
            return;
        case CSSSelector::PseudoFocus:
            m_focusPseudoClassRules.append(ruleData);
            return;
        default:
            ASSERT_NOT_REACHED();
        }
        return;
    }
    const AtomicString& localName = selector->tag().localName();
    if (localName != starAtom) {
        addToRuleSet(localName.impl(), m_tagRules, ruleData);
        return;
    }
    m_universalRules.append(ruleData);
}
Beispiel #6
0
static bool anyAttributeMatches(Element& element, CSSSelector::Match match, const CSSSelector& selector)
{
    const QualifiedName& selectorAttr = selector.attribute();
    ASSERT(selectorAttr.localName() != starAtom); // Should not be possible from the CSS grammar.

    // Synchronize the attribute in case it is lazy-computed.
    element.synchronizeAttribute(selectorAttr.localName());

    const AtomicString& selectorValue = selector.value();
    bool caseInsensitive = selector.attributeMatchType() == CSSSelector::CaseInsensitive;

    AttributeCollection attributes = element.attributesWithoutUpdate();
    AttributeCollection::iterator end = attributes.end();
    for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) {
        const Attribute& attributeItem = *it;

        if (!attributeItem.matches(selectorAttr))
            continue;

        if (attributeValueMatches(attributeItem, match, selectorValue, !caseInsensitive))
            return true;
    }

    return false;
}
Beispiel #7
0
void RuleSet::addRule(StyleRule* rule, unsigned selectorIndex, AddRuleFlags addRuleFlags)
{
    RuleData ruleData(rule, selectorIndex, m_ruleCount++, addRuleFlags);
    static const unsigned athostRuleSpecificity = 0x100000;

    if (addRuleFlags & RuleIsHostRule)
        ruleData.increaseSpecificity(athostRuleSpecificity);

    collectFeaturesFromRuleData(m_features, ruleData);

    CSSSelector* selector = ruleData.selector();

    if (selector->m_match == CSSSelector::Id) {
        addToRuleSet(selector->value().impl(), m_idRules, ruleData);
        return;
    }
    if (selector->m_match == CSSSelector::Class) {
        addToRuleSet(selector->value().impl(), m_classRules, ruleData);
        return;
    }
    if (selector->isUnknownPseudoElement()) {
        addToRuleSet(selector->value().impl(), m_shadowPseudoElementRules, ruleData);
        return;
    }
    if (SelectorChecker::isCommonPseudoClassSelector(selector)) {
        switch (selector->pseudoType()) {
        case CSSSelector::PseudoLink:
        case CSSSelector::PseudoVisited:
        case CSSSelector::PseudoAnyLink:
            m_linkPseudoClassRules.append(ruleData);
            return;
        case CSSSelector::PseudoFocus:
            m_focusPseudoClassRules.append(ruleData);
            return;
        default:
            ASSERT_NOT_REACHED();
        }
        return;
    }
    const AtomicString& localName = selector->tag().localName();
    if (localName != starAtom) {
        addToRuleSet(localName.impl(), m_tagRules, ruleData);
        return;
    }
    m_universalRules.append(ruleData);
}
bool RuleFeatureSet::extractInvalidationSetFeature(const CSSSelector& selector, InvalidationSetFeatures& features)
{
    if (selector.match() == CSSSelector::Tag && selector.tagQName().localName() != starAtom)
        features.tagName = selector.tagQName().localName();
    else if (selector.match() == CSSSelector::Id)
        features.id = selector.value();
    else if (selector.match() == CSSSelector::Class)
        features.classes.append(selector.value());
    else if (selector.isAttributeSelector())
        features.attributes.append(selector.attribute().localName());
    else if (selector.pseudoType() == CSSSelector::PseudoWebKitCustomElement)
        features.customPseudoElement = true;
    else if (selector.pseudoType() == CSSSelector::PseudoBefore || selector.pseudoType() == CSSSelector::PseudoAfter)
        features.hasBeforeOrAfter = true;
    else
        return false;
    return true;
}
static inline void collectDescendantSelectorIdentifierHashes(const CSSSelector& selector, unsigned*& hash)
{
    switch (selector.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;
    }
}
static bool anyAttributeMatches(const Element& element, CSSSelector::Match match, const CSSSelector& selector)
{
    const QualifiedName& selectorAttr = selector.attribute();
    ASSERT(selectorAttr.localName() != starAtom); // Should not be possible from the CSS grammar.

    if (match == CSSSelector::Set)
        return element.hasAttribute(selectorAttr);

    ASSERT(match == CSSSelector::Exact);

    const AtomicString& selectorValue = selector.value();
    const AtomicString& value = element.getAttribute(selectorAttr);

    if (value.isNull())
        return false;
    if (selector.attributeMatchType() == CSSSelector::CaseInsensitive)
        return equalIgnoringCase(selectorValue, value);
    return selectorValue == value;
}
Beispiel #11
0
void SelectorDataList::execute(const SelectorChecker& selectorChecker, Node* rootNode, Vector<RefPtr<Node> >& matchedElements) const
{
    if (canUseIdLookup(rootNode)) {
        ASSERT(m_selectors.size() == 1);
        CSSSelector* selector = m_selectors[0].selector;
        Element* element = rootNode->treeScope()->getElementById(selector->value());
        if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(rootNode)))
            return;
        if (selectorChecker.matches(m_selectors[0].selector, element, m_selectors[0].isFastCheckable))
            matchedElements.append(element);
        return;
    }

    unsigned selectorCount = m_selectors.size();

    Node* n = rootNode->firstChild();
    while (n) {
        if (n->isElementNode()) {
            Element* element = static_cast<Element*>(n);
            for (unsigned i = 0; i < selectorCount; ++i) {
                if (selectorChecker.matches(m_selectors[i].selector, element, m_selectors[i].isFastCheckable)) {
                    matchedElements.append(element);
                    if (firstMatchOnly)
                        return;
                    break;
                }
            }
            if (element->firstChild()) {
                n = element->firstChild();
                continue;
            }
        }
        while (!n->nextSibling()) {
            n = n->parentNode();
            if (n == rootNode)
                return;
        }
        n = n->nextSibling();
    }
}
Beispiel #12
0
static RuleFeatureSet::AttributeRules::SelectorKey makeAttributeSelectorKey(const CSSSelector& selector)
{
    bool caseInsensitive = selector.attributeValueMatchingIsCaseInsensitive();
    unsigned matchAndCase = static_cast<unsigned>(selector.match()) << 1 | (caseInsensitive ? 1 : 0);
    return std::make_pair(selector.attributeCanonicalLocalName().impl(), std::make_pair(selector.value().impl(), matchAndCase));
}