tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 934050dee1e16e24318a87cf1e8bb2116463455d
parent 79716282846e7660c6df31d363c63a8834e34db8
Author: Jacques Newman <janewman@microsoft.com>
Date:   Thu,  4 Dec 2025 16:55:05 +0000

Bug 2003736 [wpt PR 56441] - [focusgroup] Follow visual order., a=testonly

Automatic update from web-platform-tests
[focusgroup] Follow visual order.

This change refactors the utilities in FocusgroupControllerUtils to
follow the visual order as influenced by reading order. This
necessitates the introduction of FocusgroupVisualOrderTraversalContext,
which helps manage reading flow children's mappings, ensuring that we
don't need to recompute these while searching for the next focusgroup
item. The implementation largely follows how reading flow is handled in
`focus_controller.cc`.

Bug: 40210717
Change-Id: I468c02e5b23c1f46fd6e16c8d17f9e23027d68e5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7147450
Commit-Queue: Jacques Newman <janewman@microsoft.com>
Reviewed-by: Mason Freed <masonf@chromium.org>
Auto-Submit: Jacques Newman <janewman@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#1553172}

--

wpt-commits: 8043033ef62774d6132ff8481107f650a1259666
wpt-pr: 56441

Diffstat:
Atesting/web-platform/tests/html/interaction/focus/focusgroup/tentative/reading-flow-navigation/explicit-visual-reordering.html | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atesting/web-platform/tests/html/interaction/focus/focusgroup/tentative/reading-flow-navigation/fallback-to-dom-order.html | 33+++++++++++++++++++++++++++++++++
Atesting/web-platform/tests/html/interaction/focus/focusgroup/tentative/reading-flow-navigation/flex-visual-order-basic.html | 42++++++++++++++++++++++++++++++++++++++++++
Atesting/web-platform/tests/html/interaction/focus/focusgroup/tentative/reading-flow-navigation/nested-containers.html | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atesting/web-platform/tests/html/interaction/focus/focusgroup/tentative/reading-flow-navigation/partial-reordering.html | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atesting/web-platform/tests/html/interaction/focus/focusgroup/tentative/reading-flow-navigation/simple-mixed.html | 44++++++++++++++++++++++++++++++++++++++++++++
Mtesting/web-platform/tests/html/interaction/focus/focusgroup/tentative/resources/focusgroup-utils.js | 23+++++++++++++++++++++++
7 files changed, 351 insertions(+), 0 deletions(-)

diff --git a/testing/web-platform/tests/html/interaction/focus/focusgroup/tentative/reading-flow-navigation/explicit-visual-reordering.html b/testing/web-platform/tests/html/interaction/focus/focusgroup/tentative/reading-flow-navigation/explicit-visual-reordering.html @@ -0,0 +1,61 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>HTML Test: focusgroup - Reading flow with explicit visual reordering</title> +<link rel="author" title="Microsoft" href="http://www.microsoft.com/"> +<link rel="help" href="https://open-ui.org/components/scoped-focusgroup.explainer/"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="../resources/focusgroup-utils.js"></script> + +<style> +.flex-container { + display: flex; + flex-direction: row; + reading-flow: flex-visual; +} + +/* Explicitly reorder visual positions */ +.flex-container #item1 { + order: 4; /* Last visually */ +} + +.flex-container #item2 { + order: 1; /* First visually */ +} + +.flex-container #item3 { + order: 3; /* Third visually */ +} + +.flex-container #item4 { + order: 2; /* Second visually */ +} +</style> + +<div class="flex-container" focusgroup="toolbar"> + <span id=item1 tabindex=0>item1 (DOM 1st, visual 4th)</span> + <span id=item2 tabindex=0>item2 (DOM 2nd, visual 1st)</span> + <span id=item3 tabindex=0>item3 (DOM 3rd, visual 3rd)</span> + <span id=item4 tabindex=0>item4 (DOM 4th, visual 2nd)</span> +</div> + +<script> + + promise_test(async t => { + // Visual order due to flex order property and reading-flow: flex-visual + // DOM order: item1, item2, item3, item4 + // Visual order: item2 (order:1), item4 (order:2), item3 (order:3), item1 (order:4) + const elementsInVisualOrder = [ + document.getElementById("item2"), + document.getElementById("item4"), + document.getElementById("item3"), + document.getElementById("item1") + ]; + + await assert_focus_navigation_bidirectional(elementsInVisualOrder); + }, "Focusgroup navigation should follow explicit visual reordering via CSS order property."); + +</script> +\ No newline at end of file diff --git a/testing/web-platform/tests/html/interaction/focus/focusgroup/tentative/reading-flow-navigation/fallback-to-dom-order.html b/testing/web-platform/tests/html/interaction/focus/focusgroup/tentative/reading-flow-navigation/fallback-to-dom-order.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>HTML Test: focusgroup - Falls back to DOM order when no reading flow</title> +<link rel="author" title="Microsoft" href="http://www.microsoft.com/"> +<link rel="help" href="https://open-ui.org/components/scoped-focusgroup.explainer/"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="../resources/focusgroup-utils.js"></script> + +<div focusgroup="toolbar"> + <span id=item1 tabindex=0>item1</span> + <span id=item2 tabindex=-1>item2</span> + <span id=item3 tabindex=-1>item3</span> +</div> + +<script> + + promise_test(async t => { + // Without reading-flow, should follow DOM order: item1, item2, item3 + const elementsInDOMOrder = [ + document.getElementById("item1"), + document.getElementById("item2"), + document.getElementById("item3") + ]; + + await assert_focus_navigation_bidirectional(elementsInDOMOrder); + }, "Focusgroup navigation should fall back to DOM order when no reading-flow is specified."); + +</script> +\ No newline at end of file diff --git a/testing/web-platform/tests/html/interaction/focus/focusgroup/tentative/reading-flow-navigation/flex-visual-order-basic.html b/testing/web-platform/tests/html/interaction/focus/focusgroup/tentative/reading-flow-navigation/flex-visual-order-basic.html @@ -0,0 +1,41 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>HTML Test: focusgroup - Reading flow navigation respects flex visual order</title> +<link rel="author" title="Microsoft" href="http://www.microsoft.com/"> +<link rel="help" href="https://open-ui.org/components/scoped-focusgroup.explainer/"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="../resources/focusgroup-utils.js"></script> + +<style> +.flex-container { + display: flex; + flex-direction: row-reverse; + reading-flow: flex-visual; +} +</style> + +<div class="flex-container" focusgroup="toolbar"> + <span id=item1 tabindex=0>item1</span> + <span id=item2 tabindex=0>item2</span> + <span id=item3 tabindex=0>item3</span> +</div> + +<script> + + promise_test(async t => { + // Expected visual order due to flex-direction: row-reverse and reading-flow: flex-visual + // Visual order: item3, item2, item1 + const elementsInVisualOrder = [ + document.getElementById("item3"), + document.getElementById("item2"), + document.getElementById("item1") + ]; + + await assert_focus_navigation_bidirectional(elementsInVisualOrder); + }, "Focusgroup navigation should respect reading-flow: flex-visual order instead of DOM order."); + +</script> +\ No newline at end of file diff --git a/testing/web-platform/tests/html/interaction/focus/focusgroup/tentative/reading-flow-navigation/nested-containers.html b/testing/web-platform/tests/html/interaction/focus/focusgroup/tentative/reading-flow-navigation/nested-containers.html @@ -0,0 +1,57 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>HTML Test: focusgroup - Reading flow scope with nested containers</title> +<link rel="author" title="Microsoft" href="http://www.microsoft.com/"> +<link rel="help" href="https://open-ui.org/components/scoped-focusgroup.explainer/"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="../resources/focusgroup-utils.js"></script> + +<style> +.outer-flex { + display: flex; + reading-flow: flex-visual; +} +.inner-flex { + display: flex; + reading-flow: flex-visual; +} + +/* Reorder the outer container children */ +.outer-flex #item1 { order: 3; } +.outer-flex .inner-container { order: 1; } +.outer-flex #item4 { order: 2; } + +/* Reorder the inner container children */ +.inner-flex #item2 { order: 2; } +.inner-flex #item3 { order: 1; } +</style> + +<div class="outer-flex" focusgroup="toolbar"> + <span id=item1 tabindex=0>item1 (DOM 1, outer order 3)</span> + <div class="inner-flex inner-container"> + <span id=item2 tabindex=0>item2 (DOM 2, inner order 2)</span> + <span id=item3 tabindex=0>item3 (DOM 3, inner order 1)</span> + </div> + <span id=item4 tabindex=0>item4 (DOM 4, outer order 2)</span> +</div> + +<script> + + promise_test(async t => { + // DOM order: item1, item2, item3, item4 + // Visual order: item3, item2, item4, item1 + const elementsInVisualOrder = [ + document.getElementById("item3"), + document.getElementById("item2"), + document.getElementById("item4"), + document.getElementById("item1") + ]; + + await assert_focus_navigation_bidirectional(elementsInVisualOrder); + }, "Focusgroup navigation with nested reading flow containers should follow the visual order."); + +</script> +\ No newline at end of file diff --git a/testing/web-platform/tests/html/interaction/focus/focusgroup/tentative/reading-flow-navigation/partial-reordering.html b/testing/web-platform/tests/html/interaction/focus/focusgroup/tentative/reading-flow-navigation/partial-reordering.html @@ -0,0 +1,88 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>HTML Test: focusgroup - Multiple reading flow containers with complex visual reordering</title> +<link rel="author" title="Microsoft" href="http://www.microsoft.com/"> +<link rel="help" href="https://open-ui.org/components/scoped-focusgroup.explainer/"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="../resources/focusgroup-utils.js"></script> + +<style> +.reading-flow-container-reversed { + display: flex; + flex-direction: row-reverse; + reading-flow: flex-visual; +} + +.reading-flow-container { + display: flex; + reading-flow: flex-visual; +} + +.reading-flow-container-nested { + display: flex; + flex-direction: row-reverse; + reading-flow: flex-visual; +} + +/* Explicit order values for specific containers */ +.reading-flow-container #btn6 { order: 1; } +.reading-flow-container #btn7 { order: 2; } +.reading-flow-container #btn8 { order: 3; } +.reading-flow-container .reading-flow-container-nested { order: 4; } +.reading-flow-container #btn12 { order: 5; } +</style> + +<div focusgroup="toolbar wrap"> + <div class="reading-flow-container-reversed"> + <button id=btn3 tabindex=0>Button 3</button> + <button id=btn2 tabindex=0>Button 2</button> + <button id=btn1 tabindex=0>Button 1</button> + </div> + <button id=btn4 tabindex=0>Button 4</button> + <button id=btn5 tabindex=0>Button 5</button> + <div class="reading-flow-container"> + <button id=btn7 tabindex=0>Button 7</button> + <button id=btn6 tabindex=0>Button 6</button> + <button id=btn8 tabindex=0>Button 8</button> + <div class="reading-flow-container-nested"> + <button id=btn11 tabindex=0>Button 11</button> + <button id=btn10 tabindex=0>Button 10</button> + <button id=btn9 tabindex=0>Button 9</button> + </div> + <button id=btn12 tabindex=0>Button 12</button> + </div> + <button id=btn13 tabindex=0>Button 13</button> +</div> + +<script> + + promise_test(async t => { + // Get all button elements in their expected visual order based on CSS layout + // First container (row-reverse): btn1, btn2, btn3 + // Regular DOM: btn4, btn5 + // Second container (with explicit order): btn6, btn7, btn8, nested container (btn9, btn10, btn11), btn12 + // Regular DOM: btn13 + const buttonsInVisualOrder = [ + document.getElementById("btn1"), + document.getElementById("btn2"), + document.getElementById("btn3"), + document.getElementById("btn4"), + document.getElementById("btn5"), + document.getElementById("btn6"), + document.getElementById("btn7"), + document.getElementById("btn8"), + document.getElementById("btn9"), + document.getElementById("btn10"), + document.getElementById("btn11"), + document.getElementById("btn12"), + document.getElementById("btn13") + ]; + + await assert_focus_navigation_bidirectional(buttonsInVisualOrder, true); + }, "Focusgroup navigation with multiple reading-flow containers should follow visual order from CSS reading-flow properties."); + +</script> +\ No newline at end of file diff --git a/testing/web-platform/tests/html/interaction/focus/focusgroup/tentative/reading-flow-navigation/simple-mixed.html b/testing/web-platform/tests/html/interaction/focus/focusgroup/tentative/reading-flow-navigation/simple-mixed.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>HTML Test: focusgroup - Simple mixed reading flow test</title> +<link rel="author" title="Microsoft" href="http://www.microsoft.com/"> +<link rel="help" href="https://open-ui.org/components/scoped-focusgroup.explainer/"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="../resources/focusgroup-utils.js"></script> + +<style> +.container { + display: flex; + flex-direction: row-reverse; + reading-flow: flex-visual; +} +</style> + +<div focusgroup="toolbar"> + <div class="container"> + <button id="btn3" tabindex="0">Button 3</button> + <button id="btn2" tabindex="0">Button 2</button> + <button id="btn1" tabindex="0">Button 1</button> + </div> + <button id="btn4" tabindex="0">Button 4</button> +</div> + +<script> + promise_test(async t => { + // Visual order due to flex-direction: row-reverse and reading-flow: flex-visual + // Visual order: btn1, btn2, btn3, btn4 + const elementsInVisualOrder = [ + document.getElementById("btn1"), + document.getElementById("btn2"), + document.getElementById("btn3"), + document.getElementById("btn4") + ]; + + await assert_focus_navigation_bidirectional(elementsInVisualOrder); + }, "Simple mixed reading flow test."); +</script> +\ No newline at end of file diff --git a/testing/web-platform/tests/html/interaction/focus/focusgroup/tentative/resources/focusgroup-utils.js b/testing/web-platform/tests/html/interaction/focus/focusgroup/tentative/resources/focusgroup-utils.js @@ -17,3 +17,26 @@ function focusAndKeyPress(target, key) { function sendArrowKey(key) { return new test_driver.Actions().keyDown(key).keyUp(key).send(); } + +// Test bidirectional navigation through a list of elements in visual order. +// Tests forward navigation with kArrowRight and backward navigation with kArrowLeft. +// At boundaries, verifies focus does not move (unless wrap is expected). +async function assert_focus_navigation_bidirectional(elements, shouldWrap = false) { + // Test forward navigation. + for (let i = 0; i < elements.length; i++) { + await focusAndKeyPress(elements[i], kArrowRight); + const nextIndex = shouldWrap ? (i + 1) % elements.length : Math.min(i + 1, elements.length - 1); + const expectedElement = elements[nextIndex]; + assert_equals(document.activeElement, expectedElement, + `From ${elements[i].id}, right arrow should move to ${expectedElement.id}`); + } + + // Test backward navigation. + for (let i = elements.length - 1; i >= 0; i--) { + await focusAndKeyPress(elements[i], kArrowLeft); + const prevIndex = shouldWrap ? (i - 1 + elements.length) % elements.length : Math.max(i - 1, 0); + const expectedElement = elements[prevIndex]; + assert_equals(document.activeElement, expectedElement, + `From ${elements[i].id}, left arrow should move to ${expectedElement.id}`); + } +}