Title: [269059] trunk
Revision
269059
Author
[email protected]
Date
2020-10-27 11:51:38 -0700 (Tue, 27 Oct 2020)

Log Message

Accessory bar next/previous buttons do not work on inputs in shadow roots
https://bugs.webkit.org/show_bug.cgi?id=203292

Patch by Tetsuharu Ohzeki <[email protected]> on 2020-10-27
Reviewed by Ryosuke Niwa.

Source/WebCore:

Tests: fast/shadow-dom/ios/accessory-bar-work-on-input-with-tabindex-in-shadow-tree.html

* page/FocusController.cpp:
(WebCore::FocusController::nextFocusableElement):
(WebCore::FocusController::previousFocusableElement):

LayoutTests:

Introduced testcases only need to run with iOS family.

* fast/shadow-dom/ios/accessory-bar-work-on-input-with-tabindex-in-shadow-tree-expected.txt: Added.
* fast/shadow-dom/ios/accessory-bar-work-on-input-with-tabindex-in-shadow-tree.html: Added.
* TestExpectations:
* platform/ios/TestExpectations:
  Avoid to run introduced tests because we don't have to run them and
  tests are crashed on these platforms.
* resources/ui-helper.js:
(window.UIHelper.moveToNextByKeyboardAccessoryBar):
(window.UIHelper.moveToPrevByKeyboardAccessoryBar):
(window.UIHelper):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (269058 => 269059)


--- trunk/LayoutTests/ChangeLog	2020-10-27 18:46:56 UTC (rev 269058)
+++ trunk/LayoutTests/ChangeLog	2020-10-27 18:51:38 UTC (rev 269059)
@@ -1,3 +1,23 @@
+2020-10-27  Tetsuharu Ohzeki  <[email protected]>
+
+        Accessory bar next/previous buttons do not work on inputs in shadow roots
+        https://bugs.webkit.org/show_bug.cgi?id=203292
+
+        Reviewed by Ryosuke Niwa.
+
+        Introduced testcases only need to run with iOS family.
+
+        * fast/shadow-dom/ios/accessory-bar-work-on-input-with-tabindex-in-shadow-tree-expected.txt: Added.
+        * fast/shadow-dom/ios/accessory-bar-work-on-input-with-tabindex-in-shadow-tree.html: Added.
+        * TestExpectations:
+        * platform/ios/TestExpectations:
+          Avoid to run introduced tests because we don't have to run them and
+          tests are crashed on these platforms.
+        * resources/ui-helper.js:
+        (window.UIHelper.moveToNextByKeyboardAccessoryBar):
+        (window.UIHelper.moveToPrevByKeyboardAccessoryBar):
+        (window.UIHelper):
+
 2020-10-27  Philippe Normand  <[email protected]>
 
         [GStreamer] Bad handling of audio files in the ImageDecoder

Modified: trunk/LayoutTests/TestExpectations (269058 => 269059)


--- trunk/LayoutTests/TestExpectations	2020-10-27 18:46:56 UTC (rev 269058)
+++ trunk/LayoutTests/TestExpectations	2020-10-27 18:51:38 UTC (rev 269059)
@@ -4524,3 +4524,6 @@
 
 fast/layoutformattingcontext/ [ ImageOnlyFailure ]
 webkit.org/b/217054 fast/layoutformattingcontext/horizontal-sizing-with-trailing-letter-spacing.html [ Skip ]
+
+# These tests are for iOS port.
+fast/shadow-dom/ios/ [ Skip ]

Added: trunk/LayoutTests/fast/shadow-dom/ios/accessory-bar-work-on-input-with-tabindex-in-shadow-tree-expected.txt (0 => 269059)


--- trunk/LayoutTests/fast/shadow-dom/ios/accessory-bar-work-on-input-with-tabindex-in-shadow-tree-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/ios/accessory-bar-work-on-input-with-tabindex-in-shadow-tree-expected.txt	2020-10-27 18:51:38 UTC (rev 269059)
@@ -0,0 +1,106 @@
+Test that Accessory bar next/previous buttons work on inputs which is not assigned to any slot in shadow tree
+
+To manually test, do following steps.
+
+Focus the 1st of input, then Accessory bar will shown.
+Press "next" icon 4 times.
+Press "prev" icon 4 times.
+It should traverse focusable elements in the increasing numerical order and reverse the order of them.
+
+
+
+
+
+
+Test that Accessory bar next/previous buttons work on inputs which is not assigned to any slot in shadow tree
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+activate 0th input
+activated 0th input
+forward to 1th input
+documentOrShadowRoot.activeElement's placeholder attribute: 1. input element having a positive tabindex in a shadow tree host having a positive tabindex
+PASS () => activeElement.getAttribute('placeholder') is 1. input element having a positive tabindex in a shadow tree host having a positive tabindex
+forward to 2th input
+documentOrShadowRoot.activeElement's placeholder attribute: 2. input element having a positive tabindex in a element having a positive tabindex
+PASS () => activeElement.getAttribute('placeholder') is 2. input element having a positive tabindex in a element having a positive tabindex
+forward to 3th input
+documentOrShadowRoot.activeElement's placeholder attribute: 3. input element having tabindex=1 in a element having a positive tabindex
+PASS () => activeElement.getAttribute('placeholder') is 3. input element having tabindex=1 in a element having a positive tabindex
+forward to 4th input
+documentOrShadowRoot.activeElement's placeholder attribute: 4. input element having tabindex=0 in a shadow tree host having a positive tabindex
+PASS () => activeElement.getAttribute('placeholder') is 4. input element having tabindex=0 in a shadow tree host having a positive tabindex
+forward to 5th input
+documentOrShadowRoot.activeElement's placeholder attribute: 5. input element having a positive tabindex in a shadow tree host which does not tabindex
+PASS () => activeElement.getAttribute('placeholder') is 5. input element having a positive tabindex in a shadow tree host which does not tabindex
+forward to 6th input
+documentOrShadowRoot.activeElement's placeholder attribute: 6. input element in closed shadow tree host
+PASS () => activeElement.getAttribute('placeholder') is 6. input element in closed shadow tree host
+forward to 7th input
+documentOrShadowRoot.activeElement's placeholder attribute: 7. input element before nested custom element having shadow tree
+PASS () => activeElement.getAttribute('placeholder') is 7. input element before nested custom element having shadow tree
+forward to 8th input
+documentOrShadowRoot.activeElement's placeholder attribute: 8. input element in nested shadow tree
+PASS () => activeElement.getAttribute('placeholder') is 8. input element in nested shadow tree
+forward to 9th input
+documentOrShadowRoot.activeElement's placeholder attribute: 9. input element after nested custom element having shadow tree
+PASS () => activeElement.getAttribute('placeholder') is 9. input element after nested custom element having shadow tree
+forward to 10th input
+documentOrShadowRoot.activeElement's placeholder attribute: 10. Last sequentially input element outside shadow trees
+PASS () => activeElement.getAttribute('placeholder') is 10. Last sequentially input element outside shadow trees
+focus has moved to the last element and will move to the first reversely
+back to 9th input
+documentOrShadowRoot.activeElement's placeholder attribute: 9. input element after nested custom element having shadow tree
+PASS () => activeElement.getAttribute('placeholder') is 9. input element after nested custom element having shadow tree
+back to 8th input
+documentOrShadowRoot.activeElement's placeholder attribute: 8. input element in nested shadow tree
+PASS () => activeElement.getAttribute('placeholder') is 8. input element in nested shadow tree
+back to 7th input
+documentOrShadowRoot.activeElement's placeholder attribute: 7. input element before nested custom element having shadow tree
+PASS () => activeElement.getAttribute('placeholder') is 7. input element before nested custom element having shadow tree
+back to 6th input
+documentOrShadowRoot.activeElement's placeholder attribute: 6. input element in closed shadow tree host
+PASS () => activeElement.getAttribute('placeholder') is 6. input element in closed shadow tree host
+back to 5th input
+documentOrShadowRoot.activeElement's placeholder attribute: 5. input element having a positive tabindex in a shadow tree host which does not tabindex
+PASS () => activeElement.getAttribute('placeholder') is 5. input element having a positive tabindex in a shadow tree host which does not tabindex
+back to 4th input
+documentOrShadowRoot.activeElement's placeholder attribute: 4. input element having tabindex=0 in a shadow tree host having a positive tabindex
+PASS () => activeElement.getAttribute('placeholder') is 4. input element having tabindex=0 in a shadow tree host having a positive tabindex
+back to 3th input
+documentOrShadowRoot.activeElement's placeholder attribute: 3. input element having tabindex=1 in a element having a positive tabindex
+PASS () => activeElement.getAttribute('placeholder') is 3. input element having tabindex=1 in a element having a positive tabindex
+back to 2th input
+documentOrShadowRoot.activeElement's placeholder attribute: 2. input element having a positive tabindex in a element having a positive tabindex
+PASS () => activeElement.getAttribute('placeholder') is 2. input element having a positive tabindex in a element having a positive tabindex
+back to 1th input
+documentOrShadowRoot.activeElement's placeholder attribute: 1. input element having a positive tabindex in a shadow tree host having a positive tabindex
+PASS () => activeElement.getAttribute('placeholder') is 1. input element having a positive tabindex in a shadow tree host having a positive tabindex
+back to 0th input
+documentOrShadowRoot.activeElement's placeholder attribute: 0. First sequentially input element outside shadow trees
+PASS () => activeElement.getAttribute('placeholder') is 0. First sequentially input element outside shadow trees
+PASS successfullyParsed is true
+
+TEST COMPLETE
+0. First sequentially input element outside shadow trees
+1. input element having a positive tabindex in a shadow tree host having a positive tabindex
+2. input element having a positive tabindex in a element having a positive tabindex
+3. input element having tabindex=1 in a element having a positive tabindex
+4. input element having tabindex=0 in a shadow tree host having a positive tabindex
+5. input element having a positive tabindex in a shadow tree host which does not tabindex
+6. input element in closed shadow tree host
+7. input element before nested custom element having shadow tree
+8. input element in nested shadow tree
+9. input element after nested custom element having shadow tree
+10. Last sequentially input element outside shadow trees
+9. input element after nested custom element having shadow tree
+8. input element in nested shadow tree
+7. input element before nested custom element having shadow tree
+6. input element in closed shadow tree host
+5. input element having a positive tabindex in a shadow tree host which does not tabindex
+4. input element having tabindex=0 in a shadow tree host having a positive tabindex
+3. input element having tabindex=1 in a element having a positive tabindex
+2. input element having a positive tabindex in a element having a positive tabindex
+1. input element having a positive tabindex in a shadow tree host having a positive tabindex
+0. First sequentially input element outside shadow trees
+

Added: trunk/LayoutTests/fast/shadow-dom/ios/accessory-bar-work-on-input-with-tabindex-in-shadow-tree.html (0 => 269059)


--- trunk/LayoutTests/fast/shadow-dom/ios/accessory-bar-work-on-input-with-tabindex-in-shadow-tree.html	                        (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/ios/accessory-bar-work-on-input-with-tabindex-in-shadow-tree.html	2020-10-27 18:51:38 UTC (rev 269059)
@@ -0,0 +1,209 @@
+<!DOCTYPE html>
+<html>
+<body>
+
+<h1>Test that Accessory bar next/previous buttons work on inputs which is not assigned to any slot in shadow tree</h1>
+<p>To manually test, do following steps.</p>
+<ol>
+    <li>Focus the 1st of input, then Accessory bar will shown.</li>
+    <li>Press "next" icon 4 times.</li>
+    <li>Press "prev" icon 4 times.</li>
+    <li>It should traverse focusable elements in the increasing numerical order and reverse the order of them.</li>
+</ol>
+
+<input id="first" tabindex="1" _onfocus_="logOnFocus(this)"
+    placeholder="0. First sequentially input element outside shadow trees" />
+
+<div id="host-with-negative-tabindex" tabindex="-1">Should not focus: Shadow host with a negative tabindex but not input element</div>
+
+<div id="host-with-no-tabindex">
+    <input id="host-with-no-tabindex"
+        _onfocus_="logOnFocus(this)"
+        placeholder="Should not focus: input element having no tabindex in a element having no tabindex but will not assigned to slot" />
+</div>
+
+<div id="host-with-positive-tabindex" tabindex="2">
+    <div>
+        <input id="input-in-host-with-positive-tabindex-negative"
+            tabindex="-1"
+            _onfocus_="logOnFocus(this)"
+            placeholder="Should not focus: input element having a negative tabindex in a element having a positive tabindex" />
+    </div>
+    <div>
+        <input id="input-in-host-with-positive-tabindex"
+            tabindex="0"
+            _onfocus_="logOnFocus(this)"
+            placeholder="3. input element having tabindex=1 in a element having a positive tabindex" />
+    </div>
+    <div>
+        <input id="input-in-host-with-positive-tabindex-positive"
+            tabindex="1"
+            _onfocus_="logOnFocus(this)"
+            placeholder="2. input element having a positive tabindex in a element having a positive tabindex" />
+    </div>
+</div>
+
+<div id="closed-shadow-tree-host">
+    <input id="inpunt-descendants-of-closed-shadow-tree-host"
+        _onfocus_="logOnFocus(this)"
+        placeholder="6. input element in closed shadow tree host" />
+</div>
+
+<nest-input-holder></nest-input-holder>
+
+<input id="last" tabindex="0" _onfocus_="logOnFocus(this)"
+    placeholder="10. Last sequentially input element outside shadow trees" />
+
+<div id="description"></div>
+<div id="console"></div>
+<pre id="log"></pre>
+<script src=""
+<script src=""
+<script>
+
+document.getElementById('host-with-negative-tabindex').attachShadow({ mode: 'open' }).innerHTML = `
+    <input tabindex="0"
+        _onfocus_="logOnFocus(this)"
+        placeholder="Should not focus: input element having tabindex=0 in a shadow tree host having negative tabindex"/>
+`;
+
+document.getElementById('host-with-no-tabindex').attachShadow({ mode: 'open' }).innerHTML = `
+    <input tabindex="0"
+        _onfocus_="logOnFocus(this)"
+        placeholder="5. input element having a positive tabindex in a shadow tree host which does not tabindex"/>
+`;
+
+document.getElementById('host-with-positive-tabindex').attachShadow({ mode: 'open' }).innerHTML = `
+    <slot></slot>
+    <div>
+        <input tabindex="0"
+            _onfocus_="logOnFocus(this)"
+            placeholder="4. input element having tabindex=0 in a shadow tree host having a positive tabindex"/>
+    </div>
+    <div>
+        <input tabindex="-1"
+            _onfocus_="logOnFocus(this)"
+            placeholder="Should not focus: input element having negatibe tabindex in a shadow tree host having a positive tabindex"/>
+    </div>
+    <div>
+        <input tabindex="1"
+            _onfocus_="logOnFocus(this)"
+            placeholder="1. input element having a positive tabindex in a shadow tree host having a positive tabindex"/>
+    </div>
+`;
+
+document.getElementById('closed-shadow-tree-host').attachShadow({ mode: 'closed' }).innerHTML = `
+    <slot></slot>
+`;
+
+class InputHolder extends HTMLElement {
+  constructor() {
+    super();
+
+    this.attachShadow({ mode: 'open' })
+        .innerHTML = '<p><input _onfocus_="logOnFocus(this)" placeholder=""/></p>';
+  }
+}
+customElements.define('input-holder', InputHolder);
+
+class NestInputHolder extends HTMLElement {
+  constructor() {
+    super();
+
+    this.attachShadow({ mode: 'open' })
+        .innerHTML = `
+        <input _onfocus_="logOnFocus(this)" placeholder='7. input element before nested custom element having shadow tree' />
+        <input-holder></input-holder>
+        <input _onfocus_="logOnFocus(this)" placeholder='9. input element after nested custom element having shadow tree'/>
+        `;
+    this.shadowRoot.querySelector('input-holder')
+        .shadowRoot.querySelector('input').setAttribute('placeholder', '8. input element in nested shadow tree');
+  }
+}
+customElements.define('nest-input-holder', NestInputHolder);
+
+function logOnFocus(element) {
+    document.getElementById('log').textContent += element.getAttribute('placeholder') + '\n';
+}
+
+function testCase(documentOrShadowRoot, inputGetter) {
+    const inputElement = inputGetter(documentOrShadowRoot);
+    return {
+        documentOrShadowRoot,
+        inputElement,
+    };
+}
+
+async function runTest() {
+    const hostWithPositiveTabIndexShadowRoot = document.getElementById('host-with-positive-tabindex').shadowRoot;
+    const nestInputHolderShadowRoot = document.querySelector('nest-input-holder').shadowRoot;
+
+    const stack = [
+        testCase(document, (_) => document.getElementById('first')),
+
+        testCase(hostWithPositiveTabIndexShadowRoot,
+            (shadowRoot) => shadowRoot.querySelector('input[tabindex="1"]')),
+
+        testCase(document, (_) => document.getElementById('input-in-host-with-positive-tabindex-positive')),
+
+        testCase(document, (_) => document.getElementById('input-in-host-with-positive-tabindex')),
+
+        testCase(hostWithPositiveTabIndexShadowRoot,
+            (shadowRoot) => shadowRoot.querySelector('input[tabindex="0"]')),
+
+        testCase(document.getElementById('host-with-no-tabindex').shadowRoot,
+            (shadowRoot) => shadowRoot.querySelector('input[tabindex="0"]')),
+
+        testCase(document, (_) => document.getElementById('inpunt-descendants-of-closed-shadow-tree-host')),
+
+        testCase(nestInputHolderShadowRoot,
+            (shadowRoot) => shadowRoot.querySelector('input:nth-child(1)')),
+
+        testCase(nestInputHolderShadowRoot.querySelector('input-holder').shadowRoot,
+            (shadowRoot) => shadowRoot.querySelector('input')),
+
+        testCase(nestInputHolderShadowRoot,
+            (shadowRoot) => shadowRoot.querySelector('input:nth-last-child(1)')),
+
+        testCase(document, (_) => document.getElementById('last')),
+    ];
+
+    {
+        const firstElement = stack[0].inputElement;
+        debug('activate 0th input');
+        await UIHelper.activateElement(firstElement);
+        debug('activated 0th input');
+    }
+
+    for (let i = 1, l = stack.length; i < l; ++i) {
+        const { documentOrShadowRoot, inputElement, } = stack[i];
+
+        debug(`forward to ${String(i)}th input`);
+        await UIHelper.moveToNextByKeyboardAccessoryBar();
+        const activeElement = documentOrShadowRoot.activeElement;
+        debug(`documentOrShadowRoot.activeElement's placeholder attribute: ${activeElement.getAttribute('placeholder')}`);
+        shouldBe(() => activeElement.getAttribute('placeholder'), () => inputElement.getAttribute('placeholder'));
+    }
+
+    debug('focus has moved to the last element and will move to the first reversely');
+
+    for (let i = stack.length - 2; -1 < i; --i) {
+        debug(`back to ${String(i)}th input`);
+        await UIHelper.moveToPrevByKeyboardAccessoryBar();
+        const { documentOrShadowRoot, inputElement, } = stack[i];
+        const activeElement = documentOrShadowRoot.activeElement;
+        debug(`documentOrShadowRoot.activeElement's placeholder attribute: ${activeElement.getAttribute('placeholder')}`);
+        shouldBe(() => activeElement.getAttribute('placeholder'), () => inputElement.getAttribute('placeholder'));
+    }
+}
+
+if (window.testRunner) {
+    description(`Test that Accessory bar next/previous buttons work on inputs which is not assigned to any slot in shadow tree`);
+    const run = runTest().catch((e) => debug(`FAIL: \`${e}\``));
+    UIHelper.wait(run);
+} else
+    document.getElementById('console').style.display = 'none';
+
+</script>
+</body>
+</html>
\ No newline at end of file

Modified: trunk/LayoutTests/platform/ios/TestExpectations (269058 => 269059)


--- trunk/LayoutTests/platform/ios/TestExpectations	2020-10-27 18:46:56 UTC (rev 269058)
+++ trunk/LayoutTests/platform/ios/TestExpectations	2020-10-27 18:51:38 UTC (rev 269059)
@@ -3507,3 +3507,6 @@
 
 # This test fails in iOS due to subpixel differences for the marker position
 imported/w3c/web-platform-tests/css/css-lists/list-style-type-string-002.html [ ImageOnlyFailure ]
+
+# These tests are for iOS port. Should be pass.
+fast/shadow-dom/ios/ [ Pass ]

Modified: trunk/LayoutTests/resources/ui-helper.js (269058 => 269059)


--- trunk/LayoutTests/resources/ui-helper.js	2020-10-27 18:46:56 UTC (rev 269058)
+++ trunk/LayoutTests/resources/ui-helper.js	2020-10-27 18:51:38 UTC (rev 269059)
@@ -1386,6 +1386,26 @@
                 })();`, result => resolve(result === "true"));
         });
     }
+
+    static moveToNextByKeyboardAccessoryBar()
+    {
+        return new Promise((resolve) => {
+            testRunner.runUIScript(`
+                uiController.keyboardAccessoryBarNext();
+                uiController.uiScriptComplete();
+            `, resolve);
+        });
+    }
+
+    static moveToPrevByKeyboardAccessoryBar()
+    {
+        return new Promise((resolve) => {
+            testRunner.runUIScript(`
+                uiController.keyboardAccessoryBarPrevious();
+                uiController.uiScriptComplete();
+            `, resolve);
+        });
+    }
 }
 
 UIHelper.EventStreamBuilder = class {

Modified: trunk/Source/WebCore/ChangeLog (269058 => 269059)


--- trunk/Source/WebCore/ChangeLog	2020-10-27 18:46:56 UTC (rev 269058)
+++ trunk/Source/WebCore/ChangeLog	2020-10-27 18:51:38 UTC (rev 269059)
@@ -1,3 +1,16 @@
+2020-10-27  Tetsuharu Ohzeki  <[email protected]>
+
+        Accessory bar next/previous buttons do not work on inputs in shadow roots
+        https://bugs.webkit.org/show_bug.cgi?id=203292
+
+        Reviewed by Ryosuke Niwa.
+
+        Tests: fast/shadow-dom/ios/accessory-bar-work-on-input-with-tabindex-in-shadow-tree.html
+
+        * page/FocusController.cpp:
+        (WebCore::FocusController::nextFocusableElement):
+        (WebCore::FocusController::previousFocusableElement):
+
 2020-10-27  Michael Catanzaro  <[email protected]>
 
         Follow-up for: REGRESSION(r267727): Warning spam from JSC_DECLARE_CUSTOM_GETTER

Modified: trunk/Source/WebCore/page/FocusController.cpp (269058 => 269059)


--- trunk/Source/WebCore/page/FocusController.cpp	2020-10-27 18:46:56 UTC (rev 269058)
+++ trunk/Source/WebCore/page/FocusController.cpp	2020-10-27 18:51:38 UTC (rev 269059)
@@ -665,7 +665,7 @@
 {
     // FIXME: This can return a non-focusable shadow host.
     // FIXME: This can't give the correct answer that takes modifier keys into account since it doesn't pass an event.
-    return nextFocusableElementOrScopeOwner(FocusNavigationScope::scopeOf(start), &start, nullptr);
+    return findFocusableElementAcrossFocusScope(FocusDirection::Forward, FocusNavigationScope::scopeOf(start), &start, nullptr);
 }
 
 Element* FocusController::previousFocusableElement(Node& start)
@@ -672,7 +672,7 @@
 {
     // FIXME: This can return a non-focusable shadow host.
     // FIXME: This can't give the correct answer that takes modifier keys into account since it doesn't pass an event.
-    return previousFocusableElementOrScopeOwner(FocusNavigationScope::scopeOf(start), &start, nullptr);
+    return findFocusableElementAcrossFocusScope(FocusDirection::Backward, FocusNavigationScope::scopeOf(start), &start, nullptr);
 }
 
 Element* FocusController::nextFocusableElementOrScopeOwner(const FocusNavigationScope& scope, Node* start, KeyboardEvent* event)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to