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->inCompatMode();

    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);
}
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 #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);
    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>(std::move(selectorList))).iterator->value.get();
}
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)));
}
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 #6
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);
    }
}
Example #7
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;
}
Example #8
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;
}
void CSSStyleRule::setSelectorText(const String& selectorText)
{
    Document* doc = 0;
    StyleSheet* ownerStyleSheet = m_style->stylesheet();
    if (ownerStyleSheet) {
        if (ownerStyleSheet->isCSSStyleSheet())
            doc = static_cast<CSSStyleSheet*>(ownerStyleSheet)->document();
        if (!doc)
            doc = ownerStyleSheet->ownerNode() ? ownerStyleSheet->ownerNode()->document() : 0;
    }
    if (!doc)
        doc = m_style->node() ? m_style->node()->document() : 0;

    if (!doc)
        return;

    CSSParser p;
    CSSSelectorList selectorList;
    p.parseSelector(selectorText, doc, selectorList);
    if (!selectorList.first())
        return;

    String oldSelectorText = this->selectorText();
    m_selectorList.adopt(selectorList);
    if (this->selectorText() == oldSelectorText)
        return;

    doc->styleSelectorChanged(DeferRecalcStyle);
}
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;
}
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();

    BisonCSSParser parser(CSSParserContext(document, 0));
    CSSSelectorList selectorList;
    parser.parseSelector(selectors, selectorList);

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

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

    const unsigned 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 #12
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;
}
Example #13
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;
}
Example #14
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 #16
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();
}
Example #18
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);
}
Example #19
0
void SelectRuleFeatureSet::collectFeaturesFromSelectorList(
    const CSSSelectorList& list) {
  for (const CSSSelector* selector = list.first(); selector;
       selector = CSSSelectorList::next(*selector)) {
    for (const CSSSelector* component = selector; component;
         component = component->tagHistory()) {
      if (invalidationSetForSimpleSelector(*component, InvalidateDescendants))
        continue;

      if (component->selectorList())
        collectFeaturesFromSelectorList(*component->selectorList());
    }
  }
}
Example #20
0
void CSSStyleRule::setSelectorText(const String& selectorText)
{
    CSSParser p(parserContext());
    CSSSelectorList selectorList;
    p.parseSelector(selectorText, selectorList);
    if (!selectorList.first())
        return;

    CSSStyleSheet::RuleMutationScope mutationScope(this);

    m_styleRule->wrapperAdoptSelectorList(selectorList);

    if (hasCachedSelectorText()) {
        selectorTextCache().remove(this);
        setHasCachedSelectorText(false);
    }
}
Example #21
0
static void recordSelectorStats(const CSSParserContext& context, const CSSSelectorList& selectorList)
{
    if (!context.useCounter())
        return;

    for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector)) {
        for (const CSSSelector* current = selector; current ; current = current->tagHistory()) {
            UseCounter::Feature feature = UseCounter::NumberOfFeatures;
            switch (current->pseudoType()) {
            case CSSSelector::PseudoUnresolved:
                feature = UseCounter::CSSSelectorPseudoUnresolved;
                break;
            case CSSSelector::PseudoShadow:
                feature = UseCounter::CSSSelectorPseudoShadow;
                break;
            case CSSSelector::PseudoContent:
                feature = UseCounter::CSSSelectorPseudoContent;
                break;
            case CSSSelector::PseudoHost:
                feature = UseCounter::CSSSelectorPseudoHost;
                break;
            case CSSSelector::PseudoHostContext:
                feature = UseCounter::CSSSelectorPseudoHostContext;
                break;
            case CSSSelector::PseudoFullScreenDocument:
                feature = UseCounter::CSSSelectorPseudoFullScreenDocument;
                break;
            case CSSSelector::PseudoFullScreenAncestor:
                feature = UseCounter::CSSSelectorPseudoFullScreenAncestor;
                break;
            case CSSSelector::PseudoFullScreen:
                feature = UseCounter::CSSSelectorPseudoFullScreen;
                break;
            default:
                break;
            }
            if (feature != UseCounter::NumberOfFeatures)
                context.useCounter()->count(feature);
            if (current->relation() == CSSSelector::ShadowDeep)
                context.useCounter()->count(UseCounter::CSSDeepCombinator);
            if (current->selectorList())
                recordSelectorStats(context, *current->selectorList());
        }
    }
}
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 #23
0
void CSSPageRule::setSelectorText(const String& selectorText)
{
    Document* doc = 0;
    if (CSSStyleSheet* styleSheet = parentStyleSheet())
        doc = styleSheet->findDocument();
    if (!doc)
        return;
    
    CSSParser p;
    CSSSelectorList selectorList;
    p.parseSelector(selectorText, doc, selectorList);
    if (!selectorList.first())
        return;
    
    String oldSelectorText = this->selectorText();
    m_selectorList.adopt(selectorList);
    
    if (this->selectorText() == oldSelectorText)
        return;
    doc->styleSelectorChanged(DeferRecalcStyle);
}
Example #24
0
static void recordSelectorStats(const CSSParserContext& context,
                                const CSSSelectorList& selectorList) {
  if (!context.useCounter())
    return;

  for (const CSSSelector* selector = selectorList.first(); selector;
       selector = CSSSelectorList::next(*selector)) {
    for (const CSSSelector* current = selector; current;
         current = current->tagHistory()) {
      UseCounter::Feature feature = UseCounter::NumberOfFeatures;
      switch (current->getPseudoType()) {
        case CSSSelector::PseudoAny:
          feature = UseCounter::CSSSelectorPseudoAny;
          break;
        case CSSSelector::PseudoUnresolved:
          feature = UseCounter::CSSSelectorPseudoUnresolved;
          break;
        case CSSSelector::PseudoDefined:
          feature = UseCounter::CSSSelectorPseudoDefined;
          break;
        case CSSSelector::PseudoSlotted:
          feature = UseCounter::CSSSelectorPseudoSlotted;
          break;
        case CSSSelector::PseudoContent:
          feature = UseCounter::CSSSelectorPseudoContent;
          break;
        case CSSSelector::PseudoHost:
          feature = UseCounter::CSSSelectorPseudoHost;
          break;
        case CSSSelector::PseudoHostContext:
          feature = UseCounter::CSSSelectorPseudoHostContext;
          break;
        case CSSSelector::PseudoFullScreenAncestor:
          feature = UseCounter::CSSSelectorPseudoFullScreenAncestor;
          break;
        case CSSSelector::PseudoFullScreen:
          feature = UseCounter::CSSSelectorPseudoFullScreen;
          break;
        case CSSSelector::PseudoListBox:
          if (context.mode() != UASheetMode)
            feature = UseCounter::CSSSelectorInternalPseudoListBox;
          break;
        case CSSSelector::PseudoWebKitCustomElement:
          if (context.mode() != UASheetMode) {
            if (current->value() == "-internal-media-controls-cast-button")
              feature = UseCounter::CSSSelectorInternalMediaControlsCastButton;
            else if (current->value() ==
                     "-internal-media-controls-overlay-cast-button")
              feature =
                  UseCounter::CSSSelectorInternalMediaControlsOverlayCastButton;
          }
          break;
        case CSSSelector::PseudoSpatialNavigationFocus:
          if (context.mode() != UASheetMode)
            feature =
                UseCounter::CSSSelectorInternalPseudoSpatialNavigationFocus;
          break;
        case CSSSelector::PseudoReadOnly:
          if (context.mode() != UASheetMode)
            feature = UseCounter::CSSSelectorPseudoReadOnly;
          break;
        case CSSSelector::PseudoReadWrite:
          if (context.mode() != UASheetMode)
            feature = UseCounter::CSSSelectorPseudoReadWrite;
          break;
        default:
          break;
      }
      if (feature != UseCounter::NumberOfFeatures)
        context.useCounter()->count(feature);
      if (current->relation() == CSSSelector::IndirectAdjacent)
        context.useCounter()->count(UseCounter::CSSSelectorIndirectAdjacent);
      if (current->selectorList())
        recordSelectorStats(context, *current->selectorList());
    }
  }
}