Commit a8956b2e authored by tasak@google.com's avatar tasak@google.com

Revert "Reverting custom pseudo element".

This is not the same as a patch for just reverting r164153.
To make a patch smaller,
- Element IDL does not have webkitPseudo (not reverted).
- pseudo() invokes shadowPseudoId() (the old code uses pseudo() in shadowPseudoId()).
- setPseudo() also invokes setShadowPseudoId().

c.f. https://src.chromium.org/viewvc/blink?revision=164153&view=revision

BUG=349144
TEST=fast/dom/shadow/pseudo-attribute-rendering.html,fast/dom/shadow/styling-pseudo-attribute.html,fast/dom/shadow/shadow-pseudo-id.html,fast/dom/shadow/pseudo-attribute.html,fast/dom/shadow/styling-pseudo-attribute-in-shadow.html,fast/dom/shadow/shadow-nested-pseudo-id.html,fast/dom/shadow/custom-pseudo-in-selector-api.html,fast/dom/shadow/pseudo-attribute-dynamic.html

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

git-svn-id: svn://svn.chromium.org/blink/trunk@168627 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 18a6dfc2
......@@ -6,6 +6,12 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
PASS sandbox.firstChild.webkitMatchesSelector("input[type='search']::-webkit-search-decoration") is false
PASS sandbox.firstChild.querySelector("input[type='search']::-webkit-search-decoration") is null
PASS sandbox.firstChild.querySelectorAll("input[type='search']::-webkit-search-decoration").length is 0
PASS sandbox.firstChild.webkitMatchesSelector("div::x-pseudo") is false
PASS sandbox.firstChild.webkitMatchesSelector("div::x-part") is false
PASS sandbox.firstChild.querySelector("div::x-pseudo") is null
PASS sandbox.firstChild.querySelector("div::x-part") is null
PASS sandbox.firstChild.querySelectorAll("div::x-pseudo").length is 0
PASS sandbox.firstChild.querySelectorAll("div::x-part").length is 0
PASS successfullyParsed is true
TEST COMPLETE
......
......@@ -17,6 +17,20 @@ shouldBeFalse('sandbox.firstChild.webkitMatchesSelector("input[type=\'search\']:
shouldBeNull('sandbox.firstChild.querySelector("input[type=\'search\']::-webkit-search-decoration")');
shouldBe('sandbox.firstChild.querySelectorAll("input[type=\'search\']::-webkit-search-decoration").length', '0');
sandbox.innerHTML = '';
sandbox.appendChild(
createDOM('div', {'id': 'host'},
createShadowRoot(
createDOM('div', {'pseudo': 'x-pseudo', 'part': 'x-part'}))));
shouldBeFalse('sandbox.firstChild.webkitMatchesSelector("div::x-pseudo")');
shouldBeFalse('sandbox.firstChild.webkitMatchesSelector("div::x-part")');
shouldBeNull('sandbox.firstChild.querySelector("div::x-pseudo")');
shouldBeNull('sandbox.firstChild.querySelector("div::x-part")');
shouldBe('sandbox.firstChild.querySelectorAll("div::x-pseudo").length', '0');
shouldBe('sandbox.firstChild.querySelectorAll("div::x-part").length', '0');
sandbox.innerHTML = '';
</script>
</body>
......
<!DOCTYPE html>
<html>
<body>
<p>This test checks dynamic 'pseudo' attribute should reflect style.</p>
<div><div style="color: blue;">This should be blue.</div></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<style>
#host::x-foo {
color: red;
}
#host::x-bar {
color: blue;
}
</style>
</head>
<body>
<p>This test checks dynamic 'pseudo' attribute should reflect style.</p>
<div id="host"></div>
<script>
if (window.testRunner)
testRunner.waitUntilDone();
var shadowRoot = host.createShadowRoot();
var div = document.createElement('div');
div.pseudo = 'x-foo';
div.innerHTML = "This should be blue.";
shadowRoot.appendChild(div);
setTimeout(function() {
div.pseudo = 'x-bar';
if (window.testRunner)
testRunner.notifyDone();
}, 0);
</script>
</body>
</html>
This test checks pseudo attribute is exposed correctly.
PASS div.pseudo is ''
PASS div.getAttribute('pseudo') is null
PASS div.pseudo is 'foo'
PASS div.getAttribute('pseudo') is 'foo'
PASS div.pseudo is 'bar'
PASS div.getAttribute('pseudo') is 'bar'
PASS div.pseudo is ''
PASS div.getAttribute('pseudo') is null
PASS div.pseudo is 'first-letter'
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<html>
<body>
<p>This test checks element.pseudo starting '-webkit-' only works in UserAgentShadowRoot.</p>
<div><div style="color: red">This text should be red.</div></div>
<div><div>This text should not be red.</div></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<style>
div::x-foo {
color: red;
}
div::-webkit-foobar {
color: red;
}
</style>
</head>
<body>
<p>This test checks element.pseudo starting '-webkit-' only works in UserAgentShadowRoot.</p>
<div id="host1"></div>
<div id="host2"></div>
<script>
var shadowRoot1 = host1.createShadowRoot();
var div1 = document.createElement('div');
div1.pseudo = 'x-foo';
div1.innerHTML = "This text should be red.";
shadowRoot1.appendChild(div1);
var shadowRoot2 = host2.createShadowRoot();
var div2 = document.createElement('div');
div2.pseudo = '-webkit-foobar';
div2.innerHTML = "This text should not be red.";
shadowRoot2.appendChild(div2);
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<body>
<script src="../../../resources/js-test.js"></script>
<p>This test checks pseudo attribute is exposed correctly.</p>
<pre id="console"></pre>
<script>
var div = document.createElement('div');
shouldBe("div.pseudo", "''");
shouldBe("div.getAttribute('pseudo')", "null");
div.setAttribute("pseudo", "foo");
shouldBe("div.pseudo", "'foo'");
shouldBe("div.getAttribute('pseudo')", "'foo'");
div.pseudo = "bar";
shouldBe("div.pseudo", "'bar'");
shouldBe("div.getAttribute('pseudo')", "'bar'");
div.removeAttribute('pseudo');
shouldBe("div.pseudo", "''");
shouldBe("div.getAttribute('pseudo')", "null");
// Checks pseudo accepts known pseudo-element word.
div.pseudo = 'first-letter';
shouldBe("div.pseudo", "'first-letter'");
finishJSTest();
</script>
</body>
</html>
Nested pseudo id should be matchable
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS window.getComputedStyle(tuple.shadowChild).color is 'rgb(255, 0, 0)'
PASS window.getComputedStyle(shadowTuple.shadowChild).color is 'rgb(255, 0, 0)'
PASS window.getComputedStyle(shadowTuple.shadowChild).backgroundColor is 'rgb(0, 128, 0)'
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<html>
<head>
<script src="../../../resources/js-test.js"></script>
<style>
p::x-shadow-child {
color: red;
}
a::x-nested-shadow-child {
color: blue;
}
p::x-shadow-child::x-nested-shadow-child {
background-color: green;
}
</style>
</head>
<body>
<div id="console"></div>
<p id="host"></div>
<script>
function buildShadowWithOneChild(host, childTagName, childPseudoId)
{
var shadow = host.createShadowRoot();
var shadowChild = document.createElement(childTagName);
shadow.appendChild(shadowChild);
shadowChild.setAttribute("pseudo", childPseudoId);
return { host: host, shadow: shadow, shadowChild: shadowChild };
}
description("Nested pseudo id should be matchable");
if (!window.internals)
fail("You need window.internals to run this test");
var host = document.getElementById("host");
var tuple = buildShadowWithOneChild(host, "a", "x-shadow-child");
shouldBe("window.getComputedStyle(tuple.shadowChild).color", "'rgb(255, 0, 0)'");
var shadowTuple = buildShadowWithOneChild(tuple.shadowChild, "b", "x-nested-shadow-child");
shouldBe("window.getComputedStyle(shadowTuple.shadowChild).color", "'rgb(255, 0, 0)'");
shouldBe("window.getComputedStyle(shadowTuple.shadowChild).backgroundColor", "'rgb(0, 128, 0)'");
var successfullyParsed = true;
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>This test checks a custom pseudo element selector is valid only if it starts with 'x-'</p>
<div id="console"></div>
<div id="host1"><div style="color:red">pseudo is x-shadow: This should be red.</div></div>
<div id="host2"><div>pseudo is -test: This should not be red.</div></div>
<div id="host2"><div>pseudo is foobar: This should not be red.</div></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<style>
div::x-shadow {
color: red;
}
div::-test {
color: red;
}
div::foobar {
color: red;
}
</style>
</head>
<body>
<p>This test checks a custom pseudo element selector is valid only if it starts with 'x-'</p>
<div id="console"></div>
<div id="host1"></div>
<div id="host2"></div>
<div id="host3"></div>
<script>
var shadowRoot1 = host1.createShadowRoot();
var div1 = document.createElement('div');
div1.innerHTML = "pseudo is x-shadow: This should be red.";
div1.pseudo = "x-shadow";
shadowRoot1.appendChild(div1);
var shadowRoot2 = host2.createShadowRoot();
var div2 = document.createElement('div');
div2.innerHTML = "pseudo is -test: This should not be red.";
div2.pseudo = "-test";
shadowRoot2.appendChild(div2);
var shadowRoot3 = host3.createShadowRoot();
var div3 = document.createElement('div');
div3.innerHTML = "pseudo is foobar: This should not be red.";
div3.pseudo = "foobar";
shadowRoot3.appendChild(div3);
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<style>
#target {
color: red;
}
</style>
<div><div id="target">foo bar</div></div>
</html>
<!DOCTYPE html>
<html>
<body>
<div><div style="border: 1px solid green"><div style="border: 2px solid lightgreen">foobar</div></div></div>
</body>
</html>
<!doctype html>
<html>
<head>
<style>
#host::x-foo {
border: 1px solid red;
}
#host-in-shadow::x-foo {
border: 1px solid navy;
}
</style>
</head>
<div id="host1"></div>
<script>
var outerShadowRoot = host1.createShadowRoot();
outerShadowRoot.innerHTML = '<style>#host-in-shadow::x-foo { border: 1px solid green; } #host-in-shadow::x-foo::x-foobar { border: 2px solid lightgreen; }</style><div id="host-in-shadow"></div>';
var innerShadowRoot = outerShadowRoot.getElementById('host-in-shadow').createShadowRoot();
innerShadowRoot.innerHTML = '<div pseudo="x-foo" id="host-in-inner-shadow">foo</div>';
var innerMostShadowRoot = innerShadowRoot.getElementById('host-in-inner-shadow').createShadowRoot();
innerMostShadowRoot.innerHTML = '<div pseudo="x-foobar">foobar</div>';
</script>
</html>
<!DOCTYPE html>
<html>
<style>
#host1::x-foo {
color: red;
}
</style>
<div id="host1"></div>
<script>
var shadowRoot1 = host1.createShadowRoot();
var div = document.createElement('div');
div.setAttribute('pseudo', 'x-foo');
div.appendChild(document.createTextNode('foo bar'));
shadowRoot1.appendChild(div);
</script>
</html>
......@@ -483,7 +483,7 @@ CSSSelector::PseudoType CSSSelector::parsePseudoType(const AtomicString& name)
if (name.startsWith("-webkit-"))
return PseudoWebKitCustomElement;
if (name.startsWith("cue"))
if (name.startsWith("x-") || name.startsWith("cue"))
return PseudoUserAgentCustomElement;
return PseudoUnknown;
......
......@@ -69,11 +69,12 @@ SelectorChecker::SelectorChecker(Document& document, Mode mode)
static bool matchesCustomPseudoElement(const Element* element, const CSSSelector& selector)
{
ShadowRoot* root = element->containingShadowRoot();
if (!root || root->type() != ShadowRoot::UserAgentShadowRoot)
if (!root)
return false;
if (element->shadowPseudoId() != selector.value())
return false;
if (selector.pseudoType() == CSSSelector::PseudoWebKitCustomElement && root->type() != ShadowRoot::UserAgentShadowRoot)
return false;
return true;
}
......
......@@ -1034,6 +1034,8 @@ void Element::attributeChanged(const QualifiedName& name, const AtomicString& ne
classAttributeChanged(newValue);
} else if (name == HTMLNames::nameAttr) {
setHasName(!newValue.isNull());
} else if (name == HTMLNames::pseudoAttr) {
shouldInvalidateStyle |= testShouldInvalidateStyle && isInShadowTree();
}
invalidateNodeListCachesInAncestors(&name, this);
......@@ -2435,16 +2437,11 @@ String Element::textFromChildren()
const AtomicString& Element::shadowPseudoId() const
{
if (ShadowRoot* root = containingShadowRoot()) {
if (root->type() == ShadowRoot::UserAgentShadowRoot)
return fastGetAttribute(pseudoAttr);
}
return nullAtom;
return getAttribute(pseudoAttr);
}
void Element::setShadowPseudoId(const AtomicString& id)
{
ASSERT(CSSSelector::parsePseudoType(id) == CSSSelector::PseudoWebKitCustomElement || CSSSelector::parsePseudoType(id) == CSSSelector::PseudoUserAgentCustomElement);
setAttribute(pseudoAttr, id);
}
......
......@@ -404,6 +404,8 @@ public:
virtual String title() const { return String(); }
virtual const AtomicString& pseudo() const { return shadowPseudoId(); }
void setPseudo(const AtomicString& value) { setShadowPseudoId(value); }
virtual const AtomicString& shadowPseudoId() const;
void setShadowPseudoId(const AtomicString&);
......
......@@ -111,6 +111,7 @@
[RaisesException, ImplementedAs=matches, MeasureAs=ElementPrefixedMatchesSelector] boolean webkitMatchesSelector(DOMString selectors);
// Shadow DOM API
[RuntimeEnabled=ShadowDOM, Reflect, TreatNullAs=NullString, PerWorldBindings] attribute DOMString pseudo;
[RuntimeEnabled=ShadowDOM, RaisesException] ShadowRoot createShadowRoot();
[RuntimeEnabled=ShadowDOM, PerWorldBindings] readonly attribute ShadowRoot shadowRoot;
[RuntimeEnabled=ShadowDOM, PerWorldBindings] NodeList getDestinationInsertionPoints();
......
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