Diff
Modified: trunk/LayoutTests/ChangeLog (250787 => 250788)
--- trunk/LayoutTests/ChangeLog 2019-10-07 20:41:59 UTC (rev 250787)
+++ trunk/LayoutTests/ChangeLog 2019-10-07 20:58:04 UTC (rev 250788)
@@ -1,3 +1,23 @@
+2019-10-07 Ryosuke Niwa <rn...@webkit.org>
+
+ focus pseudo class should match a shadow host whose shadow tree contains the focused element
+ https://bugs.webkit.org/show_bug.cgi?id=202432
+
+ Reviewed by Antti Koivisto.
+
+ Added W3C style testharness tests and ref tests.
+
+ * fast/shadow-dom/direct-focus-pseudo-does-not-match-in-author-stylesheet-expected.txt: Added.
+ * fast/shadow-dom/direct-focus-pseudo-does-not-match-in-author-stylesheet.html: Added.
+ * fast/shadow-dom/focus-pseudo-matches-on-shadow-host-expected.txt: Added.
+ * fast/shadow-dom/focus-pseudo-matches-on-shadow-host.html: Added.
+ * fast/shadow-dom/focus-pseudo-on-shadow-host-1-expected.html: Added.
+ * fast/shadow-dom/focus-pseudo-on-shadow-host-1.html: Added.
+ * fast/shadow-dom/focus-pseudo-on-shadow-host-2-expected.html: Added.
+ * fast/shadow-dom/focus-pseudo-on-shadow-host-2.html: Added.
+ * fast/shadow-dom/focus-pseudo-on-shadow-host-3-expected.html: Added.
+ * fast/shadow-dom/focus-pseudo-on-shadow-host-3.html: Added.
+
2019-10-07 Chris Dumez <cdu...@apple.com>
DOMCache should not prevent pages from entering the back/forward cache
Added: trunk/LayoutTests/fast/shadow-dom/direct-focus-pseudo-does-not-match-in-author-stylesheet-expected.txt (0 => 250788)
--- trunk/LayoutTests/fast/shadow-dom/direct-focus-pseudo-does-not-match-in-author-stylesheet-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/direct-focus-pseudo-does-not-match-in-author-stylesheet-expected.txt 2019-10-07 20:58:04 UTC (rev 250788)
@@ -0,0 +1,14 @@
+This tests that -webkit-direct-focus is not recognized in author stylesheets
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS defaultFocus.matches(":focus") is true
+PASS defaultFocus.matches(":-webkit-direct-focus") threw exception SyntaxError: The string did not match the expected pattern..
+PASS inputInShadowRoot.matches(":focus") is true
+PASS inputInShadowRoot.matches(":-webkit-direct-focus") threw exception SyntaxError: The string did not match the expected pattern..
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
+
Added: trunk/LayoutTests/fast/shadow-dom/direct-focus-pseudo-does-not-match-in-author-stylesheet.html (0 => 250788)
--- trunk/LayoutTests/fast/shadow-dom/direct-focus-pseudo-does-not-match-in-author-stylesheet.html (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/direct-focus-pseudo-does-not-match-in-author-stylesheet.html 2019-10-07 20:58:04 UTC (rev 250788)
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<input id="defaultFocus" autofocus>
+<script>
+
+jsTestIsAsync = true;
+
+description('This tests that -webkit-direct-focus is not recognized in author stylesheets');
+
+let focusedDefault = false;
+function didFocusDefault() { }
+function checkFocusMatch() {
+ if (defaultFocus.matches(':focus')) {
+ focusedDefault = true;
+ didFocusDefault();
+ } else
+ setTimeout(checkFocusMatch, 100);
+}
+defaultFocus.addEventListener('focus', checkFocusMatch);
+
+function waitForFrameToBeFocused(test)
+{
+ return new Promise((resolve) => {
+ if (focusedDefault)
+ resolve();
+ else
+ didFocusDefault = resolve;
+ });
+}
+
+async function runTest() {
+ await waitForFrameToBeFocused();
+
+ shouldBeTrue('defaultFocus.matches(":focus")');
+ shouldThrowErrorName('defaultFocus.matches(":-webkit-direct-focus")', 'SyntaxError');
+
+ const host = document.body.appendChild(document.createElement('div'));
+ const shadowRoot = host.attachShadow({mode: 'closed'});
+ shadowRoot.innerHTML = '<input>';
+ window.inputInShadowRoot = shadowRoot.firstChild;
+ inputInShadowRoot.focus();
+
+ shouldBeTrue('inputInShadowRoot.matches(":focus")');
+ shouldThrowErrorName('inputInShadowRoot.matches(":-webkit-direct-focus")', 'SyntaxError');
+
+ finishJSTest();
+}
+
+window._onload_ = runTest;
+
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/fast/shadow-dom/focus-pseudo-matches-on-shadow-host-expected.txt (0 => 250788)
--- trunk/LayoutTests/fast/shadow-dom/focus-pseudo-matches-on-shadow-host-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/focus-pseudo-matches-on-shadow-host-expected.txt 2019-10-07 20:58:04 UTC (rev 250788)
@@ -0,0 +1,9 @@
+
+
+PASS :focus must not match a shadow host with open mode shadow root that does not contain the focused element
+PASS :focus must match a shadow host with open mode shadow root that contains the focused element
+PASS :focus must not match a shadow host with open mode shadow root contains the focused element assigned to a slot
+PASS :focus must not match a shadow host with closed mode shadow root that does not contain the focused element
+PASS :focus must match a shadow host with closed mode shadow root that contains the focused element
+PASS :focus must not match a shadow host with closed mode shadow root contains the focused element assigned to a slot
+
Added: trunk/LayoutTests/fast/shadow-dom/focus-pseudo-matches-on-shadow-host.html (0 => 250788)
--- trunk/LayoutTests/fast/shadow-dom/focus-pseudo-matches-on-shadow-host.html (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/focus-pseudo-matches-on-shadow-host.html 2019-10-07 20:58:04 UTC (rev 250788)
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta name="author" title="Ryosuke Niwa" href=""
+<meta name="assert" content=":focus should match a shadow host which contains the focused element">
+<link rel="help" href=""
+<script src=""
+<script src=""
+</head>
+<body>
+<input id="defaultFocus" autofocus>
+<div id="log"></div>
+<div id="container"></div>
+<script>
+
+let focusedDefault = false;
+function didFocusDefault() { }
+function checkFocusMatch() {
+ if (defaultFocus.matches(':focus')) {
+ focusedDefault = true;
+ didFocusDefault();
+ } else
+ setTimeout(checkFocusMatch, 100);
+}
+defaultFocus.addEventListener('focus', checkFocusMatch);
+
+function prepare(test)
+{
+ test.add_cleanup(() => {
+ defaultFocus.focus();
+ container.textContent = '';
+ });
+ return new Promise((resolve) => {
+ if (focusedDefault)
+ resolve();
+ else
+ didFocusDefault = resolve;
+ });
+}
+
+function testInMode(mode) {
+ promise_test(async function () {
+ await prepare(this);
+ const host = document.createElement('div');
+ container.appendChild(host);
+ const shadowRoot = host.attachShadow({mode});
+ shadowRoot.innerHTML = '<input>';
+ assert_equals(document.activeElement, defaultFocus);
+ assert_equals(shadowRoot.activeElement, null);
+ assert_false(host.matches(':focus'));
+ }, `:focus must not match a shadow host with ${mode} mode shadow root that does not contain the focused element`);
+
+ promise_test(async function () {
+ await prepare(this);
+ const host = document.createElement('div');
+ document.body.appendChild(host);
+ const shadowRoot = host.attachShadow({mode});
+ shadowRoot.innerHTML = '<input>';
+ shadowRoot.firstChild.focus();
+ assert_equals(document.activeElement, host);
+ assert_equals(shadowRoot.activeElement, shadowRoot.firstChild);
+ assert_true(host.matches(':focus'));
+ }, `:focus must match a shadow host with ${mode} mode shadow root that contains the focused element`);
+
+ promise_test(async function () {
+ await prepare(this);
+ const host = document.createElement('div');
+ container.appendChild(host);
+ const shadowRoot = host.attachShadow({mode});
+ shadowRoot.innerHTML = '<slot>';
+ host.innerHTML = '<input>';
+ host.firstChild.focus();
+ assert_equals(document.activeElement, host.firstChild);
+ assert_equals(shadowRoot.activeElement, null);
+ assert_false(host.matches(':focus'));
+ }, `:focus must not match a shadow host with ${mode} mode shadow root contains the focused element assigned to a slot`);
+
+}
+
+testInMode('open');
+testInMode('closed');
+
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/fast/shadow-dom/focus-pseudo-on-shadow-host-1-expected.html (0 => 250788)
--- trunk/LayoutTests/fast/shadow-dom/focus-pseudo-on-shadow-host-1-expected.html (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/focus-pseudo-on-shadow-host-1-expected.html 2019-10-07 20:58:04 UTC (rev 250788)
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+ <body>
+ <p>Test passes if you see a single 100px by 100px green box below.</p>
+ <div style="width: 100px; height: 100px; background: green;"></div>
+ </body>
+</html>
Added: trunk/LayoutTests/fast/shadow-dom/focus-pseudo-on-shadow-host-1.html (0 => 250788)
--- trunk/LayoutTests/fast/shadow-dom/focus-pseudo-on-shadow-host-1.html (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/focus-pseudo-on-shadow-host-1.html 2019-10-07 20:58:04 UTC (rev 250788)
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta name="author" title="Ryosuke Niwa" href=""
+<meta name="assert" content=":focus should match a shadow host which contains the focused element">
+<link rel="help" href=""
+</head>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<div id="host"></div>
+<style>
+#host { background: red; width: 100px; height: 100px; }
+#host:focus { background: green; }
+</style>
+<script>
+
+const shadowRoot = host.attachShadow({mode: 'closed'});
+shadowRoot.innerHTML = '<div tabindex="0" style="outline: none;"></div>';
+shadowRoot.firstChild.focus();
+
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/fast/shadow-dom/focus-pseudo-on-shadow-host-2-expected.html (0 => 250788)
--- trunk/LayoutTests/fast/shadow-dom/focus-pseudo-on-shadow-host-2-expected.html (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/focus-pseudo-on-shadow-host-2-expected.html 2019-10-07 20:58:04 UTC (rev 250788)
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+ <body>
+ <p>Test passes if you see a single 100px by 100px green box below.</p>
+ <div style="width: 100px; height: 100px; background: green;"></div>
+ </body>
+</html>
Added: trunk/LayoutTests/fast/shadow-dom/focus-pseudo-on-shadow-host-2.html (0 => 250788)
--- trunk/LayoutTests/fast/shadow-dom/focus-pseudo-on-shadow-host-2.html (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/focus-pseudo-on-shadow-host-2.html 2019-10-07 20:58:04 UTC (rev 250788)
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta name="author" title="Ryosuke Niwa" href=""
+<meta name="assert" content=":focus should match a shadow host which contains the focused element">
+<link rel="help" href=""
+</head>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<div id="host"><span>FAIL</span></div>
+<style>
+#host { background: green; width: 100px; height: 100px; }
+#host span { background: red; }
+#host:focus span { background: green; color: green; }
+</style>
+<script>
+
+const shadowRoot = host.attachShadow({mode: 'closed'});
+shadowRoot.innerHTML = '<div tabindex="0" style="outline: none;"><slot></slot></div>';
+shadowRoot.firstChild.focus();
+
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/fast/shadow-dom/focus-pseudo-on-shadow-host-3-expected.html (0 => 250788)
--- trunk/LayoutTests/fast/shadow-dom/focus-pseudo-on-shadow-host-3-expected.html (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/focus-pseudo-on-shadow-host-3-expected.html 2019-10-07 20:58:04 UTC (rev 250788)
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+ <body>
+ <p>Test passes if you see a single 100px by 100px green box below.</p>
+ <div style="width: 100px; height: 100px; background: green;"></div>
+ </body>
+</html>
Added: trunk/LayoutTests/fast/shadow-dom/focus-pseudo-on-shadow-host-3.html (0 => 250788)
--- trunk/LayoutTests/fast/shadow-dom/focus-pseudo-on-shadow-host-3.html (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/focus-pseudo-on-shadow-host-3.html 2019-10-07 20:58:04 UTC (rev 250788)
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta name="author" title="Ryosuke Niwa" href=""
+<meta name="assert" content=":focus should not match a shadow host if the focused element is a slotted content">
+<link rel="help" href=""
+</head>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<div id="host"><div id="target" tabindex="0"></div></div>
+<style>
+#host { background: green; width: 100px; height: 100px; }
+#host:focus #target { background: red; width: 100px; height: 100px; }
+#target { outline: none; }
+</style>
+<script>
+
+const shadowRoot = host.attachShadow({mode: 'closed'});
+shadowRoot.innerHTML = '<slot></slot>';
+target.focus();
+
+</script>
+</body>
+</html>
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/shadow-dom/focus/focus-selector-delegatesFocus-expected.txt (250787 => 250788)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/shadow-dom/focus/focus-selector-delegatesFocus-expected.txt 2019-10-07 20:41:59 UTC (rev 250787)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/shadow-dom/focus/focus-selector-delegatesFocus-expected.txt 2019-10-07 20:58:04 UTC (rev 250788)
@@ -1,12 +1,12 @@
foo
foo
-FAIL :focus applies to host with delegatesFocus=true when the shadow root's descendant has focus assert_true: host matches :focus expected true got false
+PASS :focus applies to host with delegatesFocus=true when the shadow root's descendant has focus
FAIL :focus applies to host with delegatesFocus=true when slotted element has focus assert_true: host matches :focus expected true got false
-FAIL :focus applies to host with delegatesFocus=true when an element in a nested shadow tree with delegatesFocus=true is focused assert_true: host of nested shadow tree matches focus expected true got false
-FAIL :focus applies to host with delegatesFocus=true when an element in a nested shadow tree with delegatesFocus=false is focused assert_true: host of nested shadow tree matches focus expected true got false
-FAIL :focus applies to host with delegatesFocus=false when the shadow root's descendant has focus assert_true: host matches :focus expected true got false
+PASS :focus applies to host with delegatesFocus=true when an element in a nested shadow tree with delegatesFocus=true is focused
+PASS :focus applies to host with delegatesFocus=true when an element in a nested shadow tree with delegatesFocus=false is focused
+PASS :focus applies to host with delegatesFocus=false when the shadow root's descendant has focus
FAIL :focus applies to host with delegatesFocus=false when slotted element has focus assert_true: host matches :focus expected true got false
-FAIL :focus applies to host with delegatesFocus=false when an element in a nested shadow tree with delegatesFocus=true is focused assert_true: host of nested shadow tree matches focus expected true got false
-FAIL :focus applies to host with delegatesFocus=false when an element in a nested shadow tree with delegatesFocus=false is focused assert_true: host of nested shadow tree matches focus expected true got false
+PASS :focus applies to host with delegatesFocus=false when an element in a nested shadow tree with delegatesFocus=true is focused
+PASS :focus applies to host with delegatesFocus=false when an element in a nested shadow tree with delegatesFocus=false is focused
Modified: trunk/Source/WebCore/ChangeLog (250787 => 250788)
--- trunk/Source/WebCore/ChangeLog 2019-10-07 20:41:59 UTC (rev 250787)
+++ trunk/Source/WebCore/ChangeLog 2019-10-07 20:58:04 UTC (rev 250788)
@@ -1,3 +1,53 @@
+2019-10-07 Ryosuke Niwa <rn...@webkit.org>
+
+ focus pseudo class should match a shadow host whose shadow tree contains the focused element
+ https://bugs.webkit.org/show_bug.cgi?id=202432
+
+ Reviewed by Antti Koivisto.
+
+ Note that focus pseudo class does not match a shadow host when its shadow tree contains a slot element
+ with a focused element or its ancestor assigned since such a shadow host has the actual focused element
+ in the same tree as the shadow host. (e.g. the focused element can be a direct child of the host).
+
+ In order to preserve the behavior of focus ring, which should be only drawn on the currently focused
+ element and not any shadow host which contains such an element, this patch introduces a new pseudo class,
+ -webkit-direct-focus, which is only available in the user agent stylesheet. Putting :host(:focus) rule
+ isn't sufficient because style rules inside shadow trees always has a lower precendence than rules
+ outside the shadow tree (the tree of its shadow host).
+
+ [1] Also see https://github.com/whatwg/html/pull/4731
+
+ Tests: fast/shadow-dom/direct-focus-pseudo-does-not-match-in-author-stylesheet.html
+ fast/shadow-dom/focus-pseudo-matches-on-shadow-host.html
+ fast/shadow-dom/focus-pseudo-on-shadow-host-1.html
+ fast/shadow-dom/focus-pseudo-on-shadow-host-2.html
+ fast/shadow-dom/focus-pseudo-on-shadow-host-3.html
+
+ * css/CSSSelector.cpp:
+ (WebCore::CSSSelector::selectorText const): Added the support for -webkit-direct-focus.
+ * css/CSSSelector.h:
+ * css/RuleSet.cpp:
+ (WebCore::RuleSet::addRule): Ditto.
+ * css/SelectorChecker.cpp:
+ (WebCore::SelectorChecker::checkOne const):: Ditto.
+ (WebCore::doesShadowTreeContainFocusedElement):: Ditto.
+ (WebCore::SelectorChecker::matchesFocusPseudoClass): Implemented the new behavior.
+ (WebCore::SelectorChecker::matchesDirectFocusPseudoClass): Added. Implements the old behavior for
+ the focus ring via -webkit-direct-focus pseudo class.
+ * css/SelectorChecker.h:
+ * css/SelectorPseudoClassAndCompatibilityElementMap.in: Added -webkit-direct-focus.
+ * css/html.css: Use -webkit-direct-focus pseudo class to preserve the existing behavior of focus ring.
+ * css/parser/CSSSelectorParser.cpp:
+ (WebCore::CSSSelectorParser::consumePseudo): Ignore -webkit-direct-focus in author and user stylesheets.
+ * cssjit/SelectorCompiler.cpp:
+ (WebCore::SelectorCompiler::addPseudoClassType): Added the support for -webkit-direct-focus.
+ * dom/Element.cpp:
+ (WebCore::Element::setFocus): Invoke setContainsFocusedElement on each shadow ancestor root of
+ the newly focused element. Note that we can't use :focus-within pseudo class since that would also match
+ the host of a shadow root which contains a slotted focused element, causing both the shadow host and
+ the slotted element to match :focus pseudo class in the host's tree.
+ * dom/ShadowRoot.h:
+
2019-10-07 Rob Buis <rb...@igalia.com>
Change Response's statusText's default
Modified: trunk/Source/WebCore/css/CSSSelector.cpp (250787 => 250788)
--- trunk/Source/WebCore/css/CSSSelector.cpp 2019-10-07 20:41:59 UTC (rev 250787)
+++ trunk/Source/WebCore/css/CSSSelector.cpp 2019-10-07 20:58:04 UTC (rev 250788)
@@ -438,6 +438,9 @@
case CSSSelector::PseudoClassAutofillStrongPasswordViewable:
str.appendLiteral(":-webkit-autofill-strong-password-viewable");
break;
+ case CSSSelector::PseudoClassDirectFocus:
+ str.appendLiteral(":-webkit-direct-focus");
+ break;
case CSSSelector::PseudoClassDrag:
str.appendLiteral(":-webkit-drag");
break;
Modified: trunk/Source/WebCore/css/CSSSelector.h (250787 => 250788)
--- trunk/Source/WebCore/css/CSSSelector.h 2019-10-07 20:41:59 UTC (rev 250787)
+++ trunk/Source/WebCore/css/CSSSelector.h 2019-10-07 20:58:04 UTC (rev 250788)
@@ -110,6 +110,7 @@
PseudoClassAutofillStrongPassword,
PseudoClassAutofillStrongPasswordViewable,
PseudoClassHover,
+ PseudoClassDirectFocus,
PseudoClassDrag,
PseudoClassFocus,
PseudoClassFocusWithin,
Modified: trunk/Source/WebCore/css/RuleSet.cpp (250787 => 250788)
--- trunk/Source/WebCore/css/RuleSet.cpp 2019-10-07 20:41:59 UTC (rev 250787)
+++ trunk/Source/WebCore/css/RuleSet.cpp 2019-10-07 20:58:04 UTC (rev 250788)
@@ -278,6 +278,7 @@
case CSSSelector::PseudoClassAnyLinkDeprecated:
linkSelector = selector;
break;
+ case CSSSelector::PseudoClassDirectFocus:
case CSSSelector::PseudoClassFocus:
focusSelector = selector;
break;
Modified: trunk/Source/WebCore/css/SelectorChecker.cpp (250787 => 250788)
--- trunk/Source/WebCore/css/SelectorChecker.cpp 2019-10-07 20:41:59 UTC (rev 250787)
+++ trunk/Source/WebCore/css/SelectorChecker.cpp 2019-10-07 20:58:04 UTC (rev 250788)
@@ -985,6 +985,8 @@
if (context.inFunctionalPseudoClass)
return false;
return element.isLink() && context.visitedMatchType == VisitedMatchType::Enabled;
+ case CSSSelector::PseudoClassDirectFocus:
+ return matchesDirectFocusPseudoClass(element);
case CSSSelector::PseudoClassDrag:
addStyleRelation(checkingContext, element, Style::Relation::AffectedByDrag);
@@ -1282,10 +1284,27 @@
return element.document().frame() && element.document().frame()->selection().isFocusedAndActive();
}
+static bool doesShadowTreeContainFocusedElement(const Element& element)
+{
+ auto* shadowRoot = element.shadowRoot();
+ return shadowRoot && shadowRoot->containsFocusedElement();
+}
+
bool SelectorChecker::matchesFocusPseudoClass(const Element& element)
{
if (InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoClassFocus))
return true;
+
+ return (element.focused() || doesShadowTreeContainFocusedElement(element)) && isFrameFocused(element);
+}
+
+// This needs to match a subset of elements matchesFocusPseudoClass match since direct focus is treated
+// as a part of focus pseudo class selectors in ElementRuleCollector::collectMatchingRules.
+bool SelectorChecker::matchesDirectFocusPseudoClass(const Element& element)
+{
+ if (InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoClassFocus))
+ return true;
+
return element.focused() && isFrameFocused(element);
}
Modified: trunk/Source/WebCore/css/SelectorChecker.h (250787 => 250788)
--- trunk/Source/WebCore/css/SelectorChecker.h 2019-10-07 20:41:59 UTC (rev 250787)
+++ trunk/Source/WebCore/css/SelectorChecker.h 2019-10-07 20:58:04 UTC (rev 250788)
@@ -97,6 +97,7 @@
static bool isCommonPseudoClassSelector(const CSSSelector*);
static bool matchesFocusPseudoClass(const Element&);
+ static bool matchesDirectFocusPseudoClass(const Element&);
static bool attributeSelectorMatches(const Element&, const QualifiedName&, const AtomString& attributeValue, const CSSSelector&);
enum LinkMatchMask { MatchDefault = 0, MatchLink = 1, MatchVisited = 2, MatchAll = MatchLink | MatchVisited };
Modified: trunk/Source/WebCore/css/SelectorPseudoClassAndCompatibilityElementMap.in (250787 => 250788)
--- trunk/Source/WebCore/css/SelectorPseudoClassAndCompatibilityElementMap.in 2019-10-07 20:41:59 UTC (rev 250787)
+++ trunk/Source/WebCore/css/SelectorPseudoClassAndCompatibilityElementMap.in 2019-10-07 20:58:04 UTC (rev 250788)
@@ -4,6 +4,7 @@
-webkit-autofill
-webkit-autofill-strong-password
-webkit-autofill-strong-password-viewable
+-webkit-direct-focus
-webkit-drag
-webkit-full-page-media
active
Modified: trunk/Source/WebCore/css/html.css (250787 => 250788)
--- trunk/Source/WebCore/css/html.css 2019-10-07 20:41:59 UTC (rev 250787)
+++ trunk/Source/WebCore/css/html.css 2019-10-07 20:58:04 UTC (rev 250788)
@@ -1165,7 +1165,7 @@
/* states */
-:focus {
+:-webkit-direct-focus {
#if defined(WTF_PLATFORM_IOS_FAMILY) && WTF_PLATFORM_IOS_FAMILY
outline: auto 3px -webkit-focus-ring-color;
#else
Modified: trunk/Source/WebCore/css/parser/CSSSelectorParser.cpp (250787 => 250788)
--- trunk/Source/WebCore/css/parser/CSSSelectorParser.cpp 2019-10-07 20:41:59 UTC (rev 250787)
+++ trunk/Source/WebCore/css/parser/CSSSelectorParser.cpp 2019-10-07 20:58:04 UTC (rev 250788)
@@ -494,10 +494,16 @@
if (colons == 1) {
selector = CSSParserSelector::parsePseudoClassSelector(token.value());
+ if (!selector)
+ return nullptr;
+ if (selector->match() == CSSSelector::PseudoClass) {
+ if (m_context.mode != UASheetMode && selector->pseudoClassType() == CSSSelector::PseudoClassDirectFocus)
+ return nullptr;
#if ENABLE(ATTACHMENT_ELEMENT)
- if (!m_context.attachmentEnabled && selector && selector->match() == CSSSelector::PseudoClass && selector->pseudoClassType() == CSSSelector::PseudoClassHasAttachment)
- return nullptr;
+ if (!m_context.attachmentEnabled && selector->pseudoClassType() == CSSSelector::PseudoClassHasAttachment)
+ return nullptr;
#endif
+ }
} else {
selector = CSSParserSelector::parsePseudoElementSelector(token.value());
#if ENABLE(VIDEO_TRACK)
Modified: trunk/Source/WebCore/cssjit/SelectorCompiler.cpp (250787 => 250788)
--- trunk/Source/WebCore/cssjit/SelectorCompiler.cpp 2019-10-07 20:41:59 UTC (rev 250787)
+++ trunk/Source/WebCore/cssjit/SelectorCompiler.cpp 2019-10-07 20:58:04 UTC (rev 250788)
@@ -558,6 +558,9 @@
case CSSSelector::PseudoClassDefined:
fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr<CSSOperationPtrTag>(isDefinedElement));
return FunctionType::SimpleSelectorChecker;
+ case CSSSelector::PseudoClassDirectFocus:
+ fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr<CSSOperationPtrTag>(SelectorChecker::matchesDirectFocusPseudoClass));
+ return FunctionType::SimpleSelectorChecker;
case CSSSelector::PseudoClassFocus:
fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr<CSSOperationPtrTag>(SelectorChecker::matchesFocusPseudoClass));
return FunctionType::SimpleSelectorChecker;
Modified: trunk/Source/WebCore/dom/Element.cpp (250787 => 250788)
--- trunk/Source/WebCore/dom/Element.cpp 2019-10-07 20:41:59 UTC (rev 250787)
+++ trunk/Source/WebCore/dom/Element.cpp 2019-10-07 20:58:04 UTC (rev 250788)
@@ -677,6 +677,12 @@
document().userActionElements().setFocused(*this, flag);
invalidateStyleForSubtree();
+ // Shadow host with a slot that contain focused element is not considered focused.
+ for (auto* root = containingShadowRoot(); root; root = root->host()->containingShadowRoot()) {
+ root->setContainsFocusedElement(flag);
+ root->host()->invalidateStyle();
+ }
+
for (Element* element = this; element; element = element->parentElementInComposedTree())
element->setHasFocusWithin(flag);
}
Modified: trunk/Source/WebCore/dom/ShadowRoot.h (250787 => 250788)
--- trunk/Source/WebCore/dom/ShadowRoot.h 2019-10-07 20:41:59 UTC (rev 250787)
+++ trunk/Source/WebCore/dom/ShadowRoot.h 2019-10-07 20:58:04 UTC (rev 250788)
@@ -61,6 +61,9 @@
bool resetStyleInheritance() const { return m_resetStyleInheritance; }
void setResetStyleInheritance(bool);
+ bool containsFocusedElement() const { return m_containsFocusedElement; }
+ void setContainsFocusedElement(bool flag) { m_containsFocusedElement = flag; }
+
Element* host() const { return m_host; }
void setHost(Element* host) { m_host = host; }
@@ -113,6 +116,7 @@
bool m_resetStyleInheritance { false };
bool m_hasBegunDeletingDetachedChildren { false };
+ bool m_containsFocusedElement { false };
ShadowRootMode m_type { ShadowRootMode::UserAgent };
Element* m_host { nullptr };