Commit 8cee5a4d authored by kochi@chromium.org's avatar kochi@chromium.org

Change shadow style's scope from Shadow Host to Shadow Root

No visible change, test expectation change is expected.

Scope of styles in shadow tree used to be its shadow host
for ease of checking the style against :host etc.

This caused code complexity for checking against boundary
breaking CSS selector rules (e.g. ::content, /deep/).
Changing the scope to its shadow root will simplify some
condition checks.

This is a step towards fixing issue 355674.

BUG=355674
TEST=pass all layout tests

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

git-svn-id: svn://svn.chromium.org/blink/trunk@176304 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 004e60fb
...@@ -130,7 +130,7 @@ static bool rulesApplicableInCurrentTreeScope(const Element* element, const Cont ...@@ -130,7 +130,7 @@ 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 (element->isInShadowTree() && (behaviorAtBoundary & SelectorChecker::ScopeIsShadowHost) && scopingNode == element->containingShadowRoot()->host()) if (SelectorChecker::isHostInItsShadowTree(*element, behaviorAtBoundary, scopingNode))
return true; return true;
return false; return false;
} }
......
...@@ -83,8 +83,8 @@ Element* SelectorChecker::parentElement(const SelectorCheckingContext& context, ...@@ -83,8 +83,8 @@ Element* SelectorChecker::parentElement(const SelectorCheckingContext& context,
if (allowToCrossBoundary) if (allowToCrossBoundary)
return context.element->parentOrShadowHostElement(); return context.element->parentOrShadowHostElement();
// If context.scope is a shadow host, we should walk up from a shadow root to its shadow host. // If context.scope is a shadow root, we should walk up to its shadow host.
if ((context.behaviorAtBoundary & SelectorChecker::ScopeIsShadowHost) && context.scope == context.element->shadowHost()) if ((context.behaviorAtBoundary & SelectorChecker::ScopeIsShadowRoot) && context.scope == context.element->containingShadowRoot())
return context.element->parentOrShadowHostElement(); return context.element->parentOrShadowHostElement();
if ((context.behaviorAtBoundary & SelectorChecker::BoundaryBehaviorMask) != SelectorChecker::StaysWithinTreeScope) if ((context.behaviorAtBoundary & SelectorChecker::BoundaryBehaviorMask) != SelectorChecker::StaysWithinTreeScope)
...@@ -106,12 +106,12 @@ bool SelectorChecker::scopeContainsLastMatchedElement(const SelectorCheckingCont ...@@ -106,12 +106,12 @@ bool SelectorChecker::scopeContainsLastMatchedElement(const SelectorCheckingCont
return true; return true;
ASSERT(context.scope); ASSERT(context.scope);
// If behaviorAtBoundary is not ScopeIsShadowHost, we can use "contains". // If behaviorAtBoundary is not ScopeIsShadowRoot, we can use "contains".
if (!(context.behaviorAtBoundary & SelectorChecker::ScopeIsShadowHost)) if (!(context.behaviorAtBoundary & SelectorChecker::ScopeIsShadowRoot))
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 && (!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(); ShadowRoot* root = context.element->containingShadowRoot();
...@@ -119,16 +119,14 @@ bool SelectorChecker::scopeContainsLastMatchedElement(const SelectorCheckingCont ...@@ -119,16 +119,14 @@ bool SelectorChecker::scopeContainsLastMatchedElement(const SelectorCheckingCont
return false; return false;
// If a host of the containing shadow root is scope, matches. // If a host of the containing shadow root is scope, matches.
return root->host() == context.scope; return root == context.scope;
} }
static inline bool nextSelectorExceedsScope(const SelectorChecker::SelectorCheckingContext& context) static inline bool nextSelectorExceedsScope(const SelectorChecker::SelectorCheckingContext& context)
{ {
if ((context.behaviorAtBoundary & SelectorChecker::BoundaryBehaviorMask) != SelectorChecker::StaysWithinTreeScope)
return context.element == context.scope;
if (context.scope && context.scope->isInShadowTree()) if (context.scope && context.scope->isInShadowTree())
return context.element == context.scope->containingShadowRoot()->host(); return context.element == context.scope->shadowHost();
return false; return false;
} }
...@@ -342,7 +340,7 @@ SelectorChecker::Match SelectorChecker::matchForRelation(const SelectorCheckingC ...@@ -342,7 +340,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->treeScope() == context.element->treeScope() && (context.behaviorAtBoundary & BoundaryBehaviorMask) != StaysWithinTreeScope) if (context.scope && context.scope->shadowHost() && context.scope->shadowHost()->treeScope() == context.element->treeScope() && (context.behaviorAtBoundary & BoundaryBehaviorMask) != StaysWithinTreeScope)
return SelectorFailsCompletely; return SelectorFailsCompletely;
Element* shadowHost = context.element->shadowHost(); Element* shadowHost = context.element->shadowHost();
...@@ -389,15 +387,16 @@ SelectorChecker::Match SelectorChecker::matchForShadowDistributed(const Element* ...@@ -389,15 +387,16 @@ SelectorChecker::Match SelectorChecker::matchForShadowDistributed(const Element*
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 a given scope is a shadow host of an insertion point but behaviorAtBoundary doesn't have ScopeIsShadowHost, // 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. // we need to update behaviorAtBoundary to make selectors like ":host > ::content" work correctly.
if (m_mode == SharingRules) { if (m_mode == SharingRules) {
nextContext.behaviorAtBoundary = static_cast<BehaviorAtBoundary>(behaviorAtBoundary | ScopeIsShadowHost); nextContext.behaviorAtBoundary = static_cast<BehaviorAtBoundary>(behaviorAtBoundary | ScopeIsShadowRoot);
nextContext.scope = insertionPoints[i]->containingShadowRoot()->shadowHost(); nextContext.scope = insertionPoints[i]->containingShadowRoot();
} else if (scope == insertionPoints[i]->containingShadowRoot()->shadowHost() && !(behaviorAtBoundary & ScopeIsShadowHost)) } else if (scope == insertionPoints[i]->containingShadowRoot() && !(behaviorAtBoundary & ScopeIsShadowRoot)) {
nextContext.behaviorAtBoundary = static_cast<BehaviorAtBoundary>(behaviorAtBoundary | ScopeIsShadowHost); nextContext.behaviorAtBoundary = static_cast<BehaviorAtBoundary>(behaviorAtBoundary | ScopeIsShadowRoot);
else } else {
nextContext.behaviorAtBoundary = behaviorAtBoundary; nextContext.behaviorAtBoundary = behaviorAtBoundary;
}
nextContext.isSubSelector = false; nextContext.isSubSelector = false;
nextContext.elementStyle = 0; nextContext.elementStyle = 0;
...@@ -537,7 +536,8 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib ...@@ -537,7 +536,8 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
bool elementIsHostInItsShadowTree = isHostInItsShadowTree(element, context.behaviorAtBoundary, context.scope); bool elementIsHostInItsShadowTree = isHostInItsShadowTree(element, context.behaviorAtBoundary, 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))
return false; return false;
if (selector.match() == CSSSelector::Tag) if (selector.match() == CSSSelector::Tag)
...@@ -929,7 +929,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib ...@@ -929,7 +929,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
// :host only matches a shadow host when :host is in a shadow tree of the shadow host. // :host only matches a shadow host when :host is in a shadow tree of the shadow host.
if (!context.scope) if (!context.scope)
return false; return false;
const ContainerNode* shadowHost = (context.behaviorAtBoundary & ScopeIsShadowHost) ? context.scope : (context.scope->isInShadowTree() ? context.scope->shadowHost() : 0); const ContainerNode* shadowHost = context.scope->shadowHost();
if (!shadowHost || shadowHost != element) if (!shadowHost || shadowHost != element)
return false; return false;
ASSERT(element.shadow()); ASSERT(element.shadow());
...@@ -947,7 +947,7 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib ...@@ -947,7 +947,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.behaviorAtBoundary = ScopeIsShadowHostInPseudoHostParameter;
subContext.scope = shadowHost; 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;
SelectorCheckingContext hostContext(subContext); SelectorCheckingContext hostContext(subContext);
......
...@@ -53,10 +53,10 @@ public: ...@@ -53,10 +53,10 @@ public:
StaysWithinTreeScope = 2, StaysWithinTreeScope = 2,
BoundaryBehaviorMask = 3, // 2bit for boundary behavior BoundaryBehaviorMask = 3, // 2bit for boundary behavior
ScopeContainsLastMatchedElement = 4, ScopeContainsLastMatchedElement = 4,
ScopeIsShadowHost = 8, ScopeIsShadowRoot = 8,
TreatShadowHostAsNormalScope = 16, TreatShadowHostAsNormalScope = 16,
ScopeIsShadowHostInPseudoHostParameter = ScopeIsShadowHost | TreatShadowHostAsNormalScope ScopeIsShadowHostInPseudoHostParameter = ScopeIsShadowRoot | TreatShadowHostAsNormalScope
}; };
struct SelectorCheckingContext { struct SelectorCheckingContext {
...@@ -179,11 +179,7 @@ inline bool SelectorChecker::checkExactAttribute(const Element& element, const Q ...@@ -179,11 +179,7 @@ inline bool SelectorChecker::checkExactAttribute(const Element& element, const Q
inline bool SelectorChecker::isHostInItsShadowTree(const Element& element, BehaviorAtBoundary behaviorAtBoundary, const ContainerNode* scope) inline bool SelectorChecker::isHostInItsShadowTree(const Element& element, BehaviorAtBoundary behaviorAtBoundary, const ContainerNode* scope)
{ {
if ((behaviorAtBoundary & (ScopeIsShadowHost | TreatShadowHostAsNormalScope)) == ScopeIsShadowHost) return scope && scope->isInShadowTree() && scope->shadowHost() == element;
return scope == element;
if (scope && scope->isInShadowTree())
return scope->shadowHost() == element;
return false;
} }
} }
......
...@@ -79,12 +79,9 @@ void TreeBoundaryCrossingRules::collectTreeBoundaryCrossingRules(Element* elemen ...@@ -79,12 +79,9 @@ void TreeBoundaryCrossingRules::collectTreeBoundaryCrossingRules(Element* elemen
unsigned boundaryBehavior = SelectorChecker::ScopeContainsLastMatchedElement; 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, // If a given scoping node is a shadow root, we should use ScopeIsShadowRoot.
// we should use ScopeIsShadowHost. if (scopingNode && scopingNode->isShadowRoot())
if (scopingNode && scopingNode->isShadowRoot()) { boundaryBehavior |= SelectorChecker::ScopeIsShadowRoot;
boundaryBehavior |= SelectorChecker::ScopeIsShadowHost;
scopingNode = toShadowRoot(scopingNode)->host();
}
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) {
......
...@@ -120,10 +120,8 @@ void ScopedStyleResolver::collectMatchingAuthorRules(ElementRuleCollector& colle ...@@ -120,10 +120,8 @@ void ScopedStyleResolver::collectMatchingAuthorRules(ElementRuleCollector& colle
if (!applyAuthorStyles) if (!applyAuthorStyles)
behaviorAtBoundary |= SelectorChecker::ScopeContainsLastMatchedElement; behaviorAtBoundary |= SelectorChecker::ScopeContainsLastMatchedElement;
if (m_scopingNode.isShadowRoot()) { if (m_scopingNode.isShadowRoot())
scopingNode = toShadowRoot(m_scopingNode).host(); behaviorAtBoundary |= SelectorChecker::ScopeIsShadowRoot;
behaviorAtBoundary |= SelectorChecker::ScopeIsShadowHost;
}
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) {
......
...@@ -39,7 +39,6 @@ namespace WebCore { ...@@ -39,7 +39,6 @@ namespace WebCore {
class MediaQueryEvaluator; class MediaQueryEvaluator;
class PageRuleCollector; class PageRuleCollector;
class ShadowRoot;
class StyleSheetContents; class StyleSheetContents;
// This class selects a RenderStyle for a given element based on a collection of stylesheets. // This class selects a RenderStyle for a given element based on a collection of stylesheets.
......
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