Commit 978d025b authored by kochi@chromium.org's avatar kochi@chromium.org

Refactor SelectorChecker::BehaviorAtBoundary

As of Blink r176304, SelectorCheckingContext::scope
for styles in shadow tree changed from its shadow host to
shadow root.

Thus the subtlety of scoping difference between TreeScope
and SelectorCheckingContext::scope is gone, and code for
handling the difference can be cleaned up.

This made possible by dropping support for <style scoped>,
which introduced the complexity at r175993.

With this change no functional difference is expected,
thus all layout tests should pass.

- Convert SelectorChecker::parentElement(context) to static helper function.
- Convert SelectorChecker::scopeContainsLastMatchedElement() to static
  helper function.
- s/{b,B}ehaviorAtBounary/{c,C}ontextFlags/g
- Removed the 2nd parameter in rulesApplicableInCurrentTreeScope()
- Removed the 2nd argument for isHostInItsShadowTree()
- Removed StaysWithinTreeScope
- Removed DoesNotCrossBoundary
- Removed ScopeIsShadowRoot.
- Removed BoundaryBehaviorMask
- Removed ScopeIsShadowHostInPseudoHostParameter
- Introduced DefaultBehavior (to be removed, though)

BUG=none
TEST=pass all layout tests.

Review URL: https://codereview.chromium.org/334263020

git-svn-id: svn://svn.chromium.org/blink/trunk@177183 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 85c33640
......@@ -118,7 +118,7 @@ void ElementRuleCollector::addElementStyleProperties(const StylePropertySet* pro
m_result.isCacheable = false;
}
static bool rulesApplicableInCurrentTreeScope(const Element* element, const ContainerNode* scopingNode, SelectorChecker::BehaviorAtBoundary behaviorAtBoundary, bool elementApplyAuthorStyles)
static bool rulesApplicableInCurrentTreeScope(const Element* element, const ContainerNode* scopingNode, bool elementApplyAuthorStyles)
{
TreeScope& treeScope = element->treeScope();
......@@ -130,12 +130,12 @@ static bool rulesApplicableInCurrentTreeScope(const Element* element, const Cont
if (!scopingNode || treeScope == scopingNode->treeScope())
return true;
// d) the rules comes from a scoped style sheet within an active shadow root whose host is the given element
if (SelectorChecker::isHostInItsShadowTree(*element, behaviorAtBoundary, scopingNode))
if (SelectorChecker::isHostInItsShadowTree(*element, scopingNode))
return true;
return false;
}
void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest, RuleRange& ruleRange, SelectorChecker::BehaviorAtBoundary behaviorAtBoundary, CascadeScope cascadeScope, CascadeOrder cascadeOrder)
void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest, RuleRange& ruleRange, SelectorChecker::ContextFlags contextFlags, CascadeScope cascadeScope, CascadeOrder cascadeOrder)
{
ASSERT(matchRequest.ruleSet);
ASSERT(m_context.element());
......@@ -144,11 +144,11 @@ void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest
const AtomicString& pseudoId = element.shadowPseudoId();
if (!pseudoId.isEmpty()) {
ASSERT(element.isStyledElement());
collectMatchingRulesForList(matchRequest.ruleSet->shadowPseudoElementRules(pseudoId), behaviorAtBoundary, ignoreCascadeScope, cascadeOrder, matchRequest, ruleRange);
collectMatchingRulesForList(matchRequest.ruleSet->shadowPseudoElementRules(pseudoId), contextFlags, ignoreCascadeScope, cascadeOrder, matchRequest, ruleRange);
}
if (element.isVTTElement())
collectMatchingRulesForList(matchRequest.ruleSet->cuePseudoRules(), behaviorAtBoundary, cascadeScope, cascadeOrder, matchRequest, ruleRange);
collectMatchingRulesForList(matchRequest.ruleSet->cuePseudoRules(), contextFlags, 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 tree scope allows author rules
......@@ -156,24 +156,24 @@ void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest
// 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, behaviorAtBoundary, matchRequest.elementApplyAuthorStyles))
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()), behaviorAtBoundary, cascadeScope, cascadeOrder, matchRequest, ruleRange);
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]), behaviorAtBoundary, cascadeScope, cascadeOrder, matchRequest, ruleRange);
collectMatchingRulesForList(matchRequest.ruleSet->classRules(element.classNames()[i]), contextFlags, cascadeScope, cascadeOrder, matchRequest, ruleRange);
}
if (element.isLink())
collectMatchingRulesForList(matchRequest.ruleSet->linkPseudoClassRules(), behaviorAtBoundary, cascadeScope, cascadeOrder, matchRequest, ruleRange);
collectMatchingRulesForList(matchRequest.ruleSet->linkPseudoClassRules(), contextFlags, cascadeScope, cascadeOrder, matchRequest, ruleRange);
if (SelectorChecker::matchesFocusPseudoClass(element))
collectMatchingRulesForList(matchRequest.ruleSet->focusPseudoClassRules(), behaviorAtBoundary, cascadeScope, cascadeOrder, matchRequest, ruleRange);
collectMatchingRulesForList(matchRequest.ruleSet->tagRules(element.localName()), behaviorAtBoundary, cascadeScope, cascadeOrder, matchRequest, ruleRange);
collectMatchingRulesForList(matchRequest.ruleSet->universalRules(), behaviorAtBoundary, cascadeScope, cascadeOrder, matchRequest, ruleRange);
collectMatchingRulesForList(matchRequest.ruleSet->focusPseudoClassRules(), 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);
}
CSSRuleList* ElementRuleCollector::nestedRuleList(CSSRule* rule)
......@@ -257,7 +257,7 @@ void ElementRuleCollector::sortAndTransferMatchedRules()
}
}
inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, const ContainerNode* scope, SelectorChecker::BehaviorAtBoundary behaviorAtBoundary, SelectorChecker::MatchResult* result)
inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, const ContainerNode* scope, SelectorChecker::ContextFlags contextFlags, SelectorChecker::MatchResult* result)
{
SelectorChecker selectorChecker(m_context.element()->document(), m_mode);
SelectorChecker::SelectorCheckingContext context(ruleData.selector(), m_context.element(), SelectorChecker::VisitedMatchEnabled);
......@@ -266,7 +266,7 @@ inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, const Co
context.pseudoId = m_pseudoStyleRequest.pseudoId;
context.scrollbar = m_pseudoStyleRequest.scrollbar;
context.scrollbarPart = m_pseudoStyleRequest.scrollbarPart;
context.behaviorAtBoundary = behaviorAtBoundary;
context.contextFlags = contextFlags;
SelectorChecker::Match match = selectorChecker.match(context, DOMSiblingTraversalStrategy(), result);
if (match != SelectorChecker::SelectorMatches)
return false;
......@@ -275,14 +275,14 @@ inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, const Co
return true;
}
void ElementRuleCollector::collectRuleIfMatches(const RuleData& ruleData, SelectorChecker::BehaviorAtBoundary behaviorAtBoundary, CascadeScope cascadeScope, CascadeOrder cascadeOrder, const MatchRequest& matchRequest, RuleRange& ruleRange)
void ElementRuleCollector::collectRuleIfMatches(const RuleData& ruleData, SelectorChecker::ContextFlags contextFlags, CascadeScope cascadeScope, CascadeOrder cascadeOrder, const MatchRequest& matchRequest, RuleRange& ruleRange)
{
if (m_canUseFastReject && m_selectorFilter.fastRejectSelector<RuleData::maximumIdentifierCount>(ruleData.descendantSelectorIdentifierHashes()))
return;
StyleRule* rule = ruleData.rule();
SelectorChecker::MatchResult result;
if (ruleMatches(ruleData, matchRequest.scope, behaviorAtBoundary, &result)) {
if (ruleMatches(ruleData, matchRequest.scope, contextFlags, &result)) {
// If the rule has no properties to apply, then ignore it in the non-debug mode.
const StylePropertySet& properties = rule->properties();
if (properties.isEmpty() && !matchRequest.includeEmptyRules)
......@@ -343,7 +343,7 @@ bool ElementRuleCollector::hasAnyMatchingRules(RuleSet* ruleSet)
int firstRuleIndex = -1, lastRuleIndex = -1;
RuleRange ruleRange(firstRuleIndex, lastRuleIndex);
// FIXME: Verify whether it's ok to ignore CascadeScope here.
collectMatchingRules(MatchRequest(ruleSet), ruleRange, SelectorChecker::StaysWithinTreeScope);
collectMatchingRules(MatchRequest(ruleSet), ruleRange, SelectorChecker::DefaultBehavior);
return m_matchedRules && !m_matchedRules->isEmpty();
}
......
......@@ -126,7 +126,7 @@ public:
PassRefPtrWillBeRawPtr<StyleRuleList> matchedStyleRuleList();
PassRefPtrWillBeRawPtr<CSSRuleList> matchedCSSRuleList();
void collectMatchingRules(const MatchRequest&, RuleRange&, SelectorChecker::BehaviorAtBoundary = SelectorChecker::DoesNotCrossBoundary, CascadeScope = ignoreCascadeScope, CascadeOrder = ignoreCascadeOrder);
void collectMatchingRules(const MatchRequest&, RuleRange&, SelectorChecker::ContextFlags = SelectorChecker::DefaultBehavior, CascadeScope = ignoreCascadeScope, CascadeOrder = ignoreCascadeOrder);
void sortAndTransferMatchedRules();
void clearMatchedRules();
void addElementStyleProperties(const StylePropertySet*, bool isCacheable = true);
......@@ -136,19 +136,19 @@ public:
void sortAndTransferMatchedRulesWithOnlySortBySpecificity();
private:
void collectRuleIfMatches(const RuleData&, SelectorChecker::BehaviorAtBoundary, CascadeScope, CascadeOrder, const MatchRequest&, RuleRange&);
void collectRuleIfMatches(const RuleData&, SelectorChecker::ContextFlags, CascadeScope, CascadeOrder, const MatchRequest&, RuleRange&);
template<typename RuleDataListType>
void collectMatchingRulesForList(const RuleDataListType* rules, SelectorChecker::BehaviorAtBoundary behaviorAtBoundary, CascadeScope cascadeScope, CascadeOrder cascadeOrder, const MatchRequest& matchRequest, RuleRange& ruleRange)
void collectMatchingRulesForList(const RuleDataListType* rules, SelectorChecker::ContextFlags contextFlags, CascadeScope cascadeScope, CascadeOrder cascadeOrder, const MatchRequest& matchRequest, RuleRange& ruleRange)
{
if (!rules)
return;
for (typename RuleDataListType::const_iterator it = rules->begin(), end = rules->end(); it != end; ++it)
collectRuleIfMatches(*it, behaviorAtBoundary, cascadeScope, cascadeOrder, matchRequest, ruleRange);
collectRuleIfMatches(*it, contextFlags, cascadeScope, cascadeOrder, matchRequest, ruleRange);
}
bool ruleMatches(const RuleData&, const ContainerNode* scope, SelectorChecker::BehaviorAtBoundary, SelectorChecker::MatchResult*);
bool ruleMatches(const RuleData&, const ContainerNode* scope, SelectorChecker::ContextFlags, SelectorChecker::MatchResult*);
CSSRuleList* nestedRuleList(CSSRule*);
template<class CSSRuleCollection>
......
......@@ -78,19 +78,12 @@ static bool matchesCustomPseudoElement(const Element* element, const CSSSelector
return true;
}
Element* SelectorChecker::parentElement(const SelectorCheckingContext& context, bool allowToCrossBoundary) const
static Element* parentElement(const SelectorChecker::SelectorCheckingContext& context)
{
// CrossesBoundary means we don't care any context.scope. So we can walk up from a shadow root to its shadow host.
if (allowToCrossBoundary)
return context.element->parentOrShadowHostElement();
// If context.scope is a shadow root, we should walk up to its shadow host.
if ((context.behaviorAtBoundary & SelectorChecker::ScopeIsShadowRoot) && context.scope == context.element->containingShadowRoot())
if (context.scope && context.scope == context.element->containingShadowRoot())
return context.element->parentOrShadowHostElement();
if ((context.behaviorAtBoundary & SelectorChecker::BoundaryBehaviorMask) != SelectorChecker::StaysWithinTreeScope)
return context.element->parentElement();
// If context.scope is some element in some shadow tree and querySelector initialized the context,
// e.g. shadowRoot.querySelector(':host *'),
// (a) context.element has the same treescope as context.scope, need to walk up to its shadow host.
......@@ -101,26 +94,22 @@ Element* SelectorChecker::parentElement(const SelectorCheckingContext& context,
return context.element->parentElement();
}
bool SelectorChecker::scopeContainsLastMatchedElement(const SelectorCheckingContext& context) const
static bool scopeContainsLastMatchedElement(const SelectorChecker::SelectorCheckingContext& context)
{
if (!(context.behaviorAtBoundary & SelectorChecker::ScopeContainsLastMatchedElement))
if (!(context.contextFlags & SelectorChecker::ScopeContainsLastMatchedElement))
return true;
ASSERT(context.scope);
// If behaviorAtBoundary is not ScopeIsShadowRoot, we can use "contains".
if (!(context.behaviorAtBoundary & SelectorChecker::ScopeIsShadowRoot))
// If the scope is not a Shadow root, we can use "contains".
if (!context.scope->isShadowRoot())
return context.scope->contains(context.element);
// If a given element is scope, i.e. shadow host, matches.
if (context.element == context.scope->shadowHost() && (!context.previousElement || context.previousElement->isInDescendantTreeOf(context.element)))
return true;
ShadowRoot* root = context.element->containingShadowRoot();
if (!root)
return false;
// If a host of the containing shadow root is scope, matches.
return root == context.scope;
// If the containing shadow root is scope, matches.
return context.element->containingShadowRoot() == context.scope;
}
static inline bool nextSelectorExceedsScope(const SelectorChecker::SelectorCheckingContext& context)
......@@ -341,7 +330,7 @@ SelectorChecker::Match SelectorChecker::matchForRelation(const SelectorCheckingC
case CSSSelector::ShadowPseudo:
{
// If we're in the same tree-scope as the scoping element, then following a shadow descendant combinator would escape that and thus the scope.
if (context.scope && context.scope->shadowHost() && context.scope->shadowHost()->treeScope() == context.element->treeScope() && (context.behaviorAtBoundary & BoundaryBehaviorMask) != StaysWithinTreeScope)
if (context.scope && context.scope->shadowHost() && context.scope->shadowHost()->treeScope() == context.element->treeScope())
return SelectorFailsCompletely;
Element* shadowHost = context.element->shadowHost();
......@@ -357,7 +346,7 @@ SelectorChecker::Match SelectorChecker::matchForRelation(const SelectorCheckingC
{
nextContext.isSubSelector = false;
nextContext.elementStyle = 0;
for (nextContext.element = parentElement(context, true); nextContext.element; nextContext.element = parentElement(nextContext, true)) {
for (nextContext.element = context.element->parentOrShadowHostElement(); nextContext.element; nextContext.element = nextContext.element->parentOrShadowHostElement()) {
Match match = this->match(nextContext, siblingTraversalStrategy, result);
if (match == SelectorMatches || match == SelectorFailsCompletely)
return match;
......@@ -380,25 +369,11 @@ SelectorChecker::Match SelectorChecker::matchForShadowDistributed(const Element*
{
ASSERT(element);
WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints;
const ContainerNode* scope = nextContext.scope;
BehaviorAtBoundary behaviorAtBoundary = nextContext.behaviorAtBoundary;
collectDestinationInsertionPoints(*element, insertionPoints);
for (size_t i = 0; i < insertionPoints.size(); ++i) {
nextContext.element = insertionPoints[i];
// If a given scope is a shadow host of an insertion point but behaviorAtBoundary doesn't have ScopeIsShadowRoot,
// we need to update behaviorAtBoundary to make selectors like ":host > ::content" work correctly.
if (m_mode == SharingRules) {
nextContext.behaviorAtBoundary = static_cast<BehaviorAtBoundary>(behaviorAtBoundary | ScopeIsShadowRoot);
if (m_mode == SharingRules)
nextContext.scope = insertionPoints[i]->containingShadowRoot();
} else if (scope == insertionPoints[i]->containingShadowRoot() && !(behaviorAtBoundary & ScopeIsShadowRoot)) {
nextContext.behaviorAtBoundary = static_cast<BehaviorAtBoundary>(behaviorAtBoundary | ScopeIsShadowRoot);
} else {
nextContext.behaviorAtBoundary = behaviorAtBoundary;
}
nextContext.isSubSelector = false;
nextContext.elementStyle = 0;
if (match(nextContext, siblingTraversalStrategy, result) == SelectorMatches)
......@@ -534,11 +509,11 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
ASSERT(context.selector);
const CSSSelector& selector = *context.selector;
bool elementIsHostInItsShadowTree = isHostInItsShadowTree(element, context.behaviorAtBoundary, context.scope);
bool elementIsHostInItsShadowTree = isHostInItsShadowTree(element, context.scope);
// Only :host and :ancestor should match the host: http://drafts.csswg.org/css-scoping/#host-element
if (elementIsHostInItsShadowTree && !selector.isHostPseudoClass()
&& !(context.behaviorAtBoundary & TreatShadowHostAsNormalScope))
&& !(context.contextFlags & TreatShadowHostAsNormalScope))
return false;
if (selector.match() == CSSSelector::Tag)
......@@ -947,7 +922,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
// If one of simple selectors matches an element, returns SelectorMatches. Just "OR".
for (subContext.selector = selector.selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(*subContext.selector)) {
subContext.behaviorAtBoundary = ScopeIsShadowHostInPseudoHostParameter;
subContext.contextFlags = TreatShadowHostAsNormalScope;
subContext.scope = context.scope;
// Use NodeRenderingTraversal to traverse a composed ancestor list of a given element.
Element* nextElement = &element;
......@@ -961,7 +936,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
maxSpecificity = std::max(maxSpecificity, hostContext.selector->specificity() + subResult.specificity);
break;
}
hostContext.behaviorAtBoundary = DoesNotCrossBoundary;
hostContext.contextFlags = DefaultBehavior;
hostContext.scope = 0;
if (selector.pseudoType() == CSSSelector::PseudoHost)
......@@ -1001,7 +976,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
} else if (selector.match() == CSSSelector::PseudoElement && selector.pseudoType() == CSSSelector::PseudoCue) {
SelectorCheckingContext subContext(context);
subContext.isSubSelector = true;
subContext.behaviorAtBoundary = StaysWithinTreeScope;
subContext.contextFlags = DefaultBehavior;
const CSSSelector* contextSelector = context.selector;
ASSERT(contextSelector);
......
......@@ -47,16 +47,11 @@ public:
enum VisitedMatchType { VisitedMatchDisabled, VisitedMatchEnabled };
enum Mode { ResolvingStyle = 0, CollectingStyleRules, CollectingCSSRules, QueryingRules, SharingRules };
explicit SelectorChecker(Document&, Mode);
enum BehaviorAtBoundary {
DoesNotCrossBoundary = 0,
// FIXME: refactor to remove BoundaryBehavior (i.e. DoesNotCrossBoundary and StaysWithinTreeScope).
StaysWithinTreeScope = 2,
BoundaryBehaviorMask = 3, // 2bit for boundary behavior
ScopeContainsLastMatchedElement = 4,
ScopeIsShadowRoot = 8,
TreatShadowHostAsNormalScope = 16,
ScopeIsShadowHostInPseudoHostParameter = ScopeIsShadowRoot | TreatShadowHostAsNormalScope
enum ContextFlags {
// FIXME: Revmoe DefaultBehavior.
DefaultBehavior = 0,
ScopeContainsLastMatchedElement = 1,
TreatShadowHostAsNormalScope = 2,
};
struct SelectorCheckingContext {
......@@ -74,7 +69,7 @@ public:
, isSubSelector(false)
, hasScrollbarPseudo(false)
, hasSelectionPseudo(false)
, behaviorAtBoundary(DoesNotCrossBoundary)
, contextFlags(DefaultBehavior)
{ }
const CSSSelector* selector;
......@@ -89,7 +84,7 @@ public:
bool isSubSelector;
bool hasScrollbarPseudo;
bool hasSelectionPseudo;
BehaviorAtBoundary behaviorAtBoundary;
ContextFlags contextFlags;
};
struct MatchResult {
......@@ -119,7 +114,7 @@ public:
enum LinkMatchMask { MatchLink = 1, MatchVisited = 2, MatchAll = MatchLink | MatchVisited };
static unsigned determineLinkMatchType(const CSSSelector&);
static bool isHostInItsShadowTree(const Element&, BehaviorAtBoundary, const ContainerNode* scope);
static bool isHostInItsShadowTree(const Element&, const ContainerNode* scope);
private:
template<typename SiblingTraversalStrategy>
......@@ -132,8 +127,6 @@ private:
Match matchForPseudoShadow(const ContainerNode*, const SelectorCheckingContext&, const SiblingTraversalStrategy&, MatchResult*) const;
bool checkScrollbarPseudoClass(const SelectorCheckingContext&, Document*, const CSSSelector&) const;
Element* parentElement(const SelectorCheckingContext&, bool allowToCrossBoundary = false) const;
bool scopeContainsLastMatchedElement(const SelectorCheckingContext&) const;
static bool isFrameFocused(const Element&);
......@@ -177,7 +170,7 @@ inline bool SelectorChecker::checkExactAttribute(const Element& element, const Q
return false;
}
inline bool SelectorChecker::isHostInItsShadowTree(const Element& element, BehaviorAtBoundary behaviorAtBoundary, const ContainerNode* scope)
inline bool SelectorChecker::isHostInItsShadowTree(const Element& element, const ContainerNode* scope)
{
return scope && scope->isInShadowTree() && scope->shadowHost() == element;
}
......
......@@ -76,18 +76,13 @@ void TreeBoundaryCrossingRules::collectTreeBoundaryCrossingRules(Element* elemen
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, we should use ScopeIsShadowRoot.
if (scopingNode && scopingNode->isShadowRoot())
boundaryBehavior |= SelectorChecker::ScopeIsShadowRoot;
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);
collector.collectMatchingRules(MatchRequest(ruleSet, includeEmptyRules, scopingNode, parentStyleSheet), ruleRange, SelectorChecker::ScopeContainsLastMatchedElement, ignoreCascadeScope, cascadeOrder);
}
++innerCascadeOrder;
--outerCascadeOrder;
......
......@@ -115,18 +115,15 @@ void ScopedStyleResolver::addKeyframeStyle(PassRefPtrWillBeRawPtr<StyleRuleKeyfr
void ScopedStyleResolver::collectMatchingAuthorRules(ElementRuleCollector& collector, bool includeEmptyRules, bool applyAuthorStyles, CascadeScope cascadeScope, CascadeOrder cascadeOrder)
{
const ContainerNode* scopingNode = &m_scopingNode;
unsigned behaviorAtBoundary = SelectorChecker::DoesNotCrossBoundary;
unsigned contextFlags = SelectorChecker::DefaultBehavior;
if (!applyAuthorStyles)
behaviorAtBoundary |= SelectorChecker::ScopeContainsLastMatchedElement;
if (m_scopingNode.isShadowRoot())
behaviorAtBoundary |= SelectorChecker::ScopeIsShadowRoot;
contextFlags |= SelectorChecker::ScopeContainsLastMatchedElement;
RuleRange ruleRange = collector.matchedResult().ranges.authorRuleRange();
for (size_t i = 0; i < m_authorStyleSheets.size(); ++i) {
MatchRequest matchRequest(&m_authorStyleSheets[i]->contents()->ruleSet(), includeEmptyRules, scopingNode, m_authorStyleSheets[i], applyAuthorStyles, i);
collector.collectMatchingRules(matchRequest, ruleRange, static_cast<SelectorChecker::BehaviorAtBoundary>(behaviorAtBoundary), cascadeScope, cascadeOrder);
collector.collectMatchingRules(matchRequest, ruleRange, static_cast<SelectorChecker::ContextFlags>(contextFlags), cascadeScope, cascadeOrder);
}
}
......
......@@ -119,7 +119,6 @@ inline bool SelectorDataList::selectorMatches(const CSSSelector& selector, Eleme
{
SelectorChecker selectorChecker(element.document(), SelectorChecker::QueryingRules);
SelectorChecker::SelectorCheckingContext selectorCheckingContext(selector, &element, SelectorChecker::VisitedMatchDisabled);
selectorCheckingContext.behaviorAtBoundary = SelectorChecker::StaysWithinTreeScope;
selectorCheckingContext.scope = !rootNode.isDocumentNode() ? &rootNode : 0;
return selectorChecker.match(selectorCheckingContext, DOMSiblingTraversalStrategy()) == SelectorChecker::SelectorMatches;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment