Skip to content

Commit 42a9dfc

Browse files
progerschromium-wpt-export-bot
authored andcommitted
Fix null canvas crash in Element::IsFocusableStyle
`Element::IsFocusableStyle` has special code that looks for a canvas ancestor, and this needs to be updated to cross frame boundaries. This regressed when https://crrev.com/1597048 changed `IsCanvasOrInCanvasSubtree` to be true in iframes, but the code in `Element::IsFocusableStyle` was not updated to find the ancestor canvas element through iframes. Fixed: 492245060 Change-Id: Ieb2f294760fb726ffeb56d1382366e08b9dcd8e7 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7750651 Auto-Submit: Philip Rogers <pdr@chromium.org> Reviewed-by: Stephen Chenney <schenney@chromium.org> Commit-Queue: Stephen Chenney <schenney@chromium.org> Cr-Commit-Position: refs/heads/main@{#1613437}
1 parent 153b3b7 commit 42a9dfc

1 file changed

Lines changed: 53 additions & 0 deletions

File tree

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<!DOCTYPE html>
2+
<meta charset="utf-8" />
3+
<title>Canvas descendant focusability in nested iframes</title>
4+
<link rel="help" href="https://html.spec.whatwg.org/multipage/canvas.html#being-used-as-relevant-canvas-fallback-content">
5+
<link rel="help" href="https://html.spec.whatwg.org/multipage/interaction.html#focusable-area">
6+
<meta name="assert" content="Checks that descendants of an iframe inside a canvas that represents fallback content are focusable.">
7+
<script src="/resources/testharness.js"></script>
8+
<script src="/resources/testharnessreport.js"></script>
9+
<div id="log"></div>
10+
<!-- Use a sandboxed iframe to disable scripting and make the canvas
11+
represent its fallback content instead of embedded content. -->
12+
<iframe id="outer" sandbox="allow-same-origin" allow="focus-without-user-activation *"></iframe>
13+
<script>
14+
setup({ explicit_done: true });
15+
setup(async () => {
16+
const outer = document.getElementById("outer");
17+
await new Promise(resolve => {
18+
outer.addEventListener("load", resolve, {once: true});
19+
outer.setAttribute("srcdoc", `
20+
<canvas>
21+
<iframe id="nested" allow="focus-without-user-activation *"></iframe>
22+
</canvas>
23+
`);
24+
});
25+
26+
const nested = outer.contentDocument.getElementById("nested");
27+
await new Promise(resolve => {
28+
nested.addEventListener("load", resolve, {once: true});
29+
nested.setAttribute("srcdoc", `
30+
<div id="div" tabindex="-1" data-focusable="true"></div>
31+
<select>
32+
<option id="option" tabindex="-1" data-focusable="false"></option>
33+
</select>
34+
`);
35+
});
36+
37+
const doc = nested.contentDocument;
38+
for (let element of doc.querySelectorAll("[data-focusable]")) {
39+
let title = element.cloneNode(false).outerHTML.toLowerCase();
40+
title = title.slice(0, title.lastIndexOf("<"));
41+
test(function() {
42+
assert_true(doc.activeElement !== element, "Not initially focused");
43+
element.focus();
44+
if (JSON.parse(element.dataset.focusable)) {
45+
assert_true(doc.activeElement === element, "Should be focused");
46+
} else {
47+
assert_true(doc.activeElement !== element, "Shouldn't be focused");
48+
}
49+
}, title);
50+
}
51+
done();
52+
});
53+
</script>

0 commit comments

Comments
 (0)