void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest, RuleRange& ruleRange, SelectorChecker::ContextFlags contextFlags, CascadeScope cascadeScope, CascadeOrder cascadeOrder) { ASSERT(matchRequest.ruleSet); ASSERT(m_context.element()); Element& element = *m_context.element(); // Check whether other types of rules are applicable in the current tree scope. Criteria for this: // a) it's a UA rule // b) the tree scope allows author rules // c) the rules comes from a scoped style sheet within the same tree scope // d) the rules comes from a scoped style sheet within an active shadow root whose host is the given element // e) the rules can cross boundaries // b)-e) is checked in rulesApplicableInCurrentTreeScope. if (!m_matchingUARules && !rulesApplicableInCurrentTreeScope(&element, matchRequest.scope, matchRequest.elementApplyAuthorStyles)) return; // We need to collect the rules for id, class, tag, and everything else into a buffer and // then sort the buffer. if (element.hasID()) collectMatchingRulesForList(matchRequest.ruleSet->idRules(element.idForStyleResolution()), contextFlags, cascadeScope, cascadeOrder, matchRequest, ruleRange); if (element.isStyledElement() && element.hasClass()) { for (size_t i = 0; i < element.classNames().size(); ++i) collectMatchingRulesForList(matchRequest.ruleSet->classRules(element.classNames()[i]), contextFlags, cascadeScope, cascadeOrder, matchRequest, ruleRange); } collectMatchingRulesForList(matchRequest.ruleSet->tagRules(element.localName()), contextFlags, cascadeScope, cascadeOrder, matchRequest, ruleRange); collectMatchingRulesForList(matchRequest.ruleSet->universalRules(), contextFlags, cascadeScope, cascadeOrder, matchRequest, ruleRange); }
void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange) { ASSERT(matchRequest.ruleSet); const AtomicString& pseudoId = m_element.shadowPseudoId(); if (!pseudoId.isEmpty()) collectMatchingRulesForList(matchRequest.ruleSet->shadowPseudoElementRules(pseudoId.impl()), matchRequest, ruleRange); #if ENABLE(VIDEO_TRACK) if (m_element.isWebVTTElement()) collectMatchingRulesForList(matchRequest.ruleSet->cuePseudoRules(), matchRequest, ruleRange); #endif // Only match UA rules in shadow tree. if (!MatchingUARulesScope::isMatchingUARules() && m_element.treeScope().rootNode().isShadowRoot()) return; // We need to collect the rules for id, class, tag, and everything else into a buffer and // then sort the buffer. if (m_element.hasID()) collectMatchingRulesForList(matchRequest.ruleSet->idRules(m_element.idForStyleResolution().impl()), matchRequest, ruleRange); if (m_element.hasClass()) { for (size_t i = 0; i < m_element.classNames().size(); ++i) collectMatchingRulesForList(matchRequest.ruleSet->classRules(m_element.classNames()[i].impl()), matchRequest, ruleRange); } if (m_element.isLink()) collectMatchingRulesForList(matchRequest.ruleSet->linkPseudoClassRules(), matchRequest, ruleRange); if (SelectorChecker::matchesFocusPseudoClass(&m_element)) collectMatchingRulesForList(matchRequest.ruleSet->focusPseudoClassRules(), matchRequest, ruleRange); collectMatchingRulesForList(matchRequest.ruleSet->tagRules(m_element.localName().impl()), matchRequest, ruleRange); collectMatchingRulesForList(matchRequest.ruleSet->universalRules(), matchRequest, ruleRange); }
void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange) { ASSERT(matchRequest.ruleSet); ASSERT_WITH_MESSAGE(!(m_mode == SelectorChecker::Mode::CollectingRulesIgnoringVirtualPseudoElements && m_pseudoStyleRequest.pseudoId != NOPSEUDO), "When in StyleInvalidation or SharingRules, SelectorChecker does not try to match the pseudo ID. While ElementRuleCollector supports matching a particular pseudoId in this case, this would indicate a error at the call site since matching a particular element should be unnecessary."); #if ENABLE(VIDEO_TRACK) if (m_element.isWebVTTElement()) collectMatchingRulesForList(matchRequest.ruleSet->cuePseudoRules(), matchRequest, ruleRange); #endif auto* shadowRoot = m_element.containingShadowRoot(); if (shadowRoot && shadowRoot->type() == ShadowRoot::Type::UserAgent) { const AtomicString& pseudoId = m_element.shadowPseudoId(); if (!pseudoId.isEmpty()) collectMatchingRulesForList(matchRequest.ruleSet->shadowPseudoElementRules(pseudoId.impl()), matchRequest, ruleRange); } // We need to collect the rules for id, class, tag, and everything else into a buffer and // then sort the buffer. auto& id = m_element.idForStyleResolution(); if (!id.isNull()) collectMatchingRulesForList(matchRequest.ruleSet->idRules(*id.impl()), matchRequest, ruleRange); if (m_element.hasClass()) { for (size_t i = 0; i < m_element.classNames().size(); ++i) collectMatchingRulesForList(matchRequest.ruleSet->classRules(m_element.classNames()[i].impl()), matchRequest, ruleRange); } if (m_element.isLink()) collectMatchingRulesForList(matchRequest.ruleSet->linkPseudoClassRules(), matchRequest, ruleRange); if (SelectorChecker::matchesFocusPseudoClass(m_element)) collectMatchingRulesForList(matchRequest.ruleSet->focusPseudoClassRules(), matchRequest, ruleRange); collectMatchingRulesForList(matchRequest.ruleSet->tagRules(m_element.localName().impl(), m_element.isHTMLElement() && m_element.document().isHTMLDocument()), matchRequest, ruleRange); collectMatchingRulesForList(matchRequest.ruleSet->universalRules(), matchRequest, ruleRange); }
void ElementRuleCollector::collectMatchingShadowPseudoElementRules(const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange) { ASSERT(matchRequest.ruleSet); ASSERT(m_element.containingShadowRoot()->mode() == ShadowRootMode::UserAgent); auto& rules = *matchRequest.ruleSet; #if ENABLE(VIDEO_TRACK) // FXIME: WebVTT should not be done by styling UA shadow trees like this. if (m_element.isWebVTTElement()) collectMatchingRulesForList(rules.cuePseudoRules(), matchRequest, ruleRange); #endif auto& pseudoId = m_element.shadowPseudoId(); if (!pseudoId.isEmpty()) collectMatchingRulesForList(rules.shadowPseudoElementRules(pseudoId.impl()), matchRequest, ruleRange); }
void ElementRuleCollector::matchSlottedPseudoElementRules(MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange) { auto* maybeSlotted = &m_element; for (auto* hostShadowRoot = m_element.parentNode()->shadowRoot(); hostShadowRoot; hostShadowRoot = maybeSlotted->parentNode()->shadowRoot()) { auto* slot = hostShadowRoot->findAssignedSlot(*maybeSlotted); if (!slot) return; matchRequest.treeContextOrdinal++; // In nested case the slot may itself be assigned to a slot. Collect ::slotted rules from all the nested trees. maybeSlotted = slot; if (!hostShadowRoot->styleScope().resolver().ruleSets().isAuthorStyleDefined()) continue; // Find out if there are any ::slotted rules in the shadow tree matching the current slot. // FIXME: This is really part of the slot style and could be cached when resolving it. ElementRuleCollector collector(*slot, hostShadowRoot->styleScope().resolver().ruleSets().authorStyle(), nullptr); auto slottedPseudoElementRules = collector.collectSlottedPseudoElementRulesForSlot(matchRequest.includeEmptyRules); if (!slottedPseudoElementRules) continue; // Match in the current scope. SetForScope<bool> change(m_isMatchingSlottedPseudoElements, true); MatchRequest scopeMatchRequest(nullptr, matchRequest.includeEmptyRules, matchRequest.treeContextOrdinal); collectMatchingRulesForList(slottedPseudoElementRules.get(), scopeMatchRequest, ruleRange); m_keepAliveSlottedPseudoElementRules.append(WTFMove(slottedPseudoElementRules)); } }
void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest, CascadeOrder cascadeOrder) { ASSERT(matchRequest.ruleSet); ASSERT(m_context.element()); Element& element = *m_context.element(); // We need to collect the rules for id, class, tag, and everything else into a buffer and // then sort the buffer. if (element.hasID()) collectMatchingRulesForList(matchRequest.ruleSet->idRules(element.idForStyleResolution()), cascadeOrder, matchRequest); if (element.isStyledElement() && element.hasClass()) { for (size_t i = 0; i < element.classNames().size(); ++i) collectMatchingRulesForList(matchRequest.ruleSet->classRules(element.classNames()[i]), cascadeOrder, matchRequest); } collectMatchingRulesForList(matchRequest.ruleSet->tagRules(element.localName()), cascadeOrder, matchRequest); collectMatchingRulesForList(matchRequest.ruleSet->universalRules(), cascadeOrder, matchRequest); }
void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange) { ASSERT(matchRequest.ruleSet); ASSERT(m_state.element()); const StyleResolver::State& state = m_state; Element* element = state.element(); const StyledElement* styledElement = state.styledElement(); const AtomicString& pseudoId = element->shadowPseudoId(); if (!pseudoId.isEmpty()) { ASSERT(styledElement); collectMatchingRulesForList(matchRequest.ruleSet->shadowPseudoElementRules(pseudoId.impl()), matchRequest, ruleRange); } #if ENABLE(VIDEO_TRACK) if (element->isWebVTTElement()) collectMatchingRulesForList(matchRequest.ruleSet->cuePseudoRules(), matchRequest, ruleRange); #endif // Check whether other types of rules are applicable in the current tree scope. Criteria for this: // a) it's a UA rule // b) the tree scope allows author rules // c) the rules comes from a scoped style sheet within the same tree scope TreeScope* treeScope = element->treeScope(); if (!MatchingUARulesScope::isMatchingUARules() && !treeScope->applyAuthorStyles() && (!matchRequest.scope || matchRequest.scope->treeScope() != treeScope) && m_behaviorAtBoundary == SelectorChecker::DoesNotCrossBoundary) return; // We need to collect the rules for id, class, tag, and everything else into a buffer and // then sort the buffer. if (element->hasID()) collectMatchingRulesForList(matchRequest.ruleSet->idRules(element->idForStyleResolution().impl()), matchRequest, ruleRange); if (styledElement && styledElement->hasClass()) { for (size_t i = 0; i < styledElement->classNames().size(); ++i) collectMatchingRulesForList(matchRequest.ruleSet->classRules(styledElement->classNames()[i].impl()), matchRequest, ruleRange); } if (element->isLink()) collectMatchingRulesForList(matchRequest.ruleSet->linkPseudoClassRules(), matchRequest, ruleRange); if (SelectorChecker::matchesFocusPseudoClass(element)) collectMatchingRulesForList(matchRequest.ruleSet->focusPseudoClassRules(), matchRequest, ruleRange); collectMatchingRulesForList(matchRequest.ruleSet->tagRules(element->localName().impl()), matchRequest, ruleRange); collectMatchingRulesForList(matchRequest.ruleSet->universalRules(), matchRequest, ruleRange); }
void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest, RuleRange& ruleRange, CascadeScope cascadeScope, CascadeOrder cascadeOrder, bool matchingTreeBoundaryRules) { ASSERT(matchRequest.ruleSet); ASSERT(m_context.element()); Element& element = *m_context.element(); const AtomicString& pseudoId = element.shadowPseudoId(); if (!pseudoId.isEmpty()) { ASSERT(element.isStyledElement()); collectMatchingRulesForList(matchRequest.ruleSet->shadowPseudoElementRules(pseudoId), ignoreCascadeScope, cascadeOrder, matchRequest, ruleRange); } if (element.isVTTElement()) collectMatchingRulesForList(matchRequest.ruleSet->cuePseudoRules(), cascadeScope, cascadeOrder, matchRequest, ruleRange); // Check whether other types of rules are applicable in the current tree scope. Criteria for this: // a) it's a UA rule // b) the rules comes from a scoped style sheet within the same tree scope // c) the rules comes from a scoped style sheet within an active shadow root whose host is the given element // d) the rules can cross boundaries // b)-e) is checked in rulesApplicableInCurrentTreeScope. if (!m_matchingUARules && !rulesApplicableInCurrentTreeScope(&element, matchRequest.scope, matchingTreeBoundaryRules)) return; // We need to collect the rules for id, class, tag, and everything else into a buffer and // then sort the buffer. if (element.hasID()) collectMatchingRulesForList(matchRequest.ruleSet->idRules(element.idForStyleResolution()), cascadeScope, cascadeOrder, matchRequest, ruleRange); if (element.isStyledElement() && element.hasClass()) { for (size_t i = 0; i < element.classNames().size(); ++i) collectMatchingRulesForList(matchRequest.ruleSet->classRules(element.classNames()[i]), cascadeScope, cascadeOrder, matchRequest, ruleRange); } if (element.isLink()) collectMatchingRulesForList(matchRequest.ruleSet->linkPseudoClassRules(), cascadeScope, cascadeOrder, matchRequest, ruleRange); if (SelectorChecker::matchesFocusPseudoClass(element)) collectMatchingRulesForList(matchRequest.ruleSet->focusPseudoClassRules(), cascadeScope, cascadeOrder, matchRequest, ruleRange); collectMatchingRulesForList(matchRequest.ruleSet->tagRules(element.localName()), cascadeScope, cascadeOrder, matchRequest, ruleRange); collectMatchingRulesForList(matchRequest.ruleSet->universalRules(), cascadeScope, cascadeOrder, matchRequest, ruleRange); }
void ElementRuleCollector::matchHostPseudoClassRules(bool includeEmptyRules) { ASSERT(m_element.shadowRoot()); auto& shadowAuthorStyle = *m_element.shadowRoot()->styleResolver().ruleSets().authorStyle(); auto& shadowHostRules = shadowAuthorStyle.hostPseudoClassRules(); if (shadowHostRules.isEmpty()) return; clearMatchedRules(); m_result.ranges.lastAuthorRule = m_result.matchedProperties().size() - 1; auto ruleRange = m_result.ranges.authorRuleRange(); MatchRequest matchRequest(&shadowAuthorStyle, includeEmptyRules); collectMatchingRulesForList(&shadowHostRules, matchRequest, ruleRange); // We just sort the host rules before other author rules. This matches the current vague spec language // but is not necessarily exactly what is needed. // FIXME: Match the spec when it is finalized. sortAndTransferMatchedRules(); }
void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange) { ASSERT(matchRequest.ruleSet); ASSERT_WITH_MESSAGE(!(m_mode == SelectorChecker::Mode::ResolvingStyle && !m_style), "When resolving style, the SelectorChecker must have a style to set the pseudo elements and/or to do marking. The SelectorCompiler also rely on that behavior."); ASSERT_WITH_MESSAGE(!(m_mode == SelectorChecker::Mode::CollectingRulesIgnoringVirtualPseudoElements && m_pseudoStyleRequest.pseudoId != NOPSEUDO), "When in StyleInvalidation or SharingRules, SelectorChecker does not try to match the pseudo ID. While ElementRuleCollector supports matching a particular pseudoId in this case, this would indicate a error at the call site since matching a particular element should be unnecessary."); #if ENABLE(VIDEO_TRACK) if (m_element.isWebVTTElement()) collectMatchingRulesForList(matchRequest.ruleSet->cuePseudoRules(), matchRequest, ruleRange); #endif if (m_element.isInShadowTree()) { const AtomicString& pseudoId = m_element.shadowPseudoId(); if (!pseudoId.isEmpty()) collectMatchingRulesForList(matchRequest.ruleSet->shadowPseudoElementRules(pseudoId.impl()), matchRequest, ruleRange); // Only match UA rules in shadow tree. if (!MatchingUARulesScope::isMatchingUARules()) return; } // We need to collect the rules for id, class, tag, and everything else into a buffer and // then sort the buffer. if (m_element.hasID()) collectMatchingRulesForList(matchRequest.ruleSet->idRules(m_element.idForStyleResolution().impl()), matchRequest, ruleRange); if (m_element.hasClass()) { for (size_t i = 0; i < m_element.classNames().size(); ++i) collectMatchingRulesForList(matchRequest.ruleSet->classRules(m_element.classNames()[i].impl()), matchRequest, ruleRange); } if (m_element.isLink()) collectMatchingRulesForList(matchRequest.ruleSet->linkPseudoClassRules(), matchRequest, ruleRange); if (SelectorChecker::matchesFocusPseudoClass(&m_element)) collectMatchingRulesForList(matchRequest.ruleSet->focusPseudoClassRules(), matchRequest, ruleRange); collectMatchingRulesForList(matchRequest.ruleSet->tagRules(m_element.localName().impl(), m_element.isHTMLElement() && m_element.document().isHTMLDocument()), matchRequest, ruleRange); collectMatchingRulesForList(matchRequest.ruleSet->universalRules(), matchRequest, ruleRange); }
std::unique_ptr<RuleSet::RuleDataVector> ElementRuleCollector::collectSlottedPseudoElementRulesForSlot(bool includeEmptyRules) { ASSERT(is<HTMLSlotElement>(m_element)); clearMatchedRules(); m_mode = SelectorChecker::Mode::CollectingRules; // Match global author rules. MatchRequest matchRequest(&m_authorStyle, includeEmptyRules); StyleResolver::RuleRange ruleRange = m_result.ranges.authorRuleRange(); collectMatchingRulesForList(&m_authorStyle.slottedPseudoElementRules(), matchRequest, ruleRange); if (m_matchedRules.isEmpty()) return { }; auto ruleDataVector = std::make_unique<RuleSet::RuleDataVector>(); ruleDataVector->reserveInitialCapacity(m_matchedRules.size()); for (auto& matchedRule : m_matchedRules) ruleDataVector->uncheckedAppend(*matchedRule.ruleData); return ruleDataVector; }
void ElementRuleCollector::collectMatchingShadowHostRules( const MatchRequest& matchRequest, CascadeOrder cascadeOrder) { collectMatchingRulesForList(matchRequest.ruleSet->shadowHostRules(), cascadeOrder, matchRequest); }
DISABLE_CFI_PERF void ElementRuleCollector::collectMatchingRules( const MatchRequest& matchRequest, CascadeOrder cascadeOrder, bool matchingTreeBoundaryRules) { ASSERT(matchRequest.ruleSet); ASSERT(m_context.element()); Element& element = *m_context.element(); const AtomicString& pseudoId = element.shadowPseudoId(); if (!pseudoId.isEmpty()) { ASSERT(element.isStyledElement()); collectMatchingRulesForList( matchRequest.ruleSet->shadowPseudoElementRules(pseudoId), cascadeOrder, matchRequest); if (pseudoId == "-webkit-input-placeholder") { collectMatchingRulesForList( matchRequest.ruleSet->placeholderPseudoRules(), cascadeOrder, matchRequest); } } if (element.isVTTElement()) collectMatchingRulesForList(matchRequest.ruleSet->cuePseudoRules(), cascadeOrder, matchRequest); // Check whether other types of rules are applicable in the current tree // scope. Criteria for this: // a) the rules are UA rules. // b) matching tree boundary crossing rules. // c) the rules come from a shadow style sheet in the same tree scope as the // given element. // c) is checked in rulesApplicableInCurrentTreeScope. if (!m_matchingUARules && !matchingTreeBoundaryRules && !rulesApplicableInCurrentTreeScope(&element, matchRequest.scope)) return; // We need to collect the rules for id, class, tag, and everything else into a // buffer and then sort the buffer. if (element.hasID()) collectMatchingRulesForList( matchRequest.ruleSet->idRules(element.idForStyleResolution()), cascadeOrder, matchRequest); if (element.isStyledElement() && element.hasClass()) { for (size_t i = 0; i < element.classNames().size(); ++i) collectMatchingRulesForList( matchRequest.ruleSet->classRules(element.classNames()[i]), cascadeOrder, matchRequest); } if (element.isLink()) collectMatchingRulesForList(matchRequest.ruleSet->linkPseudoClassRules(), cascadeOrder, matchRequest); if (SelectorChecker::matchesFocusPseudoClass(element)) collectMatchingRulesForList(matchRequest.ruleSet->focusPseudoClassRules(), cascadeOrder, matchRequest); collectMatchingRulesForList( matchRequest.ruleSet->tagRules(element.localNameForSelectorMatching()), cascadeOrder, matchRequest); collectMatchingRulesForList(matchRequest.ruleSet->universalRules(), cascadeOrder, matchRequest); }