Bug 1604140 - Part 1: Fix focus trap within shadow DOM when host is scrollable; r=smaug

The checks for `*TopLevelScopeOwner` are to skip the scope that we have already checked.
But when the shadow host is scrollable, we will traverse anonymous children for the scroll frame first in frame traversal and `oldTopLevelScopeOwner` will be reset.
Then we don't realize that we have already checked the host's scope.

Differential Revision: https://phabricator.services.mozilla.com/D60923

--HG--
rename : testing/web-platform/tests/shadow-dom/focus/focus-tabindex-order-shadow-zero-host-not-set.html => testing/web-platform/tests/shadow-dom/focus/focus-tabindex-order-shadow-zero-host-not-set-scrollable.html
extra : moz-landing-system : lando
This commit is contained in:
Edgar Chen 2020-02-07 14:38:46 +00:00
Родитель 7e767dd845
Коммит 82c858242e
2 изменённых файлов: 42 добавлений и 3 удалений

Просмотреть файл

@ -3401,15 +3401,16 @@ nsresult nsFocusManager::GetNextTabbableContent(
}
}
nsIContent* oldTopLevelScopeOwner = nullptr;
// Walk frames to find something tabbable matching aCurrentTabIndex
while (frame) {
// Try to find the topmost scope owner, since we want to skip the node
// that is not owned by document in frame traversal.
nsIContent* currentContent = frame->GetContent();
nsIContent* oldTopLevelScopeOwner = currentTopLevelScopeOwner;
if (!aForward || currentTopLevelScopeOwner != currentContent) {
currentTopLevelScopeOwner = GetTopLevelScopeOwner(currentContent);
if (currentTopLevelScopeOwner) {
oldTopLevelScopeOwner = currentTopLevelScopeOwner;
}
currentTopLevelScopeOwner = GetTopLevelScopeOwner(currentContent);
if (currentTopLevelScopeOwner &&
currentTopLevelScopeOwner == oldTopLevelScopeOwner) {
// We're within non-document scope, continue.

Просмотреть файл

@ -0,0 +1,38 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>HTML Test: focus - the sequential focus navigation order with shadow dom and scrollable/non-focusable host</title>
<link rel="help" href="https://html.spec.whatwg.org/multipage/interaction.html#sequential-focus-navigation">
<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/shadow-utils.js"></script>
<body>
<script>
// Structure:
// <div #aboveHost tabindex=0>
// <div #host style="overflow: scroll">
// #shadowRoot
// <div #aboveSlot tabindex=0>
// <slot #slotAbove tabindex=0>
// (slotted) <div #slottedAbove tabindex=0>
// <slot #slotBelow tabindex=0>
// (slotted) <div #slottedBelow tabindex=0>
// <div #belowSlot tabindex=0>
// <div #belowHost tabindex=0>
promise_test(() => {
let elementsInFlatTreeOrder;
let [aboveHost, host, aboveSlot, slotAbove, slottedAbove, slotBelow, slottedBelow, belowSlot, belowHost] =
elementsInFlatTreeOrder = prepareDOM(document.body, false);
setTabIndex(elementsInFlatTreeOrder, 0);
removeTabIndex([host]);
host.style = "overflow: scroll";
resetFocus();
// Focus should move in flat tree order since every one of them has tabindex ==0,
// but doesn't include #slot since it's not rendered and #host since its tabindex is not set
// (but #host is considered as 0 in focus scope navigation, keeping the flat tree order for the shadow root's descendants).
return assertFocusOrder(elementsInFlatTreeOrder.filter(el => (el !== slotAbove && el !== slotBelow && el !== host)));
}, "Order when all tabindex=0 except scrollable host (tabindex not set)");
</script>
</body>