Commit fef81767 authored by esprehn@chromium.org's avatar esprehn@chromium.org

Only :host and :ancestor should ever match the host in a ShadowRoot

We were blocking tag, id and class from matching when put before :host, but were
not correctly stopping things like :first-child:host or *:host.

Instead of trying to black list selectors we need to whitelist :host and
:ancestor as being special.

It turns out we did have test coverage for this, but the expected results were
all wrong so it printed PASS even though we were failing what the test was
supposed to be testing.

BUG=355149, 355158

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

git-svn-id: svn://svn.chromium.org/blink/trunk@169799 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 74420b3c
......@@ -6,7 +6,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
:ancestor out of shadow tree should not match any shadow hosts.
PASS backgroundColorOf('host') is "rgba(0, 0, 0, 0)"
:ancestor with * should not match any shadow hosts.
PASS backgroundColorOf('host') is "rgb(0, 128, 0)"
PASS backgroundColorOf('host') is "rgba(0, 0, 0, 0)"
:ancestor with tag selector should not match any shadow hosts.
PASS backgroundColorOf('host') is "rgba(0, 0, 0, 0)"
:ancestor with class selector should not match any shadow hosts.
......
......@@ -53,7 +53,7 @@ sandbox.appendChild(
createDOM('div', {},
document.createTextNode('Hello')))));
backgroundColorShouldBe('host', 'rgb(0, 128, 0)');
backgroundColorShouldBe('host', 'rgba(0, 0, 0, 0)');
cleanUp();
......
......@@ -6,7 +6,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
:host out of shadow tree should not match any shadow hosts.
PASS backgroundColorOf('host') is "rgba(0, 0, 0, 0)"
:host with * should not match any shadow hosts.
PASS backgroundColorOf('host') is "rgb(0, 128, 0)"
PASS backgroundColorOf('host') is "rgba(0, 0, 0, 0)"
:host with tag selector should not match any shadow hosts.
PASS backgroundColorOf('host') is "rgba(0, 0, 0, 0)"
:host with class selector should not match any shadow hosts.
......
......@@ -53,7 +53,7 @@ sandbox.appendChild(
createDOM('div', {},
document.createTextNode('Hello')))));
backgroundColorShouldBe('host', 'rgb(0, 128, 0)');
backgroundColorShouldBe('host', 'rgba(0, 0, 0, 0)');
cleanUp();
......
......@@ -9,9 +9,11 @@ PASS borderColorOf('host-child') is "rgb(0, 0, 0)"
Test that * in a shadow tree cannot match without :host.
PASS borderColorOf('host') is not "rgb(0, 128, 0)"
PASS borderColorOf('host-child') is "rgb(0, 0, 0)"
Test that :not(*) in a shadow tree can match without :host.
PASS borderColorOf('host') is "rgb(0, 128, 0)"
Test that :not(*) in a shadow tree cannot match without :host.
PASS borderColorOf('host') is "rgb(0, 0, 0)"
PASS borderColorOf('host-child') is "rgb(0, 0, 0)"
Test that :first-child in a shadow tree cannot match without :host.
PASS borderColorOf('host') is "rgb(0, 0, 0)"
Test that styles in a containing treescope wins if specificities are the same.
PASS borderColorOf('host') is "rgb(0, 128, 0)"
Test that rules which has higher specificity win.
......
......@@ -63,7 +63,7 @@ shouldHaveBorderColor('host-child', 'rgb(0, 0, 0)');
cleanUp();
debug('Test that :not(*) in a shadow tree can match without :host.');
debug('Test that :not(*) in a shadow tree cannot match without :host.');
sandbox.appendChild(
createDOM('div', {'id': 'host'},
......@@ -74,11 +74,26 @@ sandbox.appendChild(
createDOM('div', {'id': 'host-child'},
document.createTextNode('Hello, Host!'))));
shouldHaveBorderColor('host', 'rgb(0, 128, 0)');
shouldHaveBorderColor('host', 'rgb(0, 0, 0)');
shouldHaveBorderColor('host-child', 'rgb(0, 0, 0)');
cleanUp();
debug('Test that :first-child in a shadow tree cannot match without :host.');
sandbox.appendChild(
createDOM('div', {'id': 'host'},
createShadowRoot(
createDOM('style', {},
document.createTextNode(':first-child { border: 1px solid green; }')),
createDOM('content', {})),
createDOM('div', {'id': 'host-child'},
document.createTextNode('Hello, Host!'))));
shouldHaveBorderColor('host', 'rgb(0, 0, 0)');
cleanUp();
debug('Test that styles in a containing treescope wins if specificities are the same.');
sandbox.appendChild(
......
......@@ -258,4 +258,14 @@ CSSParserSelector* CSSParserSelector::findDistributedPseudoElementSelector() con
return 0;
}
bool CSSParserSelector::hasHostPseudoSelector() const
{
CSSParserSelector* selector = const_cast<CSSParserSelector*>(this);
do {
if (selector->pseudoType() == CSSSelector::PseudoHost || selector->pseudoType() == CSSSelector::PseudoAncestor)
return true;
} while ((selector = selector->tagHistory()));
return false;
}
} // namespace WebCore
......@@ -233,6 +233,7 @@ public:
void setFunctionArgumentSelector(CSSParserSelector* selector) { m_functionArgumentSelector = selector; }
bool isDistributedPseudoElement() const { return m_selector->isDistributedPseudoElement(); }
CSSParserSelector* findDistributedPseudoElementSelector() const;
bool hasHostPseudoSelector() const;
CSSSelector::PseudoType pseudoType() const { return m_selector->pseudoType(); }
bool isCustomPseudoElement() const { return m_selector->isCustomPseudoElement(); }
......
......@@ -386,7 +386,7 @@ inline bool CSSSelector::isCustomPseudoElement() const
inline bool CSSSelector::isHostPseudoClass() const
{
return m_match == PseudoClass && m_pseudoType == PseudoHost;
return m_match == PseudoClass && (m_pseudoType == PseudoHost || m_pseudoType == PseudoAncestor);
}
inline bool CSSSelector::isSiblingSelector() const
......
......@@ -490,18 +490,20 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
bool elementIsHostInItsShadowTree = isHostInItsShadowTree(element, context.behaviorAtBoundary, context.scope);
// Only :host and :ancestor should match the host: http://drafts.csswg.org/css-scoping/#host-element
if (elementIsHostInItsShadowTree && !selector.isHostPseudoClass())
return false;
if (selector.m_match == CSSSelector::Tag)
return SelectorChecker::tagMatches(element, selector.tagQName()) && !elementIsHostInItsShadowTree;
return SelectorChecker::tagMatches(element, selector.tagQName());
if (selector.m_match == CSSSelector::Class)
return element.hasClass() && element.classNames().contains(selector.value()) && !elementIsHostInItsShadowTree;
return element.hasClass() && element.classNames().contains(selector.value());
if (selector.m_match == CSSSelector::Id)
return element.hasID() && element.idForStyleResolution() == selector.value() && !elementIsHostInItsShadowTree;
return element.hasID() && element.idForStyleResolution() == selector.value();
if (selector.isAttributeSelector()) {
if (elementIsHostInItsShadowTree)
return false;
if (!anyAttributeMatches(element, static_cast<CSSSelector::Match>(selector.m_match), selector))
return false;
}
......
......@@ -1934,9 +1934,11 @@ CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithElementName(const Atomic
if (specifiers->needsCrossingTreeScopeBoundary())
return rewriteSpecifiersWithElementNameForCustomPseudoElement(tag, elementName, specifiers, tagIsForNamespaceRule);
if (tag == anyQName())
// *:host never matches, so we can't discard the * otherwise we can't tell the
// difference between *:host and just :host.
if (tag == anyQName() && !specifiers->hasHostPseudoSelector())
return specifiers;
if (!(specifiers->pseudoType() == CSSSelector::PseudoCue))
if (specifiers->pseudoType() != CSSSelector::PseudoCue)
specifiers->prependTagSelector(tag, tagIsForNamespaceRule);
return specifiers;
}
......
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