void ScopedStyleResolver::matchAuthorRules(ElementRuleCollector& collector, bool includeEmptyRules, bool applyAuthorStyles) { collector.clearMatchedRules(); collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1; collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, ignoreCascadeScope); collector.sortAndTransferMatchedRules(); }
void ScopedStyleResolver::matchHostRules(ElementRuleCollector& collector, bool includeEmptyRules) { if (m_atHostRules.isEmpty() || !m_scopingNode->isElementNode()) return; ElementShadow* shadow = toElement(m_scopingNode)->shadow(); if (!shadow) return; collector.clearMatchedRules(); collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1; // FIXME(99827): https://bugs.webkit.org/show_bug.cgi?id=99827 // add a new flag to ElementShadow and cache whether any @host @-rules are // applied to the element or not. So we can quickly exit this method // by using the flag. ShadowRoot* shadowRoot = shadow->youngestShadowRoot(); for (; shadowRoot; shadowRoot = shadowRoot->olderShadowRoot()) if (!ScopeContentDistribution::hasShadowElement(shadowRoot)) break; // All shadow roots have <shadow>. if (!shadowRoot) shadowRoot = shadow->oldestShadowRoot(); StyleResolver::RuleRange ruleRange = collector.matchedResult().ranges.authorRuleRange(); collector.setBehaviorAtBoundary(static_cast<SelectorChecker::BehaviorAtBoundary>(SelectorChecker::DoesNotCrossBoundary | SelectorChecker::ScopeContainsLastMatchedElement)); for (; shadowRoot; shadowRoot = shadowRoot->youngerShadowRoot()) { if (RuleSet* ruleSet = atHostRuleSetFor(shadowRoot)) collector.collectMatchingRules(MatchRequest(ruleSet, includeEmptyRules, m_scopingNode), ruleRange); } collector.sortAndTransferMatchedRules(); }
void ScopedStyleResolver::matchAuthorRules(ElementRuleCollector& collector, bool includeEmptyRules, bool applyAuthorStyles) { if (m_authorStyle) { collector.clearMatchedRules(); collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1; // Match author rules. MatchRequest matchRequest(m_authorStyle.get(), includeEmptyRules, m_scopingNode); StyleResolver::RuleRange ruleRange = collector.matchedResult().ranges.authorRuleRange(); collector.setBehaviorAtBoundary(applyAuthorStyles ? SelectorChecker::DoesNotCrossBoundary : static_cast<SelectorChecker::BehaviorAtBoundary>(SelectorChecker::DoesNotCrossBoundary | SelectorChecker::ScopeContainsLastMatchedElement)); collector.collectMatchingRules(matchRequest, ruleRange); collector.collectMatchingRulesForRegion(matchRequest, ruleRange); collector.sortAndTransferMatchedRules(); } }
void TreeBoundaryCrossingRules::collectTreeBoundaryCrossingRules(Element* element, ElementRuleCollector& collector, bool includeEmptyRules) { if (m_treeBoundaryCrossingRuleSetMap.isEmpty()) return; RuleRange ruleRange = collector.matchedResult().ranges.authorRuleRange(); // When comparing rules declared in outer treescopes, outer's rules win. CascadeOrder outerCascadeOrder = size() + size(); // When comparing rules declared in inner treescopes, inner's rules win. CascadeOrder innerCascadeOrder = size(); for (DocumentOrderedList::iterator it = m_scopingNodes.begin(); it != m_scopingNodes.end(); ++it) { const ContainerNode* scopingNode = toContainerNode(*it); CSSStyleSheetRuleSubSet* ruleSubSet = m_treeBoundaryCrossingRuleSetMap.get(scopingNode); bool isInnerTreeScope = element->treeScope().isInclusiveAncestorOf(scopingNode->treeScope()); CascadeOrder cascadeOrder = isInnerTreeScope ? innerCascadeOrder : outerCascadeOrder; for (CSSStyleSheetRuleSubSet::iterator it = ruleSubSet->begin(); it != ruleSubSet->end(); ++it) { CSSStyleSheet* parentStyleSheet = it->first; RuleSet* ruleSet = it->second.get(); collector.collectMatchingRules(MatchRequest(ruleSet, includeEmptyRules, scopingNode, parentStyleSheet), ruleRange, SelectorChecker::ScopeContainsLastMatchedElement, ignoreCascadeScope, cascadeOrder); } ++innerCascadeOrder; --outerCascadeOrder; } }
void ScopedStyleResolver::collectMatchingTreeBoundaryCrossingRules(ElementRuleCollector& collector, bool includeEmptyRules, CascadeOrder cascadeOrder) { RuleRange ruleRange = collector.matchedResult().ranges.authorRuleRange(); for (const auto& rules : *m_treeBoundaryCrossingRuleSet) { MatchRequest request(rules->m_ruleSet.get(), includeEmptyRules, &treeScope().rootNode(), rules->m_parentStyleSheet, rules->m_parentIndex); collector.collectMatchingRules(request, ruleRange, cascadeOrder, true); } }
void ScopedStyleResolver::collectMatchingShadowHostRules(ElementRuleCollector& collector, bool includeEmptyRules, CascadeOrder cascadeOrder) { RuleRange ruleRange = collector.matchedResult().ranges.authorRuleRange(); ASSERT(!collector.scopeContainsLastMatchedElement()); collector.setScopeContainsLastMatchedElement(true); for (size_t i = 0; i < m_authorStyleSheets.size(); ++i) { ASSERT(m_authorStyleSheets[i]->ownerNode()); MatchRequest matchRequest(&m_authorStyleSheets[i]->contents()->ruleSet(), includeEmptyRules, &m_scope->rootNode(), m_authorStyleSheets[i], i); collector.collectMatchingShadowHostRules(matchRequest, ruleRange, cascadeOrder); } collector.setScopeContainsLastMatchedElement(false); }
void ScopedStyleResolver::collectMatchingAuthorRules(ElementRuleCollector& collector, bool includeEmptyRules, bool applyAuthorStyles, CascadeScope cascadeScope, CascadeOrder cascadeOrder) { const ContainerNode* scopingNode = &m_scopingNode; unsigned behaviorAtBoundary = SelectorChecker::DoesNotCrossBoundary; if (!applyAuthorStyles) behaviorAtBoundary |= SelectorChecker::ScopeContainsLastMatchedElement; if (m_scopingNode.isShadowRoot()) { scopingNode = toShadowRoot(m_scopingNode).host(); behaviorAtBoundary |= SelectorChecker::ScopeIsShadowHost; } for (size_t i = 0; i < m_authorStyleSheets.size(); ++i) { MatchRequest matchRequest(&m_authorStyleSheets[i]->contents()->ruleSet(), includeEmptyRules, scopingNode, applyAuthorStyles, i, m_authorStyleSheets[i]); collector.collectMatchingRules(matchRequest, collector.matchedResult().ranges.authorRuleRange(), static_cast<SelectorChecker::BehaviorAtBoundary>(behaviorAtBoundary), cascadeScope, cascadeOrder); } }
void ScopedStyleResolver::collectMatchingAuthorRules(ElementRuleCollector& collector, bool includeEmptyRules, bool applyAuthorStyles, CascadeScope cascadeScope, CascadeOrder cascadeOrder) { if (!m_authorStyle) return; const ContainerNode* scopingNode = &m_scopingNode; unsigned behaviorAtBoundary = SelectorChecker::DoesNotCrossBoundary; if (!applyAuthorStyles) behaviorAtBoundary |= SelectorChecker::ScopeContainsLastMatchedElement; if (m_scopingNode.isShadowRoot()) { scopingNode = toShadowRoot(m_scopingNode).host(); behaviorAtBoundary |= SelectorChecker::ScopeIsShadowHost; } MatchRequest matchRequest(m_authorStyle.get(), includeEmptyRules, scopingNode, applyAuthorStyles); RuleRange ruleRange = collector.matchedResult().ranges.authorRuleRange(); collector.collectMatchingRules(matchRequest, ruleRange, static_cast<SelectorChecker::BehaviorAtBoundary>(behaviorAtBoundary), cascadeScope, cascadeOrder); collector.collectMatchingRulesForRegion(matchRequest, ruleRange, static_cast<SelectorChecker::BehaviorAtBoundary>(behaviorAtBoundary), cascadeScope, cascadeOrder); }
void TreeBoundaryCrossingRules::collectTreeBoundaryCrossingRules(Element* element, ElementRuleCollector& collector, bool includeEmptyRules) { if (m_treeBoundaryCrossingRuleSetMap.isEmpty()) return; RuleRange ruleRange = collector.matchedResult().ranges.authorRuleRange(); // When comparing rules declared in outer treescopes, outer's rules win. CascadeOrder outerCascadeOrder = size() + size(); // When comparing rules declared in inner treescopes, inner's rules win. CascadeOrder innerCascadeOrder = size(); for (DocumentOrderedList::iterator it = m_scopingNodes.begin(); it != m_scopingNodes.end(); ++it) { const ContainerNode* scopingNode = toContainerNode(*it); CSSStyleSheetRuleSubSet* ruleSubSet = m_treeBoundaryCrossingRuleSetMap.get(scopingNode); unsigned boundaryBehavior = SelectorChecker::ScopeContainsLastMatchedElement; bool isInnerTreeScope = element->treeScope().isInclusiveAncestorOf(scopingNode->treeScope()); // If a given scoping node is a shadow root and a given element is in a descendant tree of tree hosted by // the scoping node's shadow host, we should use ScopeIsShadowHost. if (scopingNode && scopingNode->isShadowRoot()) { if (element->isInDescendantTreeOf(toShadowRoot(scopingNode)->host())) boundaryBehavior |= SelectorChecker::ScopeIsShadowHost; scopingNode = toShadowRoot(scopingNode)->host(); } CascadeOrder cascadeOrder = isInnerTreeScope ? innerCascadeOrder : outerCascadeOrder; for (CSSStyleSheetRuleSubSet::iterator it = ruleSubSet->begin(); it != ruleSubSet->end(); ++it) { CSSStyleSheet* parentStyleSheet = it->first; RuleSet* ruleSet = it->second.get(); collector.collectMatchingRules(MatchRequest(ruleSet, includeEmptyRules, scopingNode, parentStyleSheet), ruleRange, static_cast<SelectorChecker::BehaviorAtBoundary>(boundaryBehavior), ignoreCascadeScope, cascadeOrder); } ++innerCascadeOrder; --outerCascadeOrder; } }