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 ...@@ -118,7 +118,7 @@ void ElementRuleCollector::addElementStyleProperties(const StylePropertySet* pro
m_result.isCacheable = false; 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(); TreeScope& treeScope = element->treeScope();
...@@ -130,12 +130,12 @@ static bool rulesApplicableInCurrentTreeScope(const Element* element, const Cont ...@@ -130,12 +130,12 @@ static bool rulesApplicableInCurrentTreeScope(const Element* element, const Cont
if (!scopingNode || treeScope == scopingNode->treeScope()) if (!scopingNode || treeScope == scopingNode->treeScope())
return true; return true;
// d) the rules comes from a scoped style sheet within an active shadow root whose host is the given element // 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 true;
return false; 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(matchRequest.ruleSet);
ASSERT(m_context.element()); ASSERT(m_context.element());
...@@ -144,11 +144,11 @@ void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest ...@@ -144,11 +144,11 @@ void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest
const AtomicString& pseudoId = element.shadowPseudoId(); const AtomicString& pseudoId = element.shadowPseudoId();
if (!pseudoId.isEmpty()) { if (!pseudoId.isEmpty()) {
ASSERT(element.isStyledElement()); 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()) 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: // Check whether other types of rules are applicable in the current tree scope. Criteria for this:
// a) it's a UA rule // a) it's a UA rule
// b) the tree scope allows author rules // b) the tree scope allows author rules
...@@ -156,24 +156,24 @@ void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest ...@@ -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 // 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 // e) the rules can cross boundaries
// b)-e) is checked in rulesApplicableInCurrentTreeScope. // 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; return;
// We need to collect the rules for id, class, tag, and everything else into a buffer and // We need to collect the rules for id, class, tag, and everything else into a buffer and
// then sort the buffer. // then sort the buffer.
if (element.hasID()) 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()) { if (element.isStyledElement() && element.hasClass()) {
for (size_t i = 0; i < element.classNames().size(); ++i) 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()) 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)) if (SelectorChecker::matchesFocusPseudoClass(element))
collectMatchingRulesForList(matchRequest.ruleSet->focusPseudoClassRules(), behaviorAtBoundary, cascadeScope, cascadeOrder, matchRequest, ruleRange); collectMatchingRulesForList(matchRequest.ruleSet->focusPseudoClassRules(), contextFlags, cascadeScope, cascadeOrder, matchRequest, ruleRange);
collectMatchingRulesForList(matchRequest.ruleSet->tagRules(element.localName()), behaviorAtBoundary, cascadeScope, cascadeOrder, matchRequest, ruleRange); collectMatchingRulesForList(matchRequest.ruleSet->tagRules(element.localName()), contextFlags, cascadeScope, cascadeOrder, matchRequest, ruleRange);
collectMatchingRulesForList(matchRequest.ruleSet->universalRules(), behaviorAtBoundary, cascadeScope, cascadeOrder, matchRequest, ruleRange); collectMatchingRulesForList(matchRequest.ruleSet->universalRules(), contextFlags, cascadeScope, cascadeOrder, matchRequest, ruleRange);
} }
CSSRuleList* ElementRuleCollector::nestedRuleList(CSSRule* rule) CSSRuleList* ElementRuleCollector::nestedRuleList(CSSRule* rule)
...@@ -257,7 +257,7 @@ void ElementRuleCollector::sortAndTransferMatchedRules() ...@@ -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 selectorChecker(m_context.element()->document(), m_mode);
SelectorChecker::SelectorCheckingContext context(ruleData.selector(), m_context.element(), SelectorChecker::VisitedMatchEnabled); SelectorChecker::SelectorCheckingContext context(ruleData.selector(), m_context.element(), SelectorChecker::VisitedMatchEnabled);
...@@ -266,7 +266,7 @@ inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, const Co ...@@ -266,7 +266,7 @@ inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, const Co
context.pseudoId = m_pseudoStyleRequest.pseudoId; context.pseudoId = m_pseudoStyleRequest.pseudoId;
context.scrollbar = m_pseudoStyleRequest.scrollbar; context.scrollbar = m_pseudoStyleRequest.scrollbar;
context.scrollbarPart = m_pseudoStyleRequest.scrollbarPart; context.scrollbarPart = m_pseudoStyleRequest.scrollbarPart;
context.behaviorAtBoundary = behaviorAtBoundary; context.contextFlags = contextFlags;
SelectorChecker::Match match = selectorChecker.match(context, DOMSiblingTraversalStrategy(), result); SelectorChecker::Match match = selectorChecker.match(context, DOMSiblingTraversalStrategy(), result);
if (match != SelectorChecker::SelectorMatches) if (match != SelectorChecker::SelectorMatches)
return false; return false;
...@@ -275,14 +275,14 @@ inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, const Co ...@@ -275,14 +275,14 @@ inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, const Co
return true; 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())) if (m_canUseFastReject && m_selectorFilter.fastRejectSelector<RuleData::maximumIdentifierCount>(ruleData.descendantSelectorIdentifierHashes()))
return; return;
StyleRule* rule = ruleData.rule(); StyleRule* rule = ruleData.rule();
SelectorChecker::MatchResult result; 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. // If the rule has no properties to apply, then ignore it in the non-debug mode.
const StylePropertySet& properties = rule->properties(); const StylePropertySet& properties = rule->properties();
if (properties.isEmpty() && !matchRequest.includeEmptyRules) if (properties.isEmpty() && !matchRequest.includeEmptyRules)
...@@ -343,7 +343,7 @@ bool ElementRuleCollector::hasAnyMatchingRules(RuleSet* ruleSet) ...@@ -343,7 +343,7 @@ bool ElementRuleCollector::hasAnyMatchingRules(RuleSet* ruleSet)
int firstRuleIndex = -1, lastRuleIndex = -1; int firstRuleIndex = -1, lastRuleIndex = -1;
RuleRange ruleRange(firstRuleIndex, lastRuleIndex); RuleRange ruleRange(firstRuleIndex, lastRuleIndex);
// FIXME: Verify whether it's ok to ignore CascadeScope here. // 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(); return m_matchedRules && !m_matchedRules->isEmpty();
} }
......
...@@ -126,7 +126,7 @@ public: ...@@ -126,7 +126,7 @@ public:
PassRefPtrWillBeRawPtr<StyleRuleList> matchedStyleRuleList(); PassRefPtrWillBeRawPtr<StyleRuleList> matchedStyleRuleList();
PassRefPtrWillBeRawPtr<CSSRuleList> matchedCSSRuleList(); 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 sortAndTransferMatchedRules();
void clearMatchedRules(); void clearMatchedRules();
void addElementStyleProperties(const StylePropertySet*, bool isCacheable = true); void addElementStyleProperties(const StylePropertySet*, bool isCacheable = true);
...@@ -136,19 +136,19 @@ public: ...@@ -136,19 +136,19 @@ public:
void sortAndTransferMatchedRulesWithOnlySortBySpecificity(); void sortAndTransferMatchedRulesWithOnlySortBySpecificity();
private: 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> 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) if (!rules)
return; return;
for (typename RuleDataListType::const_iterator it = rules->begin(), end = rules->end(); it != end; ++it) 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*); CSSRuleList* nestedRuleList(CSSRule*);
template<class CSSRuleCollection> template<class CSSRuleCollection>
......
...@@ -78,19 +78,12 @@ static bool matchesCustomPseudoElement(const Element* element, const CSSSelector ...@@ -78,19 +78,12 @@ static bool matchesCustomPseudoElement(const Element* element, const CSSSelector
return true; 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.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(); 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, // If context.scope is some element in some shadow tree and querySelector initialized the context,
// e.g. shadowRoot.querySelector(':host *'), // e.g. shadowRoot.querySelector(':host *'),
// (a) context.element has the same treescope as context.scope, need to walk up to its shadow 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, ...@@ -101,26 +94,22 @@ Element* SelectorChecker::parentElement(const SelectorCheckingContext& context,
return context.element->parentElement(); 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; return true;
ASSERT(context.scope); ASSERT(context.scope);
// If behaviorAtBoundary is not ScopeIsShadowRoot, we can use "contains". // If the scope is not a Shadow root, we can use "contains".
if (!(context.behaviorAtBoundary & SelectorChecker::ScopeIsShadowRoot)) if (!context.scope->isShadowRoot())
return context.scope->contains(context.element); return context.scope->contains(context.element);
// If a given element is scope, i.e. shadow host, matches. // If a given element is scope, i.e. shadow host, matches.
if (context.element == context.scope->shadowHost() && (!context.previousElement || context.previousElement->isInDescendantTreeOf(context.element))) if (context.element == context.scope->shadowHost() && (!context.previousElement || context.previousElement->isInDescendantTreeOf(context.element)))
return true; return true;
ShadowRoot* root = context.element->containingShadowRoot(); // If the containing shadow root is scope, matches.
if (!root) return context.element->containingShadowRoot() == context.scope;
return false;
// If a host of the containing shadow root is scope, matches.
return root == context.scope;
} }
static inline bool nextSelectorExceedsScope(const SelectorChecker::SelectorCheckingContext& context) static inline bool nextSelectorExceedsScope(const SelectorChecker::SelectorCheckingContext& context)
...@@ -341,7 +330,7 @@ SelectorChecker::Match SelectorChecker::matchForRelation(const SelectorCheckingC ...@@ -341,7 +330,7 @@ SelectorChecker::Match SelectorChecker::matchForRelation(const SelectorCheckingC
case CSSSelector::ShadowPseudo: 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 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; return SelectorFailsCompletely;
Element* shadowHost = context.element->shadowHost(); Element* shadowHost = context.element->shadowHost();
...@@ -357,7 +346,7 @@ SelectorChecker::Match SelectorChecker::matchForRelation(const SelectorCheckingC ...@@ -357,7 +346,7 @@ SelectorChecker::Match SelectorChecker::matchForRelation(const SelectorCheckingC
{ {
nextContext.isSubSelector = false; nextContext.isSubSelector = false;
nextContext.elementStyle = 0; 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); Match match = this->match(nextContext, siblingTraversalStrategy, result);
if (match == SelectorMatches || match == SelectorFailsCompletely) if (match == SelectorMatches || match == SelectorFailsCompletely)
return match; return match;
...@@ -380,25 +369,11 @@ SelectorChecker::Match SelectorChecker::matchForShadowDistributed(const Element* ...@@ -380,25 +369,11 @@ SelectorChecker::Match SelectorChecker::matchForShadowDistributed(const Element*
{ {
ASSERT(element); ASSERT(element);
WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints; WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints;
const ContainerNode* scope = nextContext.scope;
BehaviorAtBoundary behaviorAtBoundary = nextContext.behaviorAtBoundary;
collectDestinationInsertionPoints(*element, insertionPoints); collectDestinationInsertionPoints(*element, insertionPoints);
for (size_t i = 0; i < insertionPoints.size(); ++i) { for (size_t i = 0; i < insertionPoints.size(); ++i) {
nextContext.element = insertionPoints[i]; nextContext.element = insertionPoints[i];
if (m_mode == SharingRules)
// 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);
nextContext.scope = insertionPoints[i]->containingShadowRoot(); 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.isSubSelector = false;
nextContext.elementStyle = 0; nextContext.elementStyle = 0;
if (match(nextContext, siblingTraversalStrategy, result) == SelectorMatches) if (match(nextContext, siblingTraversalStrategy, result) == SelectorMatches)
...@@ -534,11 +509,11 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib ...@@ -534,11 +509,11 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
ASSERT(context.selector); ASSERT(context.selector);
const CSSSelector& selector = *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 // Only :host and :ancestor should match the host: http://drafts.csswg.org/css-scoping/#host-element
if (elementIsHostInItsShadowTree && !selector.isHostPseudoClass() if (elementIsHostInItsShadowTree && !selector.isHostPseudoClass()
&& !(context.behaviorAtBoundary & TreatShadowHostAsNormalScope)) && !(context.contextFlags & TreatShadowHostAsNormalScope))
return false; return false;
if (selector.match() == CSSSelector::Tag) if (selector.match() == CSSSelector::Tag)
...@@ -947,7 +922,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib ...@@ -947,7 +922,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
// If one of simple selectors matches an element, returns SelectorMatches. Just "OR". // 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)) { for (subContext.selector = selector.selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(*subContext.selector)) {
subContext.behaviorAtBoundary = ScopeIsShadowHostInPseudoHostParameter; subContext.contextFlags = TreatShadowHostAsNormalScope;
subContext.scope = context.scope; subContext.scope = context.scope;
// Use NodeRenderingTraversal to traverse a composed ancestor list of a given element. // Use NodeRenderingTraversal to traverse a composed ancestor list of a given element.
Element* nextElement = &element; Element* nextElement = &element;
...@@ -961,7 +936,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib ...@@ -961,7 +936,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
maxSpecificity = std::max(maxSpecificity, hostContext.selector->specificity() + subResult.specificity); maxSpecificity = std::max(maxSpecificity, hostContext.selector->specificity() + subResult.specificity);
break; break;
} }
hostContext.behaviorAtBoundary = DoesNotCrossBoundary; hostContext.contextFlags = DefaultBehavior;
hostContext.scope = 0; hostContext.scope = 0;
if (selector.pseudoType() == CSSSelector::PseudoHost) if (selector.pseudoType() == CSSSelector::PseudoHost)
...@@ -1001,7 +976,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib ...@@ -1001,7 +976,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
} else if (selector.match() == CSSSelector::PseudoElement && selector.pseudoType() == CSSSelector::PseudoCue) { } else if (selector.match() == CSSSelector::PseudoElement && selector.pseudoType() == CSSSelector::PseudoCue) {
SelectorCheckingContext subContext(context); SelectorCheckingContext subContext(context);
subContext.isSubSelector = true; subContext.isSubSelector = true;
subContext.behaviorAtBoundary = StaysWithinTreeScope; subContext.contextFlags = DefaultBehavior;
const CSSSelector* contextSelector = context.selector; const CSSSelector* contextSelector = context.selector;
ASSERT(contextSelector); ASSERT(contextSelector);
......
...@@ -47,16 +47,11 @@ public: ...@@ -47,16 +47,11 @@ public:
enum VisitedMatchType { VisitedMatchDisabled, VisitedMatchEnabled }; enum VisitedMatchType { VisitedMatchDisabled, VisitedMatchEnabled };
enum Mode { ResolvingStyle = 0, CollectingStyleRules, CollectingCSSRules, QueryingRules, SharingRules }; enum Mode { ResolvingStyle = 0, CollectingStyleRules, CollectingCSSRules, QueryingRules, SharingRules };
explicit SelectorChecker(Document&, Mode); explicit SelectorChecker(Document&, Mode);
enum BehaviorAtBoundary { enum ContextFlags {
DoesNotCrossBoundary = 0, // FIXME: Revmoe DefaultBehavior.
// FIXME: refactor to remove BoundaryBehavior (i.e. DoesNotCrossBoundary and StaysWithinTreeScope). DefaultBehavior = 0,
StaysWithinTreeScope = 2, ScopeContainsLastMatchedElement = 1,
BoundaryBehaviorMask = 3, // 2bit for boundary behavior TreatShadowHostAsNormalScope = 2,
ScopeContainsLastMatchedElement = 4,
ScopeIsShadowRoot = 8,
TreatShadowHostAsNormalScope = 16,
ScopeIsShadowHostInPseudoHostParameter = ScopeIsShadowRoot | TreatShadowHostAsNormalScope
}; };
struct SelectorCheckingContext { struct SelectorCheckingContext {
...@@ -74,7 +69,7 @@ public: ...@@ -74,7 +69,7 @@ public:
, isSubSelector(false) , isSubSelector(false)
, hasScrollbarPseudo(false) , hasScrollbarPseudo(false)
, hasSelectionPseudo(false) , hasSelectionPseudo(false)
, behaviorAtBoundary(DoesNotCrossBoundary) , contextFlags(DefaultBehavior)
{ } { }
const CSSSelector* selector; const CSSSelector* selector;
...@@ -89,7 +84,7 @@ public: ...@@ -89,7 +84,7 @@ public:
bool isSubSelector; bool isSubSelector;
bool hasScrollbarPseudo; bool hasScrollbarPseudo;
bool hasSelectionPseudo; bool hasSelectionPseudo;
BehaviorAtBoundary behaviorAtBoundary; ContextFlags contextFlags;
}; };
struct MatchResult { struct MatchResult {
...@@ -119,7 +114,7 @@ public: ...@@ -119,7 +114,7 @@ public:
enum LinkMatchMask { MatchLink = 1, MatchVisited = 2, MatchAll = MatchLink | MatchVisited }; enum LinkMatchMask { MatchLink = 1, MatchVisited = 2, MatchAll = MatchLink | MatchVisited };
static unsigned determineLinkMatchType(const CSSSelector&); static unsigned determineLinkMatchType(const CSSSelector&);
static bool isHostInItsShadowTree(const Element&, BehaviorAtBoundary, const ContainerNode* scope); static bool isHostInItsShadowTree(const Element&, const ContainerNode* scope);
private: private:
template<typename SiblingTraversalStrategy> template<typename SiblingTraversalStrategy>
...@@ -132,8 +127,6 @@ private: ...@@ -132,8 +127,6 @@ private:
Match matchForPseudoShadow(const ContainerNode*, const SelectorCheckingContext&, const SiblingTraversalStrategy&, MatchResult*) const; Match matchForPseudoShadow(const ContainerNode*, const SelectorCheckingContext&, const SiblingTraversalStrategy&, MatchResult*) const;
bool checkScrollbarPseudoClass(const SelectorCheckingContext&, Document*, const CSSSelector&) 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&); static bool isFrameFocused(const Element&);
...@@ -177,7 +170,7 @@ inline bool SelectorChecker::checkExactAttribute(const Element& element, const Q ...@@ -177,7 +170,7 @@ inline bool SelectorChecker::checkExactAttribute(const Element& element, const Q
return false; 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; return scope && scope->isInShadowTree() && scope->shadowHost() == element;
} }
......
...@@ -76,18 +76,13 @@ void TreeBoundaryCrossingRules::collectTreeBoundaryCrossingRules(Element* elemen ...@@ -76,18 +76,13 @@ void TreeBoundaryCrossingRules::collectTreeBoundaryCrossingRules(Element* elemen
for (DocumentOrderedList::iterator it = m_scopingNodes.begin(); it != m_scopingNodes.end(); ++it) { for (DocumentOrderedList::iterator it = m_scopingNodes.begin(); it != m_scopingNodes.end(); ++it) {
const ContainerNode* scopingNode = toContainerNode(*it); const ContainerNode* scopingNode = toContainerNode(*it);
CSSStyleSheetRuleSubSet* ruleSubSet = m_treeBoundaryCrossingRuleSetMap.get(scopingNode); CSSStyleSheetRuleSubSet* ruleSubSet = m_treeBoundaryCrossingRuleSetMap.get(scopingNode);
unsigned boundaryBehavior = SelectorChecker::ScopeContainsLastMatchedElement;
bool isInnerTreeScope = element->treeScope().isInclusiveAncestorOf(scopingNode->treeScope()); 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; CascadeOrder cascadeOrder = isInnerTreeScope ? innerCascadeOrder : outerCascadeOrder;
for (CSSStyleSheetRuleSubSet::iterator it = ruleSubSet->begin(); it != ruleSubSet->end(); ++it) { for (CSSStyleSheetRuleSubSet::iterator it = ruleSubSet->begin(); it != ruleSubSet->end(); ++it) {
CSSStyleSheet* parentStyleSheet = it->first; CSSStyleSheet* parentStyleSheet = it->first;
RuleSet* ruleSet = it->second.get(); 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; ++innerCascadeOrder;
--outerCascadeOrder; --outerCascadeOrder;
......
...@@ -115,18 +115,15 @@ void ScopedStyleResolver::addKeyframeStyle(PassRefPtrWillBeRawPtr<StyleRuleKeyfr ...@@ -115,18 +115,15 @@ void ScopedStyleResolver::addKeyframeStyle(PassRefPtrWillBeRawPtr<StyleRuleKeyfr
void ScopedStyleResolver::collectMatchingAuthorRules(ElementRuleCollector& collector, bool includeEmptyRules, bool applyAuthorStyles, CascadeScope cascadeScope, CascadeOrder cascadeOrder) void ScopedStyleResolver::collectMatchingAuthorRules(ElementRuleCollector& collector, bool includeEmptyRules, bool applyAuthorStyles, CascadeScope cascadeScope, CascadeOrder cascadeOrder)
{ {
const ContainerNode* scopingNode = &m_scopingNode; const ContainerNode* scopingNode = &m_scopingNode;
unsigned behaviorAtBoundary = SelectorChecker::DoesNotCrossBoundary; unsigned contextFlags = SelectorChecker::DefaultBehavior;
if (!applyAuthorStyles) if (!applyAuthorStyles)
behaviorAtBoundary |= SelectorChecker::ScopeContainsLastMatchedElement; contextFlags |= SelectorChecker::ScopeContainsLastMatchedElement;
if (m_scopingNode.isShadowRoot())
behaviorAtBoundary |= SelectorChecker::ScopeIsShadowRoot;
RuleRange ruleRange = collector.matchedResult().ranges.authorRuleRange(); RuleRange ruleRange = collector.matchedResult().ranges.authorRuleRange();
for (size_t i = 0; i < m_authorStyleSheets.size(); ++i) { for (size_t i = 0; i < m_authorStyleSheets.size(); ++i) {
MatchRequest matchRequest(&m_authorStyleSheets[i]->contents()->ruleSet(), includeEmptyRules, scopingNode, m_authorStyleSheets[i], applyAuthorStyles, 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 ...@@ -119,7 +119,6 @@ inline bool SelectorDataList::selectorMatches(const CSSSelector& selector, Eleme
{ {
SelectorChecker selectorChecker(element.document(), SelectorChecker::QueryingRules); SelectorChecker selectorChecker(element.document(), SelectorChecker::QueryingRules);
SelectorChecker::SelectorCheckingContext selectorCheckingContext(selector, &element, SelectorChecker::VisitedMatchDisabled); SelectorChecker::SelectorCheckingContext selectorCheckingContext(selector, &element, SelectorChecker::VisitedMatchDisabled);
selectorCheckingContext.behaviorAtBoundary = SelectorChecker::StaysWithinTreeScope;
selectorCheckingContext.scope = !rootNode.isDocumentNode() ? &rootNode : 0; selectorCheckingContext.scope = !rootNode.isDocumentNode() ? &rootNode : 0;
return selectorChecker.match(selectorCheckingContext, DOMSiblingTraversalStrategy()) == SelectorChecker::SelectorMatches; 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