Example #1
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;
}
Example #2
0
static unsigned simpleSelectorFunctionalPseudoClassStaticSpecificity(const CSSSelector& simpleSelector, bool& ok)
{
    if (simpleSelector.match() == CSSSelector::PseudoClass) {
        CSSSelector::PseudoClassType pseudoClassType = simpleSelector.pseudoClassType();
        if (pseudoClassType == CSSSelector::PseudoClassMatches || pseudoClassType == CSSSelector::PseudoClassNthChild || pseudoClassType == CSSSelector::PseudoClassNthLastChild) {
            const CSSSelectorList* selectorList = simpleSelector.selectorList();
            if (!selectorList) {
                ASSERT_WITH_MESSAGE(pseudoClassType != CSSSelector::PseudoClassMatches, ":matches() should never be created without a valid selector list.");
                return 0;
            }

            const CSSSelector& firstSubselector = *selectorList->first();

            unsigned initialSpecificity = staticSpecificityInternal(firstSubselector, ok);
            if (!ok)
                return 0;

            const CSSSelector* subselector = &firstSubselector;
            while ((subselector = CSSSelectorList::next(subselector))) {
                unsigned subSelectorSpecificity = staticSpecificityInternal(*subselector, ok);
                if (initialSpecificity != subSelectorSpecificity)
                    ok = false;
                if (!ok)
                    return 0;
            }
            return initialSpecificity;
        }
    }
    return 0;
}
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;
}
Example #4
0
PassRefPtr<StaticNodeList> createSelectorNodeList(PassRefPtr<Node> rootNode, CSSSelector* querySelector)
{
    Vector<RefPtr<Node> > nodes;
    Document* document = rootNode->document();
    AtomicString selectorValue = querySelector->m_value;

    if (!querySelector->next() && querySelector->m_match == CSSSelector::Id && !document->containsMultipleElementsWithId(selectorValue)) {
        Element* element = document->getElementById(selectorValue);
        if (element && (rootNode->isDocumentNode() || element->isDescendantOf(rootNode.get())))
            nodes.append(element);
    } else {
        CSSStyleSelector::SelectorChecker selectorChecker(document, !document->inCompatMode());
        
        for (Node* n = rootNode->firstChild(); n; n = n->traverseNextNode(rootNode.get())) {
            if (n->isElementNode()) {
                Element* element = static_cast<Element*>(n);
                for (CSSSelector* selector = querySelector; selector; selector = selector->next()) {
                    if (selectorChecker.checkSelector(selector, element)) {
                        nodes.append(n);
                        break;
                    }
                }
            }
        }
    }
    
    return StaticNodeList::adopt(nodes);
}
Example #5
0
static inline bool includesDisallowedPseudoClass(const CSSSelector& selector)
{
    if (selector.pseudoType() == CSSSelector::PseudoNot) {
        const CSSSelector* subSelector = selector.selectorList()->first();
        return subSelector->match() == CSSSelector::PseudoClass;
    }
    return selector.match() == CSSSelector::PseudoClass;
}
 bool operator()(const CSSSelector& selector)
 {
     if (selector.match() == CSSSelector::Tag && selector.tagQName().prefix() != nullAtom && selector.tagQName().prefix() != starAtom)
         return true;
     if (selector.isAttributeSelector() && selector.attribute().prefix() != nullAtom && selector.attribute().prefix() != starAtom)
         return true;
     return false;
 }
Example #7
0
unsigned CSSSelectorList::length() const {
  if (!m_selectorArray)
    return 0;
  CSSSelector* current = m_selectorArray;
  while (!current->isLastInSelectorList())
    ++current;
  return (current - m_selectorArray) + 1;
}
Example #8
0
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());
}
Example #9
0
void CSSSelectorList::deleteSelectors()
{
    if (!m_selectorArray)
        return;

    for (CSSSelector* s = m_selectorArray; !s->isLastInSelectorList(); ++s)
        s->~CSSSelector();
    fastFree(m_selectorArray);
}
String CSSStyleRule::selectorText() const
{
    String str;
    for (CSSSelector* s = selectorList().first(); s; s = CSSSelectorList::next(s)) {
        if (s != selectorList().first())
            str += ", ";
        str += s->selectorText();
    }
    return str;
}
Example #11
0
String CSSStyleRule::generateSelectorText() const
{
    StringBuilder builder;
    for (CSSSelector* s = m_styleRule->selectorList().first(); s; s = CSSSelectorList::next(s)) {
        if (s != m_styleRule->selectorList().first())
            builder.append(", ");
        builder.append(s->selectorText());
    }
    return builder.toString();
}
Example #12
0
void CSSSelectorList::deleteSelectors() {
  ASSERT(m_selectorArray);

  bool finished = false;
  for (CSSSelector* s = m_selectorArray; !finished; ++s) {
    finished = s->isLastInSelectorList();
    s->~CSSSelector();
  }

  WTF::Partitions::fastFree(m_selectorArray);
}
Example #13
0
static inline bool selectorListContainsUncommonAttributeSelector(const CSSSelector* selector)
{
    CSSSelectorList* selectorList = selector->selectorList();
    if (!selectorList)
        return false;
    for (CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) {
        if (subSelector->isAttributeSelector())
            return true;
    }
    return false;
}
Example #14
0
String CSSPageRule::pageSelectorText() const
{
    String text = "@page";
    CSSSelector* selector = selectorList().first();
    if (selector) {
        String pageSpecification = selector->selectorText();
        if (!pageSpecification.isEmpty() && pageSpecification != starAtom)
            text += " " + pageSpecification;
    }
    return text;
}
Example #15
0
void CSSSelectorList::deleteSelectors()
{
    if (!m_selectorArray)
        return;

    for (CSSSelector* s = m_selectorArray; ; ++s) {
        s->~CSSSelector();
        if (s->isLastInSelectorList())
            break;
    }
    fastFree(m_selectorArray);
}
Example #16
0
String CSSSelectorList::selectorsText() const
{
    StringBuilder result;

    for (CSSSelector* s = first(); s; s = next(s)) {
        if (s != first())
            result.append(", ");
        result.append(s->selectorText());
    }

    return result.toString();
}
static inline bool isSelectorMatchingHTMLBasedOnRuleHash(const CSSSelector& selector)
{
    if (selector.tagHistory())
        return false;

    if (selector.match() == CSSSelector::Tag) {
        const AtomicString& selectorNamespace = selector.tagQName().namespaceURI();
        return selectorNamespace == starAtom || selectorNamespace == xhtmlNamespaceURI;
    }
    if (SelectorChecker::isCommonPseudoClassSelector(&selector))
        return true;
    return selector.match() == CSSSelector::Id || selector.match() == CSSSelector::Class;
}
Example #18
0
String CSSStyleRule::selectorText() const
{
    if (m_selector) {
        String str;
        for (CSSSelector* s = m_selector; s; s = s->next()) {
            if (s != m_selector)
                str += ", ";
            str += s->selectorText();
        }
        return str;
    }
    return String();
}
void CSSSelectorList::deleteSelectors()
{
    if (!m_selectorArray)
        return;

    bool finished = false;
    for (CSSSelector* s = m_selectorArray; !finished; ++s) {
        finished = s->isLastInSelectorList();
        s->~CSSSelector();
    }

    fastFree(m_selectorArray);
}
Example #20
0
void SelectorFilter::collectIdentifierHashes(const CSSSelector& selector,
                                             unsigned* identifierHashes,
                                             unsigned maximumIdentifierCount) {
  unsigned* hash = identifierHashes;
  unsigned* end = identifierHashes + maximumIdentifierCount;
  CSSSelector::RelationType relation = selector.relation();
  if (selector.relationIsAffectedByPseudoContent()) {
    // Disable fastRejectSelector.
    *identifierHashes = 0;
    return;
  }

  // Skip the topmost selector. It is handled quickly by the rule hashes.
  bool skipOverSubselectors = true;
  for (const CSSSelector* current = selector.tagHistory(); current;
       current = current->tagHistory()) {
    // Only collect identifiers that match ancestors.
    switch (relation) {
      case CSSSelector::SubSelector:
        if (!skipOverSubselectors)
          collectDescendantSelectorIdentifierHashes(*current, hash);
        break;
      case CSSSelector::DirectAdjacent:
      case CSSSelector::IndirectAdjacent:
        skipOverSubselectors = true;
        break;
      case CSSSelector::ShadowSlot:
        // Disable fastRejectSelector.
        *identifierHashes = 0;
        return;
      case CSSSelector::Descendant:
      case CSSSelector::Child:
      // Fall through.
      case CSSSelector::ShadowPseudo:
      case CSSSelector::ShadowDeep:
        skipOverSubselectors = false;
        collectDescendantSelectorIdentifierHashes(*current, hash);
        break;
    }
    if (hash == end)
      return;
    relation = current->relation();
    if (current->relationIsAffectedByPseudoContent()) {
      // Disable fastRejectSelector.
      *identifierHashes = 0;
      return;
    }
  }
  *hash = 0;
}
Example #21
0
bool SelectorChecker::checkPseudoClass(const CSSSelector& selector)
{
    switch (selector.pseudoType()) {
    case CSSSelector::PseudoFocus:
        m_matchedFocusSelector = true;
        return matchesFocusPseudoClass(m_element);

    case CSSSelector::PseudoHover:
        m_matchedHoverSelector = true;
        return m_element.hovered();

    case CSSSelector::PseudoActive:
        m_matchedActiveSelector = true;
        return m_element.active();

    case CSSSelector::PseudoLang:
    {
        AtomicString value = m_element.computeInheritedLanguage();
        const AtomicString& argument = selector.argument();
        if (value.isEmpty() || !value.startsWith(argument, false))
            break;
        if (value.length() != argument.length() && value[argument.length()] != '-')
            break;
        return true;
    }

    case CSSSelector::PseudoHost:
    {
        // We can only get here if the selector was defined in the right
        // scope so we don't need to check it.

        // For empty parameter case, i.e. just :host or :host().
        if (!selector.selectorList())
            return true;
        for (const CSSSelector* current = selector.selectorList()->first(); current; current = CSSSelectorList::next(*current)) {
            if (match(*current))
                return true;
        }
        return false;
    }

    case CSSSelector::PseudoUnknown:
    case CSSSelector::PseudoNotParsed:
    case CSSSelector::PseudoUserAgentCustomElement:
        return false;
    }
    ASSERT_NOT_REACHED();
    return false;
}
void SelectRuleFeatureSet::collectFeaturesFromSelector(const CSSSelector& selector)
{
    m_cssRuleFeatureSet.collectFeaturesFromSelector(selector);

    switch (selector.pseudoType()) {
    case CSSSelector::PseudoChecked:
        setSelectRuleFeature(AffectedSelectorChecked);
        break;
    case CSSSelector::PseudoEnabled:
        setSelectRuleFeature(AffectedSelectorEnabled);
        break;
    case CSSSelector::PseudoDisabled:
        setSelectRuleFeature(AffectedSelectorDisabled);
        break;
    case CSSSelector::PseudoIndeterminate:
        setSelectRuleFeature(AffectedSelectorIndeterminate);
        break;
    case CSSSelector::PseudoLink:
        setSelectRuleFeature(AffectedSelectorLink);
        break;
    case CSSSelector::PseudoTarget:
        setSelectRuleFeature(AffectedSelectorTarget);
        break;
    case CSSSelector::PseudoVisited:
        setSelectRuleFeature(AffectedSelectorVisited);
        break;
    default:
        break;
    }
}
Example #23
0
static inline bool isSelectorMatchingHTMLBasedOnRuleHash(const CSSSelector& selector)
{
    if (selector.m_match == CSSSelector::Tag) {
        const AtomicString& selectorNamespace = selector.tagQName().namespaceURI();
        if (selectorNamespace != starAtom && selectorNamespace != xhtmlNamespaceURI)
            return false;
        if (selector.relation() == CSSSelector::SubSelector) {
            ASSERT(selector.tagHistory());
            return isSelectorMatchingHTMLBasedOnRuleHash(*selector.tagHistory());
        }
        return true;
    }
    if (SelectorChecker::isCommonPseudoClassSelector(selector))
        return true;
    return selector.m_match == CSSSelector::Id || selector.m_match == CSSSelector::Class;
}
Example #24
0
static unsigned selectorSpecificity(const CSSSelector& firstSimpleSelector, bool isComputingMaximumSpecificity)
{
    unsigned total = simpleSelectorSpecificityInternal(firstSimpleSelector, isComputingMaximumSpecificity);

    for (const CSSSelector* selector = firstSimpleSelector.tagHistory(); selector; selector = selector->tagHistory())
        total = CSSSelector::addSpecificities(total, simpleSelectorSpecificityInternal(*selector, isComputingMaximumSpecificity));
    return total;
}
Example #25
0
static inline MatchBasedOnRuleHash computeMatchBasedOnRuleHash(const CSSSelector& selector)
{
    if (selector.tagHistory())
        return MatchBasedOnRuleHash::None;

    if (selector.match() == CSSSelector::Tag) {
        const QualifiedName& tagQualifiedName = selector.tagQName();
        const AtomicString& selectorNamespace = tagQualifiedName.namespaceURI();
        if (selectorNamespace == starAtom || selectorNamespace == xhtmlNamespaceURI) {
            if (tagQualifiedName == anyQName())
                return MatchBasedOnRuleHash::Universal;
            return MatchBasedOnRuleHash::ClassC;
        }
        return MatchBasedOnRuleHash::None;
    }
    if (SelectorChecker::isCommonPseudoClassSelector(&selector))
        return MatchBasedOnRuleHash::ClassB;
#if ENABLE(SHADOW_DOM)
    if (selector.match() == CSSSelector::PseudoClass && selector.pseudoClassType() == CSSSelector::PseudoClassHost)
        return MatchBasedOnRuleHash::ClassB;
#endif
    if (selector.match() == CSSSelector::Id)
        return MatchBasedOnRuleHash::ClassA;
    if (selector.match() == CSSSelector::Class)
        return MatchBasedOnRuleHash::ClassB;
    return MatchBasedOnRuleHash::None;
}
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;
}
Example #27
0
static void collectFeaturesFromRuleData(RuleFeatureSet& features, const RuleData& ruleData)
{
    bool foundSiblingSelector = false;
    for (CSSSelector* selector = ruleData.selector(); selector; selector = selector->tagHistory()) {
        features.collectFeaturesFromSelector(selector);
        
        if (CSSSelectorList* selectorList = selector->selectorList()) {
            for (CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) {
                if (!foundSiblingSelector && selector->isSiblingSelector())
                    foundSiblingSelector = true;
                features.collectFeaturesFromSelector(subSelector);
            }
        } else if (!foundSiblingSelector && selector->isSiblingSelector())
            foundSiblingSelector = true;
    }
    if (foundSiblingSelector)
        features.siblingRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin()));
    if (ruleData.containsUncommonAttributeSelector())
        features.uncommonAttributeRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin()));
}
Example #28
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();
    }
}
Example #29
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;
}
Example #30
0
static bool validateSelector(CSSSelector* selector)
{
    ASSERT(selector);

    if (!validateSubSelector(selector))
        return false;

    CSSSelector* prevSubSelector = selector;
    CSSSelector* subSelector = selector->tagHistory();

    while (subSelector) {
        if (prevSubSelector->relation() != CSSSelector::SubSelector)
            return false;
        if (!validateSubSelector(subSelector))
            return false;

        prevSubSelector = subSelector;
        subSelector = subSelector->tagHistory();
    }

    return true;
}