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); }
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(); }
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(); }
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; }
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)); }
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))); }
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)); }
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; }
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))); }
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); } }
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); } }
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(); }
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); } }
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]); }
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); } }