Commit 4de702b3 authored by rune@opera.com's avatar rune@opera.com

Support invalidation sets for :host pseudo.

Traverse the selectorList() for :host pseudo, extract features, and create
class invalidation sets like we do for features and classes on the top level.

R=esprehn,ojan
BUG=335247,339729

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

git-svn-id: svn://svn.chromium.org/blink/trunk@169927 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 7a99d4dc
Check that targeted class invalidation works with the :host pseudo class.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS getComputedStyle(host1, null).backgroundColor is transparent
PASS getComputedStyle(inner, null).backgroundColor is transparent
PASS getComputedStyle(host3, null).backgroundColor is transparent
PASS getComputedStyle(host4, null).backgroundColor is transparent
PASS internals.updateStyleAndReturnAffectedElementCount() is 1
PASS getComputedStyle(host1, null).backgroundColor is green
PASS internals.updateStyleAndReturnAffectedElementCount() is 2
PASS getComputedStyle(inner, null).backgroundColor is green
PASS internals.updateStyleAndReturnAffectedElementCount() is 6
PASS getComputedStyle(host3, null).backgroundColor is green
PASS internals.updateStyleAndReturnAffectedElementCount() is 1
PASS getComputedStyle(host4, null).backgroundColor is green
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<script src="../../../resources/js-test.js"></script>
<div id="host1"></div>
<div id="host2"></div>
<div id="host3" class="c3"></div>
<div id="host4"></div>
<script>
description("Check that targeted class invalidation works with the :host pseudo class.");
// Create shadow trees
var host1 = document.getElementById("host1");
host1.createShadowRoot().innerHTML = "<style>:host(.c1) { background-color: green }</style><div></div><div></div><div></div><div></div><div></div>";
var host2 = document.getElementById("host2");
host2.createShadowRoot().innerHTML = '<style>:host(.c2) .inner { background-color: green }</style><div></div><div></div><div></div><div><span id="inner" class="inner"></span></div>';
var host3 = document.getElementById("host3");
host3.createShadowRoot().innerHTML = "<style>:host(#host3:not(.c3)) { background-color: green }</style><div></div><div></div><div></div><div></div>";
var host4 = document.getElementById("host4");
host4.createShadowRoot().innerHTML = "<style>:host(.nomatch, .c4) { background-color: green }</style><div></div><div></div><div></div><div></div>";
var transparent = "rgba(0, 0, 0, 0)";
var green = "rgb(0, 128, 0)";
var inner = host2.shadowRoot.getElementById("inner");
shouldBe("getComputedStyle(host1, null).backgroundColor", "transparent");
shouldBe("getComputedStyle(inner, null).backgroundColor", "transparent");
shouldBe("getComputedStyle(host3, null).backgroundColor", "transparent");
shouldBe("getComputedStyle(host4, null).backgroundColor", "transparent");
document.body.offsetLeft; // force style recalc.
host1.className = "c1";
if (window.internals)
shouldBe("internals.updateStyleAndReturnAffectedElementCount()", "1");
shouldBe("getComputedStyle(host1, null).backgroundColor", "green");
document.body.offsetLeft; // force style recalc.
host2.className = "c2";
if (window.internals)
shouldBe("internals.updateStyleAndReturnAffectedElementCount()", "2");
shouldBe("getComputedStyle(inner, null).backgroundColor", "green");
document.body.offsetLeft; // force style recalc.
host3.className = "";
if (window.internals)
shouldBe("internals.updateStyleAndReturnAffectedElementCount()", "6");
shouldBe("getComputedStyle(host3, null).backgroundColor", "green");
document.body.offsetLeft; // force style recalc.
host4.className = "c4";
if (window.internals)
shouldBe("internals.updateStyleAndReturnAffectedElementCount()", "1");
shouldBe("getComputedStyle(host4, null).backgroundColor", "green");
</script>
......@@ -47,7 +47,7 @@ static bool isSkippableComponentForInvalidation(const CSSSelector& selector)
|| selector.isAttributeSelector())
return true;
if (selector.m_match == CSSSelector::PseudoElement) {
switch (selector.m_pseudoType) {
switch (selector.pseudoType()) {
case CSSSelector::PseudoBefore:
case CSSSelector::PseudoAfter:
case CSSSelector::PseudoBackdrop:
......@@ -112,6 +112,16 @@ RuleFeatureSet::InvalidationSetMode RuleFeatureSet::supportsClassDescendantInval
if (component->m_match == CSSSelector::Class || component->isAttributeSelector()) {
if (!foundDescendantRelation)
foundIdent = true;
} else if (component->pseudoType() == CSSSelector::PseudoHost) {
if (const CSSSelectorList* selectorList = component->selectorList()) {
for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(*selector)) {
InvalidationSetMode hostMode = supportsClassDescendantInvalidation(*selector);
if (hostMode == UseSubtreeStyleChange)
return foundDescendantRelation ? UseLocalStyleChange : UseSubtreeStyleChange;
if (hostMode == AddFeatures)
foundIdent = true;
}
}
} else if (!isSkippableComponentForInvalidation(*component)) {
return foundDescendantRelation ? UseLocalStyleChange : UseSubtreeStyleChange;
}
......@@ -168,19 +178,38 @@ RuleFeatureSet::InvalidationSetMode RuleFeatureSet::updateInvalidationSets(const
AtomicString tagName;
Vector<AtomicString> attributes;
const CSSSelector* current = extractInvalidationSetFeatures(selector, classes, id, tagName, attributes);
if (current)
current = current->tagHistory();
if (current)
addFeaturesToInvalidationSets(*current, classes, id, tagName, attributes);
return AddFeatures;
}
const CSSSelector* RuleFeatureSet::extractInvalidationSetFeatures(const CSSSelector& selector, Vector<AtomicString>& classes, AtomicString& id, AtomicString& tagName, Vector<AtomicString>& attributes)
{
const CSSSelector* lastSelector = &selector;
for (; lastSelector; lastSelector = lastSelector->tagHistory()) {
extractClassIdTagOrAttribute(*lastSelector, classes, id, tagName, attributes);
// Initialize the entry in the invalidation set map, if supported.
invalidationSetForSelector(*lastSelector);
if (lastSelector->pseudoType() == CSSSelector::PseudoHost) {
if (const CSSSelectorList* selectorList = lastSelector->selectorList()) {
for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(*selector))
extractInvalidationSetFeatures(*selector, classes, id, tagName, attributes);
}
}
if (lastSelector->relation() != CSSSelector::SubSelector)
break;
}
return lastSelector;
}
if (!lastSelector)
return AddFeatures;
for (const CSSSelector* current = lastSelector->tagHistory(); current; current = current->tagHistory()) {
void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector& selector, const Vector<AtomicString>& classes, AtomicString id, AtomicString tagName, const Vector<AtomicString>& attributes)
{
for (const CSSSelector* current = &selector; current; current = current->tagHistory()) {
if (DescendantInvalidationSet* invalidationSet = invalidationSetForSelector(*current)) {
if (!id.isEmpty())
invalidationSet->addId(id);
......@@ -190,9 +219,13 @@ RuleFeatureSet::InvalidationSetMode RuleFeatureSet::updateInvalidationSets(const
invalidationSet->addClass(*it);
for (Vector<AtomicString>::const_iterator it = attributes.begin(); it != attributes.end(); ++it)
invalidationSet->addAttribute(*it);
} else if (current->pseudoType() == CSSSelector::PseudoHost) {
if (const CSSSelectorList* selectorList = current->selectorList()) {
for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(*selector))
addFeaturesToInvalidationSets(*selector, classes, id, tagName, attributes);
}
}
}
return AddFeatures;
}
void RuleFeatureSet::addContentAttr(const AtomicString& attributeName)
......
......@@ -144,6 +144,8 @@ private:
DescendantInvalidationSet* invalidationSetForSelector(const CSSSelector&);
InvalidationSetMode updateInvalidationSets(const CSSSelector&);
const CSSSelector* extractInvalidationSetFeatures(const CSSSelector&, Vector<AtomicString>& classes, AtomicString& id, AtomicString& tagName, Vector<AtomicString>& attributes);
void addFeaturesToInvalidationSets(const CSSSelector&, const Vector<AtomicString>& classes, AtomicString id, AtomicString tagName, const Vector<AtomicString>& attributes);
void addClassToInvalidationSet(const AtomicString& className, Element*);
......
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