Example #1
0
PassRefPtr<StaticNodeList> createSelectorNodeList(Node* rootNode, const CSSSelectorList& querySelectorList)
{
    Vector<RefPtr<Node> > nodes;
    Document* document = rootNode->document();
    CSSSelector* onlySelector = querySelectorList.hasOneSelector() ? querySelectorList.first() : 0;
    bool strictParsing = !document->inQuirksMode();

    CSSStyleSelector::SelectorChecker selectorChecker(document, strictParsing);

    if (strictParsing && rootNode->inDocument() && onlySelector && onlySelector->m_match == CSSSelector::Id && !document->containsMultipleElementsWithId(onlySelector->m_value)) {
        Element* element = document->getElementById(onlySelector->m_value);
        if (element && (rootNode->isDocumentNode() || element->isDescendantOf(rootNode)) && selectorChecker.checkSelector(onlySelector, element))
            nodes.append(element);
    } else {
        for (Node* n = rootNode->firstChild(); n; n = n->traverseNextNode(rootNode)) {
            if (n->isElementNode()) {
                Element* element = static_cast<Element*>(n);
                for (CSSSelector* selector = querySelectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
                    if (selectorChecker.checkSelector(selector, element)) {
                        nodes.append(n);
                        break;
                    }
                }
            }
        }
    }
    
    return StaticNodeList::adopt(nodes);
}
Example #2
0
SelectorQuery* SelectorQueryCache::add(const AtomicString& selectors, const Document& document, ExceptionState& exceptionState)
{
    HashMap<AtomicString, OwnPtr<SelectorQuery>>::iterator it = m_entries.find(selectors);
    if (it != m_entries.end())
        return it->value.get();

    CSSSelectorList selectorList;
    CSSParser::parseSelector(CSSParserContext(document, nullptr), selectors, selectorList);

    if (!selectorList.first()) {
        exceptionState.throwDOMException(SyntaxError, "'" + selectors + "' is not a valid selector.");
        return nullptr;
    }

    // throw a NamespaceError if the selector includes any namespace prefixes.
    if (selectorList.selectorsNeedNamespaceResolution()) {
        exceptionState.throwDOMException(NamespaceError, "'" + selectors + "' contains namespaces, which are not supported.");
        return nullptr;
    }

    const unsigned maximumSelectorQueryCacheSize = 256;
    if (m_entries.size() == maximumSelectorQueryCacheSize)
        m_entries.remove(m_entries.begin());

    return m_entries.add(selectors, SelectorQuery::adopt(selectorList)).storedValue->value.get();
}
Example #3
0
SelectorQuery* SelectorQueryCache::add(const String& selectors, Document& document, ExceptionCode& ec)
{
    auto it = m_entries.find(selectors);
    if (it != m_entries.end())
        return it->value.get();

    CSSParser parser(document);
    parser.setArena(m_arena.get());
    CSSSelectorList selectorList;
    parser.parseSelector(selectors, selectorList);

    if (!selectorList.first() || selectorList.hasInvalidSelector()) {
        ec = SYNTAX_ERR;
        return nullptr;
    }

    // Throw a NAMESPACE_ERR if the selector includes any namespace prefixes.
    if (selectorList.selectorsNeedNamespaceResolution()) {
        ec = NAMESPACE_ERR;
        return nullptr;
    }

    const int maximumSelectorQueryCacheSize = 256;
    if (m_entries.size() == maximumSelectorQueryCacheSize)
        m_entries.remove(m_entries.begin());

    return m_entries.add(selectors, std::make_unique<SelectorQuery>(WTFMove(selectorList))).iterator->value.get();
}
Example #4
0
SelectorQuery* SelectorQueryCache::add(const AtomicString& selectors, Document* document, ExceptionCode& ec)
{
    HashMap<AtomicString, OwnPtr<SelectorQuery> >::iterator it = m_entries.find(selectors);
    if (it != m_entries.end())
        return it->value.get();

    CSSParser parser(document);
    CSSSelectorList selectorList;
    parser.parseSelector(selectors, selectorList);

    if (!selectorList.first() || selectorList.hasInvalidSelector()) {
        ec = SYNTAX_ERR;
        return 0;
    }

    // throw a NAMESPACE_ERR if the selector includes any namespace prefixes.
    if (selectorList.selectorsNeedNamespaceResolution()) {
        ec = NAMESPACE_ERR;
        return 0;
    }

    const int maximumSelectorQueryCacheSize = 256;
    if (m_entries.size() == maximumSelectorQueryCacheSize)
        m_entries.remove(m_entries.begin());
    
    OwnPtr<SelectorQuery> selectorQuery = adoptPtr(new SelectorQuery(selectorList));
    SelectorQuery* rawSelectorQuery = selectorQuery.get();
    m_entries.add(selectors, selectorQuery.release());
    return rawSelectorQuery;
}
SelectorQuery* SelectorQueryCache::add(const AtomicString& selectors, const Document& document, ExceptionState& es)
{
    HashMap<AtomicString, OwnPtr<SelectorQuery> >::iterator it = m_entries.find(selectors);
    if (it != m_entries.end())
        return it->value.get();

    CSSParser parser(document);
    CSSSelectorList selectorList;
    parser.parseSelector(selectors, selectorList);

    if (!selectorList.first()) {
        es.throwDOMException(SyntaxError, "Failed to execute query: '" + selectors + "' is not a valid selector.");
        return 0;
    }

    // throw a NamespaceError if the selector includes any namespace prefixes.
    if (selectorList.selectorsNeedNamespaceResolution()) {
        es.throwDOMException(NamespaceError, "Failed to execute query: '" + selectors + "' contains namespaces, which are not supported.");
        return 0;
    }

    const int maximumSelectorQueryCacheSize = 256;
    if (m_entries.size() == maximumSelectorQueryCacheSize)
        m_entries.remove(m_entries.begin());

    OwnPtr<SelectorQuery> selectorQuery = adoptPtr(new SelectorQuery(selectorList));
    SelectorQuery* rawSelectorQuery = selectorQuery.get();
    m_entries.add(selectors, selectorQuery.release());
    return rawSelectorQuery;
}
Example #6
0
static bool allCompound(const CSSSelectorList& selectorList)
{
    for (const CSSSelector* selector = selectorList.first(); selector; selector = selectorList.next(selector)) {
        if (!selector->isCompound())
            return false;
    }
    return true;
}
static bool isValidSelector(const String& selector)
{
    CSSParserContext context(HTMLQuirksMode);
    CSSParser parser(context);
    CSSSelectorList selectorList;
    parser.parseSelector(selector, selectorList);
    return selectorList.isValid();
}
void CSSPageRule::setSelectorText(const String& selectorText)
{
    CSSParserContext context(parserContext(), nullptr);
    CSSSelectorList selectorList = CSSParser::parsePageSelector(context, parentStyleSheet() ? parentStyleSheet()->contents() : nullptr, selectorText);
    if (!selectorList.isValid())
        return;

    CSSStyleSheet::RuleMutationScope mutationScope(this);

    m_pageRule->wrapperAdoptSelectorList(std::move(selectorList));
}
Example #9
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;
}
WebString canonicalizeSelector(WebString webSelector, WebSelectorType restriction)
{
    CSSSelectorList selectorList = CSSParser::parseSelector(strictCSSParserContext(), nullptr, webSelector);

    if (restriction == WebSelectorTypeCompound) {
        for (const CSSSelector* selector = selectorList.first(); selector; selector = selectorList.next(*selector)) {
            if (!selector->isCompound())
                return WebString();
        }
    }
    return selectorList.selectorsText();
}
void SelectorDataList::initialize(const CSSSelectorList& selectorList)
{
    ASSERT(m_selectors.isEmpty());

    unsigned selectorCount = 0;
    for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector))
        selectorCount++;

    m_selectors.reserveInitialCapacity(selectorCount);
    for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector))
        m_selectors.uncheckedAppend(SelectorData(*selector, SelectorCheckerFastPath::canUse(*selector)));
}
Example #12
0
void CSSSelectorParser::parseSelector(CSSParserTokenRange range, const CSSParserContext& context, const AtomicString& defaultNamespace, StyleSheetContents* styleSheet, CSSSelectorList& output)
{
    CSSSelectorParser parser(context, defaultNamespace, styleSheet);
    range.consumeWhitespace();
    CSSSelectorList result;
    parser.consumeComplexSelectorList(range, result);
    if (range.atEnd()) {
        output.adopt(result);
        recordSelectorStats(context, output);
    }
    ASSERT(!(output.isValid() && parser.m_failedParsing));
}
Example #13
0
void CSSPageRule::setSelectorText(const String& selectorText)
{
    CSSParser parser(parserContext());
    CSSSelectorList selectorList;
    parser.parseSelector(selectorText, selectorList);
    if (!selectorList.first())
        return;

    CSSStyleSheet::RuleMutationScope mutationScope(this);

    String oldSelectorText = this->selectorText();
    m_pageRule->wrapperAdoptSelectorList(selectorList);
}
PassRefPtrWillBeRawPtr<StyleRulePage> CSSParserImpl::consumePageRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
{
    // We only support a small subset of the css-page spec.
    prelude.consumeWhitespace();
    AtomicString typeSelector;
    if (prelude.peek().type() == IdentToken)
        typeSelector = prelude.consume().value();

    AtomicString pseudo;
    if (prelude.peek().type() == ColonToken) {
        prelude.consume();
        if (prelude.peek().type() != IdentToken)
            return nullptr; // Parse error; expected ident token following colon in @page header
        pseudo = prelude.consume().value();
    }

    prelude.consumeWhitespace();
    if (!prelude.atEnd())
        return nullptr; // Parse error; extra tokens in @page header

    OwnPtr<CSSParserSelector> selector;
    if (!typeSelector.isNull() && pseudo.isNull()) {
        selector = CSSParserSelector::create(QualifiedName(nullAtom, typeSelector, m_styleSheet->defaultNamespace()));
    } else {
        selector = CSSParserSelector::create();
        if (!pseudo.isNull()) {
            selector->setMatch(CSSSelector::PagePseudoClass);
            selector->updatePseudoType(pseudo.lower());
            if (selector->pseudoType() == CSSSelector::PseudoUnknown)
                return nullptr; // Parse error; unknown page pseudo-class
        }
        if (!typeSelector.isNull())
            selector->prependTagSelector(QualifiedName(nullAtom, typeSelector, m_styleSheet->defaultNamespace()));
    }

    if (m_observerWrapper) {
        unsigned endOffset = m_observerWrapper->endOffset(prelude);
        m_observerWrapper->observer().startRuleHeader(StyleRule::Page, m_observerWrapper->startOffset(prelude));
        m_observerWrapper->observer().endRuleHeader(endOffset);
    }

    selector->setForPage();
    Vector<OwnPtr<CSSParserSelector>> selectorVector;
    selectorVector.append(selector.release());
    CSSSelectorList selectorList;
    selectorList.adoptSelectorVector(selectorVector);

    consumeDeclarationList(block, StyleRule::Style);

    return StyleRulePage::create(selectorList, createStylePropertySet(m_parsedProperties, m_context.mode()));
}
PassRefPtrWillBeRawPtr<StyleRule> CSSParserImpl::consumeStyleRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
{
    CSSSelectorList selectorList;
    CSSSelectorParser::parseSelector(prelude, m_context, m_styleSheet, selectorList);
    if (!selectorList.isValid())
        return nullptr; // Parse error, invalid selector list

    if (m_observerWrapper)
        observeSelectors(*m_observerWrapper, prelude);

    consumeDeclarationList(block, StyleRule::Style);

    return StyleRule::create(selectorList, createStylePropertySet(m_parsedProperties, m_context.mode()));
}
static bool determineSelectorScopes(const CSSSelectorList& selectorList, HashSet<StringImpl*>& idScopes, HashSet<StringImpl*>& classScopes)
{
    for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector)) {
        const CSSSelector* scopeSelector = 0;
        // This picks the widest scope, not the narrowest, to minimize the number of found scopes.
        for (const CSSSelector* current = selector; current; current = current->tagHistory()) {
            // Prefer ids over classes.
            if (current->match() == CSSSelector::Id)
                scopeSelector = current;
            else if (current->match() == CSSSelector::Class && (!scopeSelector || scopeSelector->match() != CSSSelector::Id))
                scopeSelector = current;
            CSSSelector::RelationType relation = current->relation();
            // FIXME: it would be better to use setNeedsStyleRecalc for all shadow hosts matching
            // scopeSelector. Currently requests full style recalc.
            if (relation == CSSSelector::ShadowDeep || relation == CSSSelector::ShadowPseudo)
                return false;
            if (relation != CSSSelector::Descendant && relation != CSSSelector::Child && relation != CSSSelector::SubSelector)
                break;
        }
        if (!scopeSelector)
            return false;
        ASSERT(scopeSelector->match() == CSSSelector::Class || scopeSelector->match() == CSSSelector::Id);
        if (scopeSelector->match() == CSSSelector::Id)
            idScopes.add(scopeSelector->value().impl());
        else
            classScopes.add(scopeSelector->value().impl());
    }
    return true;
}
Example #17
0
static unsigned maxSpecificity(const CSSSelectorList& selectorList)
{
    unsigned maxSpecificity = 0;
    for (const CSSSelector* subSelector = selectorList.first(); subSelector; subSelector = CSSSelectorList::next(subSelector))
        maxSpecificity = std::max(maxSpecificity, selectorSpecificity(*subSelector, true));
    return maxSpecificity;
}
void SelectorDataList::initialize(const CSSSelectorList& selectorList)
{
    ASSERT(m_selectors.isEmpty());

    for (CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector))
        m_selectors.append(SelectorData(selector, SelectorChecker::isFastCheckableSelector(selector)));
}
Example #19
0
bool CSSLazyParsingState::shouldLazilyParseProperties(
    const CSSSelectorList& selectors,
    const CSSParserTokenRange& block) const {
  // Simple heuristic for an empty block. Note that |block| here does not
  // include {} brackets. We avoid lazy parsing empty blocks so we can avoid
  // considering them when possible for matching. Lazy blocks must always be
  // considered. Three tokens is a reasonable minimum for a block:
  // ident ':' <value>.
  if (block.end() - block.begin() <= 2)
    return false;

  //  Disallow lazy parsing for blocks which have before/after in their selector
  //  list. This ensures we don't cause a collectFeatures() when we trigger
  //  parsing for attr() functions which would trigger expensive invalidation
  //  propagation.
  for (const auto* s = selectors.first(); s; s = CSSSelectorList::next(*s)) {
    for (const CSSSelector* current = s; current;
         current = current->tagHistory()) {
      const CSSSelector::PseudoType type(current->getPseudoType());
      if (type == CSSSelector::PseudoBefore || type == CSSSelector::PseudoAfter)
        return false;
      if (current->relation() != CSSSelector::SubSelector)
        break;
    }
  }
  return true;
}
static bool determineSelectorScopes(const CSSSelectorList& selectorList, HashSet<AtomicStringImpl*>& idScopes, HashSet<AtomicStringImpl*>& classScopes)
{
    for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
        const CSSSelector* scopeSelector = 0;
        // This picks the widest scope, not the narrowest, to minimize the number of found scopes.
        for (const 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;
}
CSSSelectorList::CSSSelectorList(const CSSSelectorList& other)
{
    unsigned otherLength = other.length();
    m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * otherLength));
    for (unsigned i = 0; i < otherLength; ++i)
        new (&m_selectorArray[i]) CSSSelector(other.m_selectorArray[i]);
}
void CSSStyleRule::setSelectorText(const String& selectorText)
{
    CSSParserContext context(parserContext(), 0);
    CSSSelectorList selectorList = CSSParser::parseSelector(context, parentStyleSheet() ? parentStyleSheet()->contents() : nullptr, selectorText);
    if (!selectorList.isValid())
        return;

    CSSStyleSheet::RuleMutationScope mutationScope(this);

    m_styleRule->wrapperAdoptSelectorList(std::move(selectorList));

    if (hasCachedSelectorText()) {
        selectorTextCache().remove(this);
        setHasCachedSelectorText(false);
    }
}
Example #23
0
void SelectorDataList::initialize(const CSSSelectorList& selectorList)
{
    ASSERT(m_selectors.isEmpty());

    unsigned selectorCount = 0;
    for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector))
        selectorCount++;

    m_crossesTreeBoundary = false;
    m_selectors.reserveInitialCapacity(selectorCount);
    unsigned index = 0;
    for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector), ++index) {
        m_selectors.uncheckedAppend(selector);
        m_crossesTreeBoundary |= selectorList.selectorCrossesTreeScopes(index);
    }
}
void CSSStyleRule::setSelectorText(const String& selectorText)
{
    CSSParser p(parserContext());
    CSSSelectorList selectorList;
    p.parseSelector(selectorText, selectorList);
    if (!selectorList.isValid())
        return;

    CSSStyleSheet::RuleMutationScope mutationScope(this);

    m_styleRule->wrapperAdoptSelectorList(selectorList);

    if (hasCachedSelectorText()) {
        selectorTextCache().remove(this);
        setHasCachedSelectorText(false);
    }
}
Example #25
0
CSSSelectorList::CSSSelectorList(const CSSSelectorList& other)
{
    unsigned otherComponentCount = other.componentCount();
    ASSERT_WITH_SECURITY_IMPLICATION(otherComponentCount);

    m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * otherComponentCount));
    for (unsigned i = 0; i < otherComponentCount; ++i)
        new (NotNull, &m_selectorArray[i]) CSSSelector(other.m_selectorArray[i]);
}
SelectorQuery* SelectorQueryCache::add(const AtomicString& selectors, const Document& document, ExceptionState& exceptionState)
{
    HashMap<AtomicString, OwnPtr<SelectorQuery>>::iterator it = m_entries.find(selectors);
    if (it != m_entries.end())
        return it->value.get();

    CSSSelectorList selectorList = CSSParser::parseSelector(CSSParserContext(document, nullptr), nullptr, selectors);

    if (!selectorList.first()) {
        exceptionState.throwDOMException(SyntaxError, "'" + selectors + "' is not a valid selector.");
        return nullptr;
    }

    const unsigned maximumSelectorQueryCacheSize = 256;
    if (m_entries.size() == maximumSelectorQueryCacheSize)
        m_entries.remove(m_entries.begin());

    return m_entries.add(selectors, SelectorQuery::adopt(std::move(selectorList))).storedValue->value.get();
}
Example #27
0
SelectorDataList::SelectorDataList(const CSSSelectorList& selectorList)
{
    unsigned selectorCount = 0;
    for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector))
        selectorCount++;

    m_selectors.reserveInitialCapacity(selectorCount);
    for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector))
        m_selectors.uncheckedAppend(SelectorData(selector, SelectorCheckerFastPath::canUse(selector)));

    if (selectorCount == 1) {
        const CSSSelector& selector = *m_selectors.first().selector;
        if (selector.isLastInTagHistory()) {
            switch (selector.m_match) {
            case CSSSelector::Tag:
                m_matchType = TagNameMatch;
                break;
            case CSSSelector::Class:
                m_matchType = ClassNameMatch;
                break;
            case CSSSelector::Id:
                m_matchType = RightMostWithIdMatch;
                break;
            default:
                m_matchType = CompilableSingle;
                break;
            }
        } else {
            switch (findIdMatchingType(selector)) {
            case IdMatchingType::None:
                m_matchType = CompilableSingle;
                break;
            case IdMatchingType::Rightmost:
                m_matchType = RightMostWithIdMatch;
                break;
            case IdMatchingType::Filter:
                m_matchType = CompilableSingleWithRootFilter;
                break;
            }
        }
    } else
        m_matchType = MultipleSelectorMatch;
}
void SelectorDataList::initialize(const CSSSelectorList& selectorList)
{
    ASSERT(m_selectors.isEmpty());

    unsigned selectorCount = 0;
    for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector))
        selectorCount++;

    m_usesDeepCombinatorOrShadowPseudo = false;
    m_needsUpdatedDistribution = false;
    m_selectors.reserveInitialCapacity(selectorCount);
    unsigned index = 0;
    for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector), ++index) {
        if (selector->matchesPseudoElement())
            continue;
        m_selectors.uncheckedAppend(selector);
        m_usesDeepCombinatorOrShadowPseudo |= selectorList.selectorUsesDeepCombinatorOrShadowPseudo(index);
        m_needsUpdatedDistribution |= selectorList.selectorNeedsUpdatedDistribution(index);
    }
}
Example #29
0
CSSSelectorList::CSSSelectorList(const CSSSelectorList& o)
{
    unsigned length = o.length();
    if (length == 1) {
        // Destructor expects a single selector to be allocated by new, multiple with fastMalloc.
        m_selectorArray = new CSSSelector(o.m_selectorArray[0]);
        return;
    }
    m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * length));
    for (unsigned i = 0; i < length; ++i)
        new (&m_selectorArray[i]) CSSSelector(o.m_selectorArray[i]);
}
Example #30
0
void CSSStyleRule::setSelectorText(const String& selectorText)
{
    CSSParser p(parserContext());
    CSSSelectorList selectorList;
    p.parseSelector(selectorText, selectorList);
    if (!selectorList.isValid())
        return;

    // NOTE: The selector list has to fit into RuleData. <http://webkit.org/b/118369>
    if (selectorList.componentCount() > RuleData::maximumSelectorComponentCount)
        return;

    CSSStyleSheet::RuleMutationScope mutationScope(this);

    m_styleRule->wrapperAdoptSelectorList(selectorList);

    if (hasCachedSelectorText()) {
        selectorTextCache().remove(this);
        setHasCachedSelectorText(false);
    }
}