Title: [273812] trunk
Revision
273812
Author
[email protected]
Date
2021-03-02 22:43:53 -0800 (Tue, 02 Mar 2021)

Log Message

[selectors] :focus-visible implementation
https://bugs.webkit.org/show_bug.cgi?id=222028
<rdar://problem/74679243>

Reviewed by Darin Adler.

LayoutTests/imported/w3c:

Update expectations, most of the :focus-visible tests are passing now.

* web-platform-tests/css/selectors/focus-in-focus-event-001-expected.txt:
* web-platform-tests/css/selectors/focus-in-focusin-event-001-expected.txt:
* web-platform-tests/css/selectors/focus-visible-001-expected.txt:
* web-platform-tests/css/selectors/focus-visible-002-expected.txt:
* web-platform-tests/css/selectors/focus-visible-006-expected.txt:
* web-platform-tests/css/selectors/focus-visible-007-expected.txt:
* web-platform-tests/css/selectors/focus-visible-007.html: Import last changes on this test
* web-platform-tests/css/selectors/focus-visible-008-expected.txt:
(see https://github.com/web-platform-tests/wpt/pull/27656).
* web-platform-tests/css/selectors/focus-visible-011-expected.txt:
* web-platform-tests/css/selectors/focus-visible-011.html: Import last changes on this test
(see https://github.com/web-platform-tests/wpt/pull/27700).
* web-platform-tests/css/selectors/focus-visible-013-expected.txt:
* web-platform-tests/css/selectors/focus-visible-014-expected.txt:
* web-platform-tests/css/selectors/focus-visible-016-expected.txt:

Source/WebCore:

Add basic :focus-visible implementation behind the FocusVisibleEnabled experimental feature flag.
This patch implements the heuristics defined in the spec (https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo),
except the ones related to script focus.

Test: imported/w3c/web-platform-tests/css/selectors/focus-visible-*

* css/SelectorCheckerTestFunctions.h:
(WebCore::matchesFocusVisiblePseudoClass): Check element.hasFocusVisible().
* dom/Element.cpp:
(WebCore::Element::setFocus): When an element loses focus it always call setHasFocusVisible(false). When an element gets focused
it calls setHasFocusVisible(true) for elements that support keyboard input (as they always match :focus-visible).
(WebCore::Element::setHasFocusVisible): New method gated behind the experimental flag.
* dom/Element.h:
(WebCore::Element::hasFocusVisible const): Add new method.
* dom/Node.h:
(WebCore::Node::flagHasFocusVisible): Add new flag for :focus-visible matching.
* page/EventHandler.cpp:
(WebCore::EventHandler::internalKeyEvent): If the user interacts with the page via keyboard, call setHasFocusVisible(true).
Avoid that for modifier keys.
* page/FocusController.cpp:
(WebCore::FocusController::advanceFocusInDocumentOrder): Call setHasFocusVisible(true) for keyboard focus.
* page/FrameView.cpp:
(WebCore::FrameView::scrollToFragmentInternal): Call setHasFocusVisible(true) for anchor focus.
* style/StyleSharingResolver.cpp:
(WebCore::Style::SharingResolver::canShareStyleWithElement const): Add check for hasFocusVisible().

LayoutTests:

* platform/ios/TestExpectations: Skip focus-visible-008.html and focus-visible-011.html as they timeout in iOS.
* platform/mac/imported/w3c/web-platform-tests/css/selectors/focus-visible-008-expected.txt: Copied from LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-008-expected.txt.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (273811 => 273812)


--- trunk/LayoutTests/ChangeLog	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/LayoutTests/ChangeLog	2021-03-03 06:43:53 UTC (rev 273812)
@@ -1,3 +1,14 @@
+2021-03-02  Manuel Rego Casasnovas  <[email protected]>
+
+        [selectors] :focus-visible implementation
+        https://bugs.webkit.org/show_bug.cgi?id=222028
+        <rdar://problem/74679243>
+
+        Reviewed by Darin Adler.
+
+        * platform/ios/TestExpectations: Skip focus-visible-008.html and focus-visible-011.html as they timeout in iOS.
+        * platform/mac/imported/w3c/web-platform-tests/css/selectors/focus-visible-008-expected.txt: Copied from LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-008-expected.txt.
+
 2021-03-02  Lauro Moura  <[email protected]>
 
         [GLIB] Rebaseline and update expectations

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (273811 => 273812)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2021-03-03 06:43:53 UTC (rev 273812)
@@ -1,3 +1,29 @@
+2021-03-02  Manuel Rego Casasnovas  <[email protected]>
+
+        [selectors] :focus-visible implementation
+        https://bugs.webkit.org/show_bug.cgi?id=222028
+        <rdar://problem/74679243>
+
+        Reviewed by Darin Adler.
+
+        Update expectations, most of the :focus-visible tests are passing now.
+
+        * web-platform-tests/css/selectors/focus-in-focus-event-001-expected.txt:
+        * web-platform-tests/css/selectors/focus-in-focusin-event-001-expected.txt:
+        * web-platform-tests/css/selectors/focus-visible-001-expected.txt:
+        * web-platform-tests/css/selectors/focus-visible-002-expected.txt:
+        * web-platform-tests/css/selectors/focus-visible-006-expected.txt:
+        * web-platform-tests/css/selectors/focus-visible-007-expected.txt:
+        * web-platform-tests/css/selectors/focus-visible-007.html: Import last changes on this test
+        * web-platform-tests/css/selectors/focus-visible-008-expected.txt:
+        (see https://github.com/web-platform-tests/wpt/pull/27656).
+        * web-platform-tests/css/selectors/focus-visible-011-expected.txt:
+        * web-platform-tests/css/selectors/focus-visible-011.html: Import last changes on this test
+        (see https://github.com/web-platform-tests/wpt/pull/27700).
+        * web-platform-tests/css/selectors/focus-visible-013-expected.txt:
+        * web-platform-tests/css/selectors/focus-visible-014-expected.txt:
+        * web-platform-tests/css/selectors/focus-visible-016-expected.txt:
+
 2021-03-02  Rob Buis  <[email protected]>
 
         Take box-sizing into account in replaced element intrinsic sizing

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-in-focus-event-001-expected.txt (273811 => 273812)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-in-focus-event-001-expected.txt	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-in-focus-event-001-expected.txt	2021-03-03 06:43:53 UTC (rev 273812)
@@ -1,6 +1,6 @@
 
 
 PASS Checks that ':focus' pseudo-class matches inside 'focus' event handler
-FAIL Checks that ':focus-visible' pseudo-class matches inside 'focus' event handler assert_unreached: ':focus-visible'  is an invalid selector. SyntaxError: Error: assert_equals: ':focus-visible' matches event.target expected null but got Element node <input type="text"></input> Reached unreachable code
+PASS Checks that ':focus-visible' pseudo-class matches inside 'focus' event handler
 PASS Checks that ':focus-within' pseudo-class matches inside 'focus' event handler
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-in-focusin-event-001-expected.txt (273811 => 273812)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-in-focusin-event-001-expected.txt	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-in-focusin-event-001-expected.txt	2021-03-03 06:43:53 UTC (rev 273812)
@@ -1,6 +1,6 @@
 
 
 PASS Checks that ':focus' pseudo-class matches inside 'focusin' event handler
-FAIL Checks that ':focus-visible' pseudo-class matches inside 'focusin' event handler assert_unreached: ':focus-visible'  is an invalid selector. SyntaxError: Error: assert_equals: ':focus-visible' matches event.target expected null but got Element node <input type="text"></input> Reached unreachable code
+PASS Checks that ':focus-visible' pseudo-class matches inside 'focusin' event handler
 PASS Checks that ':focus-within' pseudo-class matches inside 'focusin' event handler
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-001-expected.txt (273811 => 273812)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-001-expected.txt	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-001-expected.txt	2021-03-03 06:43:53 UTC (rev 273812)
@@ -5,5 +5,5 @@
 
 Focus me.
 
-FAIL Keyboard focus should match :focus-visible assert_equals: outlineColor for DIV#el should be green expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
+PASS Keyboard focus should match :focus-visible
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-002-expected.txt (273811 => 273812)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-002-expected.txt	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-002-expected.txt	2021-03-03 06:43:53 UTC (rev 273812)
@@ -18,18 +18,18 @@
 
 
 
-FAIL Focus element INPUT#input1 via mouse should match :focus-visible as it supports keyboard input assert_equals: outlineColor for INPUT#input1 should be green expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
-FAIL Focus element INPUT#input2 via mouse should match :focus-visible as it supports keyboard input assert_equals: outlineColor for INPUT#input2 should be green expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
-FAIL Focus element INPUT#input3 via mouse should match :focus-visible as it supports keyboard input assert_equals: outlineColor for INPUT#input3 should be green expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
-FAIL Focus element INPUT#input4 via mouse should match :focus-visible as it supports keyboard input assert_equals: outlineColor for INPUT#input4 should be green expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
-FAIL Focus element INPUT#input5 via mouse should match :focus-visible as it supports keyboard input assert_equals: outlineColor for INPUT#input5 should be green expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
-FAIL Focus element INPUT#input6 via mouse should match :focus-visible as it supports keyboard input assert_equals: outlineColor for INPUT#input6 should be green expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
-FAIL Focus element INPUT#input7 via mouse should match :focus-visible as it supports keyboard input assert_equals: outlineColor for INPUT#input7 should be green expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
-FAIL Focus element INPUT#input8 via mouse should match :focus-visible as it supports keyboard input assert_equals: outlineColor for INPUT#input8 should be green expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
-FAIL Focus element INPUT#input9 via mouse should match :focus-visible as it supports keyboard input assert_equals: outlineColor for INPUT#input9 should be green expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
-FAIL Focus element INPUT#input10 via mouse should match :focus-visible as it supports keyboard input assert_equals: outlineColor for INPUT#input10 should be green expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
-FAIL Focus element INPUT#input11 via mouse should match :focus-visible as it supports keyboard input assert_equals: outlineColor for INPUT#input11 should be green expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
-FAIL Focus element INPUT#input12 via mouse should match :focus-visible as it supports keyboard input assert_equals: outlineColor for INPUT#input12 should be green expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
-FAIL Focus element INPUT#input13 via mouse should match :focus-visible as it supports keyboard input assert_equals: outlineColor for INPUT#input13 should be green expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
-FAIL Focus element TEXTAREA#input14 via mouse should match :focus-visible as it supports keyboard input assert_equals: outlineColor for TEXTAREA#input14 should be green expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
+PASS Focus element INPUT#input1 via mouse should match :focus-visible as it supports keyboard input
+PASS Focus element INPUT#input2 via mouse should match :focus-visible as it supports keyboard input
+PASS Focus element INPUT#input3 via mouse should match :focus-visible as it supports keyboard input
+PASS Focus element INPUT#input4 via mouse should match :focus-visible as it supports keyboard input
+PASS Focus element INPUT#input5 via mouse should match :focus-visible as it supports keyboard input
+PASS Focus element INPUT#input6 via mouse should match :focus-visible as it supports keyboard input
+PASS Focus element INPUT#input7 via mouse should match :focus-visible as it supports keyboard input
+PASS Focus element INPUT#input8 via mouse should match :focus-visible as it supports keyboard input
+PASS Focus element INPUT#input9 via mouse should match :focus-visible as it supports keyboard input
+PASS Focus element INPUT#input10 via mouse should match :focus-visible as it supports keyboard input
+PASS Focus element INPUT#input11 via mouse should match :focus-visible as it supports keyboard input
+PASS Focus element INPUT#input12 via mouse should match :focus-visible as it supports keyboard input
+PASS Focus element INPUT#input13 via mouse should match :focus-visible as it supports keyboard input
+PASS Focus element TEXTAREA#input14 via mouse should match :focus-visible as it supports keyboard input
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-006-expected.txt (273811 => 273812)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-006-expected.txt	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-006-expected.txt	2021-03-03 06:43:53 UTC (rev 273812)
@@ -5,5 +5,5 @@
 
 Focus me
 
-FAIL Focus should always match :focus-visible on content editable divs assert_equals: outlineColor for SPAN#el should be green expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
+PASS Focus should always match :focus-visible on content editable divs
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-007-expected.txt (273811 => 273812)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-007-expected.txt	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-007-expected.txt	2021-03-03 06:43:53 UTC (rev 273812)
@@ -2,9 +2,9 @@
 If the user-agent does not claim to support the :focus-visible pseudo-class then SKIP this test.
 Use the mouse to focus the element below that says "Click me."
 If the element has a red outline, then the test result is FAILURE.
-Press the SHIFT key.
+Press the ENTER key.
 If the element now has a green outline and not red background, then the test result is SUCCESS.
 Click me.
 
-FAIL Using keyboard while element is focused should trigger :focus-visible; using mouse without moving focus should not cancel it; moving focus using mouse should cancel it. assert_equals: expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
+PASS Using keyboard while element is focused should trigger :focus-visible; using mouse without moving focus should not cancel it; moving focus using mouse should cancel it.
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-007.html (273811 => 273812)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-007.html	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-007.html	2021-03-03 06:43:53 UTC (rev 273812)
@@ -36,7 +36,7 @@
     <li>If the user-agent does not claim to support the <code>:focus-visible</code> pseudo-class then SKIP this test.</li>
     <li>Use the mouse to focus the element below that says "Click me."</li>
     <li>If the element has a red outline, then the test result is FAILURE.</li>
-    <li>Press the SHIFT key.</li>
+    <li>Press the ENTER key.</li>
     <li>If the element now has a green outline and not red background, then the test result is SUCCESS.</li>
   </ol>
 
@@ -65,7 +65,8 @@
         one.addEventListener("keyup", t.step_func(test_modality_change));
         one.removeEventListener("focus", handle_initial_focus);
 
-        test_driver.send_keys(one, "\uE050");
+        const enter = "\uE007";
+        test_driver.send_keys(one, enter);
       });
 
       const test_modality_change = t.step_func(() => {

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-008-expected.txt (273811 => 273812)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-008-expected.txt	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-008-expected.txt	2021-03-03 06:43:53 UTC (rev 273812)
@@ -6,7 +6,5 @@
 Tab to me and press ENTER.
 I will be focused programmatically.
 
-Harness Error (TIMEOUT), message = null
+FAIL Programmatic focus after keypress should match :focus-visible assert_equals: outlineColor for DIV#el should be green expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)"
 
-TIMEOUT Programmatic focus after keypress should match :focus-visible Test timed out
-

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-011-expected.txt (273811 => 273812)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-011-expected.txt	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-011-expected.txt	2021-03-03 06:43:53 UTC (rev 273812)
@@ -1,11 +1,9 @@
 This test checks that :focus-visible matches after a keyboard event, even if the event handler calls preventDefault() on the event.
 Click "Click here and press right arrow.".
 Press the right arrow key.
-If "Focus moves here." has a red background, then the test result is FAILURE. If it has a green outline, then the test result is SUCCESS.
+If the element has a red background, then the test result is FAILURE. If it has a green outline, then the test result is SUCCESS.
 
-Click here and press right arrow.  Focus moves here.
+Click here and press right arrow.
 
-Harness Error (TIMEOUT), message = null
+PASS :focus-visible matches even if preventDefault() is called
 
-TIMEOUT :focus-visible matches even if preventDefault() is called Test timed out
-

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-011.html (273811 => 273812)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-011.html	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-011.html	2021-03-03 06:43:53 UTC (rev 273812)
@@ -21,11 +21,11 @@
       border: 0;
     }
 
-    #next:focus-visible {
+    :focus-visible {
       outline: green solid 5px;
     }
 
-    #next:focus:not(:focus-visible) {
+    :focus:not(:focus-visible) {
       background-color: red;
       outline: 0;
     }
@@ -37,30 +37,33 @@
   <ul id="instructions">
     <li>Click "Click here and press right arrow.".</li>
     <li>Press the right arrow key.</li>
-    <li>If "Focus moves here." has a red background, then the test result is FAILURE.
+    <li>If the element has a red background, then the test result is FAILURE.
         If it has a green outline, then the test result is SUCCESS.</li>
   </ul>
   <br />
-  <button id="start" tabindex="0">Click here and press right arrow.</button>
-  <button id="next" tabindex="-1">Focus moves here.</button>
+  <div id="target" tabindex="0">Click here and press right arrow.</div>
   <script>
-    start.addEventListener('keydown', (e) => {
+    target.addEventListener("keydown", (e) => {
       e.preventDefault();
-      next.focus();
     });
+    target.addEventListener("keyup", (e) => {
+      e.preventDefault();
+    });
+    target.addEventListener("keypress", (e) => {
+      e.preventDefault();
+    });
+    async_test(function(t) {
+      target.addEventListener("focus", () => {
+        const arrow_right = "\ue014";
+        test_driver.send_keys(target, arrow_right);
+      });
 
-    async_test(function(t) {
-      next.addEventListener("focus", t.step_func(() => {
-        assert_equals(getComputedStyle(next).outlineColor, "rgb(0, 128, 0)", `outlineColor for ${next.tagName}#${next.id} should be green`);
-        assert_not_equals(getComputedStyle(next).backgroundColor, "rgb(255, 0, 0)", `backgroundColor for ${next.tagName}#${next.id} should NOT be red`);
-        t.done()
+      target.addEventListener("keyup", t.step_func_done((e) => {
+        assert_equals(getComputedStyle(target).outlineColor, "rgb(0, 128, 0)", `outlineColor for ${target.tagName}#${target.id} should be green`);
+        assert_not_equals(getComputedStyle(target).backgroundColor, "rgb(255, 0, 0)", `backgroundColor for ${target.tagName}#${target.id} should NOT be red`);
       }));
 
-      // \ue014 -> ARROW_RIGHT
-      test_driver.send_keys(start, "\ue014").catch(t.step_func(() => {
-        assert_true(false, "send_keys not implemented yet");
-        t.done();
-      }));
+      test_driver.click(target);
     }, ":focus-visible matches even if preventDefault() is called");
   </script>
 </body>

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-013-expected.txt (273811 => 273812)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-013-expected.txt	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-013-expected.txt	2021-03-03 06:43:53 UTC (rev 273812)
@@ -8,7 +8,5 @@
 Initial
 Target
 
-Harness Error (TIMEOUT), message = null
+PASS :focus-visible does not match after mouse click even if previous focused element was matching :focus-visible
 
-FAIL :focus-visible does not match after mouse click even if previous focused element was matching :focus-visible assert_equals: outlineColor for DIV#initial should be green expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
-

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-014-expected.txt (273811 => 273812)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-014-expected.txt	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-014-expected.txt	2021-03-03 06:43:53 UTC (rev 273812)
@@ -1,5 +1,5 @@
 
 Target
 
-FAIL :focus-visible matches after script focus move assert_equals: backgroundColor for INPUT#input should be lime expected "rgb(0, 255, 0)" but got "rgb(255, 0, 0)"
+FAIL :focus-visible matches after script focus move assert_equals: backgroundColor for DIV#target should be lime expected "rgb(0, 255, 0)" but got "rgb(255, 0, 0)"
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-016-expected.txt (273811 => 273812)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-016-expected.txt	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-016-expected.txt	2021-03-03 06:43:53 UTC (rev 273812)
@@ -1,5 +1,5 @@
 Initial
 
 
-FAIL :focus-visible always match on text inputs assert_equals: backgroundColor for INPUT#target should be lime expected "rgb(0, 255, 0)" but got "rgb(255, 0, 0)"
+PASS :focus-visible always match on text inputs
 

Modified: trunk/LayoutTests/platform/ios/TestExpectations (273811 => 273812)


--- trunk/LayoutTests/platform/ios/TestExpectations	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/LayoutTests/platform/ios/TestExpectations	2021-03-03 06:43:53 UTC (rev 273812)
@@ -3394,7 +3394,9 @@
 
 webkit.org/b/209734 imported/w3c/web-platform-tests/css/selectors/focus-visible-001.html [ Skip ]
 webkit.org/b/209734 imported/w3c/web-platform-tests/css/selectors/focus-visible-007.html [ Skip ]
+webkit.org/b/209734 imported/w3c/web-platform-tests/css/selectors/focus-visible-008.html [ Skip ]
 webkit.org/b/209734 imported/w3c/web-platform-tests/css/selectors/focus-visible-009.html [ Skip ]
+webkit.org/b/209734 imported/w3c/web-platform-tests/css/selectors/focus-visible-011.html [ Skip ]
 webkit.org/b/209734 imported/w3c/web-platform-tests/css/selectors/focus-visible-012.html [ Skip ]
 webkit.org/b/209734 imported/w3c/web-platform-tests/css/selectors/focus-visible-013.html [ Skip ]
 webkit.org/b/209734 imported/w3c/web-platform-tests/css/selectors/hover-002.html [ Skip ]

Copied: trunk/LayoutTests/platform/mac/imported/w3c/web-platform-tests/css/selectors/focus-visible-008-expected.txt (from rev 273811, trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/focus-visible-008-expected.txt) (0 => 273812)


--- trunk/LayoutTests/platform/mac/imported/w3c/web-platform-tests/css/selectors/focus-visible-008-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/platform/mac/imported/w3c/web-platform-tests/css/selectors/focus-visible-008-expected.txt	2021-03-03 06:43:53 UTC (rev 273812)
@@ -0,0 +1,12 @@
+This test checks that programmatically focusing an element after a keypress causes :focus-visible to match.
+Use the tab key to move focus to the button below that says "Tab to me and press ENTER."
+Press ENTER.
+If the element that says "I will be focused programmatically." has a red background, then the test result is FAILURE. If the element has a green outline, then the test result is SUCCESS.
+
+Tab to me and press ENTER.
+I will be focused programmatically.
+
+Harness Error (TIMEOUT), message = null
+
+TIMEOUT Programmatic focus after keypress should match :focus-visible Test timed out
+

Modified: trunk/Source/WebCore/ChangeLog (273811 => 273812)


--- trunk/Source/WebCore/ChangeLog	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/Source/WebCore/ChangeLog	2021-03-03 06:43:53 UTC (rev 273812)
@@ -1,3 +1,37 @@
+2021-03-02  Manuel Rego Casasnovas  <[email protected]>
+
+        [selectors] :focus-visible implementation
+        https://bugs.webkit.org/show_bug.cgi?id=222028
+        <rdar://problem/74679243>
+
+        Reviewed by Darin Adler.
+
+        Add basic :focus-visible implementation behind the FocusVisibleEnabled experimental feature flag.
+        This patch implements the heuristics defined in the spec (https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo),
+        except the ones related to script focus.
+
+        Test: imported/w3c/web-platform-tests/css/selectors/focus-visible-*
+
+        * css/SelectorCheckerTestFunctions.h:
+        (WebCore::matchesFocusVisiblePseudoClass): Check element.hasFocusVisible().
+        * dom/Element.cpp:
+        (WebCore::Element::setFocus): When an element loses focus it always call setHasFocusVisible(false). When an element gets focused
+        it calls setHasFocusVisible(true) for elements that support keyboard input (as they always match :focus-visible).
+        (WebCore::Element::setHasFocusVisible): New method gated behind the experimental flag.
+        * dom/Element.h:
+        (WebCore::Element::hasFocusVisible const): Add new method.
+        * dom/Node.h:
+        (WebCore::Node::flagHasFocusVisible): Add new flag for :focus-visible matching.
+        * page/EventHandler.cpp:
+        (WebCore::EventHandler::internalKeyEvent): If the user interacts with the page via keyboard, call setHasFocusVisible(true).
+        Avoid that for modifier keys.
+        * page/FocusController.cpp:
+        (WebCore::FocusController::advanceFocusInDocumentOrder): Call setHasFocusVisible(true) for keyboard focus.
+        * page/FrameView.cpp:
+        (WebCore::FrameView::scrollToFragmentInternal): Call setHasFocusVisible(true) for anchor focus.
+        * style/StyleSharingResolver.cpp:
+        (WebCore::Style::SharingResolver::canShareStyleWithElement const): Add check for hasFocusVisible().
+
 2021-03-02  Julian Gonzalez  <[email protected]>
 
         Crash in removeSymbolElementsFromSubtree()

Modified: trunk/Source/WebCore/css/SelectorCheckerTestFunctions.h (273811 => 273812)


--- trunk/Source/WebCore/css/SelectorCheckerTestFunctions.h	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/Source/WebCore/css/SelectorCheckerTestFunctions.h	2021-03-03 06:43:53 UTC (rev 273812)
@@ -474,7 +474,10 @@
 
 ALWAYS_INLINE bool matchesFocusVisiblePseudoClass(const Element& element)
 {
-    return InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoClassFocusVisible);
+    if (InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoClassFocusVisible))
+        return true;
+
+    return element.hasFocusVisible() && isFrameFocused(element);
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/dom/Element.cpp (273811 => 273812)


--- trunk/Source/WebCore/dom/Element.cpp	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/Source/WebCore/dom/Element.cpp	2021-03-03 06:43:53 UTC (rev 273812)
@@ -744,8 +744,28 @@
 
     for (auto* element = this; element; element = element->parentElementInComposedTree())
         element->setHasFocusWithin(flag);
+
+    auto computeHasFocusVisible = [&] {
+        if (!flag)
+            return false;
+        // Elements that support keyboard input (form inputs and contenteditable) always match :focus-visible when focused.
+        return hasFocusVisible() || isTextField() || isContentEditable();
+    };
+    setHasFocusVisible(computeHasFocusVisible());
 }
 
+void Element::setHasFocusVisible(bool flag)
+{
+    if (!document().settings().focusVisibleEnabled())
+        return;
+
+    if (hasFocusVisible() == flag)
+        return;
+
+    Style::PseudoClassChangeInvalidation styleInvalidation(*this, CSSSelector::PseudoClassFocusVisible);
+    setNodeFlag(NodeFlag::HasFocusVisible, flag);
+}
+
 void Element::setHasFocusWithin(bool flag)
 {
     if (hasFocusWithin() == flag)

Modified: trunk/Source/WebCore/dom/Element.h (273811 => 273812)


--- trunk/Source/WebCore/dom/Element.h	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/Source/WebCore/dom/Element.h	2021-03-03 06:43:53 UTC (rev 273812)
@@ -319,6 +319,7 @@
     bool hovered() const { return isUserActionElement() && isUserActionElementHovered(); }
     bool focused() const { return isUserActionElement() && isUserActionElementFocused(); }
     bool isBeingDragged() const { return isUserActionElement() && isUserActionElementDragged(); }
+    bool hasFocusVisible() const { return hasNodeFlag(NodeFlag::HasFocusVisible); };
     bool hasFocusWithin() const { return hasNodeFlag(NodeFlag::HasFocusWithin); };
 
     virtual void setActive(bool = true, bool pause = false, Style::InvalidationScope = Style::InvalidationScope::All);
@@ -325,6 +326,7 @@
     virtual void setHovered(bool = true, Style::InvalidationScope = Style::InvalidationScope::All);
     virtual void setFocus(bool);
     void setBeingDragged(bool);
+    void setHasFocusVisible(bool);
     void setHasFocusWithin(bool);
 
     Optional<int> tabIndexSetExplicitly() const;

Modified: trunk/Source/WebCore/dom/Node.h (273811 => 273812)


--- trunk/Source/WebCore/dom/Node.h	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/Source/WebCore/dom/Node.h	2021-03-03 06:43:53 UTC (rev 273812)
@@ -508,6 +508,7 @@
     static int32_t flagIsShadowRoot() { return static_cast<int32_t>(NodeFlag::IsShadowRoot); }
     static int32_t flagIsHTML() { return static_cast<int32_t>(NodeFlag::IsHTMLElement); }
     static int32_t flagIsLink() { return static_cast<int32_t>(NodeFlag::IsLink); }
+    static int32_t flagHasFocusVisible() { return static_cast<int32_t>(NodeFlag::HasFocusVisible); }
     static int32_t flagHasFocusWithin() { return static_cast<int32_t>(NodeFlag::HasFocusWithin); }
     static int32_t flagIsParsingChildrenFinished() { return static_cast<int32_t>(NodeFlag::IsParsingChildrenFinished); }
 #endif // ENABLE(JIT)
@@ -549,6 +550,7 @@
 #endif
         IsComputedStyleInvalidFlag = 1 << 26,
 
+        HasFocusVisible = 1 << 27,
         // Bits 27-31 are free.
     };
 

Modified: trunk/Source/WebCore/page/EventHandler.cpp (273811 => 273812)


--- trunk/Source/WebCore/page/EventHandler.cpp	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/Source/WebCore/page/EventHandler.cpp	2021-03-03 06:43:53 UTC (rev 273812)
@@ -3532,6 +3532,11 @@
         keydown->preventDefault();
     keydown->setTarget(element);
 
+    // If the user interacts with the page via the keyboard, the currently focused element should match :focus-visible.
+    // Just typing a modifier key is not considered user interaction with the page, but Shift + a (or Caps Lock + a) is considered an interaction.
+    if (keydown->modifierKeys().isEmpty() || ((keydown->shiftKey() || keydown->capsLockKey()) && !initialKeyEvent.text().isEmpty()))
+        element->setHasFocusVisible(true);
+
     if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) {
         element->dispatchEvent(keydown);
         // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.

Modified: trunk/Source/WebCore/page/FocusController.cpp (273811 => 273812)


--- trunk/Source/WebCore/page/FocusController.cpp	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/Source/WebCore/page/FocusController.cpp	2021-03-03 06:43:53 UTC (rev 273812)
@@ -533,6 +533,7 @@
         }
     }
 
+    element->setHasFocusVisible(true);
     element->focus(SelectionRestorationMode::SelectAll, direction);
     return true;
 }

Modified: trunk/Source/WebCore/page/FrameView.cpp (273811 => 273812)


--- trunk/Source/WebCore/page/FrameView.cpp	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/Source/WebCore/page/FrameView.cpp	2021-03-03 06:43:53 UTC (rev 273812)
@@ -2268,9 +2268,10 @@
     
     // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation.
     if (anchorElement) {
-        if (anchorElement->isFocusable())
+        if (anchorElement->isFocusable()) {
+            anchorElement->setHasFocusVisible(true);
             document.setFocusedElement(anchorElement.get());
-        else {
+        } else {
             document.setFocusedElement(nullptr);
             document.setFocusNavigationStartingNode(anchorElement.get());
         }

Modified: trunk/Source/WebCore/style/StyleSharingResolver.cpp (273811 => 273812)


--- trunk/Source/WebCore/style/StyleSharingResolver.cpp	2021-03-03 05:05:30 UTC (rev 273811)
+++ trunk/Source/WebCore/style/StyleSharingResolver.cpp	2021-03-03 06:43:53 UTC (rev 273812)
@@ -227,6 +227,8 @@
         return false;
     if (candidateElement.focused() != element.focused())
         return false;
+    if (candidateElement.hasFocusVisible() != element.hasFocusVisible())
+        return false;
     if (candidateElement.hasFocusWithin() != element.hasFocusWithin())
         return false;
     if (candidateElement.isBeingDragged() != element.isBeingDragged())
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to