Bug 1722621: Fix detection of autocomplete popups in XULListboxAccessible after recent DOM changes. r=morgan

Previously, we used GetFlattenedTreeParent from the list box to find the autocomplete popup.
After bug 1708735, this now returns a slot instead of the panel.
We now use GetParentElement instead, which works as expected and is consistent with other code in this class anyway.

I also added a new test so this doesn't regress yet again.
We already have test_focus_autocomplete.xhtml which is supposed to test this, but that test is broken, was thus disabled and is complicated enough that I don't think we're going to fix it any time soon, if ever.

The new test was triggering an assertion on Windows when trying to handle a caret event, so HyperTextAccessible::GetCaretRect had to be tweaked slightly to fix this.

Differential Revision: https://phabricator.services.mozilla.com/D121163
This commit is contained in:
James Teh 2021-07-30 18:03:04 +00:00
Родитель 2f5b54bbea
Коммит f2a0bfe104
4 изменённых файлов: 96 добавлений и 4 удалений

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

@ -1818,8 +1818,16 @@ LayoutDeviceIntRect HyperTextAccessible::GetCaretRect(nsIWidget** aWidget) {
// the character. This is important for font size transitions, and is // the character. This is important for font size transitions, and is
// necessary because the Gecko caret uses the previous character's size as // necessary because the Gecko caret uses the previous character's size as
// the user moves forward in the text by character. // the user moves forward in the text by character.
int32_t caretOffset = CaretOffset();
if (NS_WARN_IF(caretOffset == -1)) {
// The caret offset will be -1 if this Accessible isn't focused. Note that
// the DOM node contaning the caret might be focused, but the Accessible
// might not be; e.g. due to an autocomplete popup suggestion having a11y
// focus.
return LayoutDeviceIntRect();
}
nsIntRect charRect = CharBounds( nsIntRect charRect = CharBounds(
CaretOffset(), nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE); caretOffset, nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE);
if (!charRect.IsEmpty()) { if (!charRect.IsEmpty()) {
caretRect.SetTopEdge(charRect.Y()); caretRect.SetTopEdge(charRect.Y());
} }

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

@ -23,6 +23,7 @@ support-files =
[test_flush.html] [test_flush.html]
[test_focusable_statechange.html] [test_focusable_statechange.html]
[test_focus_aria_activedescendant.html] [test_focus_aria_activedescendant.html]
[test_focus_autocomplete.html]
[test_focus_autocomplete.xhtml] [test_focus_autocomplete.xhtml]
# Disabled on Linux and Windows due to frequent failures - bug 695019, bug 890795 # Disabled on Linux and Windows due to frequent failures - bug 695019, bug 890795
skip-if = os == 'win' || os == 'linux' skip-if = os == 'win' || os == 'linux'

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

@ -0,0 +1,83 @@
<!doctype html>
<head>
<title>Form Autocomplete Tests</title>
<link rel="stylesheet"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script src="../common.js"></script>
<script src="../promisified-events.js"></script>
<script src="../role.js"></script>
<script type="application/javascript">
const { TestUtils } = ChromeUtils.import(
"resource://testing-common/TestUtils.jsm");
async function waitForFocusOnOptionWithname(name) {
let event = await waitForEvent(
EVENT_FOCUS,
evt => evt.accessible.role == ROLE_COMBOBOX_OPTION
);
if (!event.accessible.name) {
// Sometimes, the name is null for a very short time after the focus
// event.
await waitForEvent(EVENT_NAME_CHANGE, event.accessible);
}
is(event.accessible.name, name, "Got focus on option with name " + name);
}
async function doTests() {
const input = getNode("input");
info("Focusing the input");
let focused = waitForEvent(EVENT_FOCUS, input);
input.focus();
await focused;
let shown = waitForEvent(EVENT_SHOW, event =>
event.accessible.role == ROLE_GROUPING &&
event.accessible.firstChild.role == ROLE_COMBOBOX_LIST);
info("Pressing ArrowDown to open the popup");
synthesizeKey("KEY_ArrowDown");
await shown;
// The popup still doesn't seem to be ready even once it's fired an a11y
// show event!
const controller = Cc["@mozilla.org/autocomplete/controller;1"].
getService(Ci.nsIAutoCompleteController);
info("Waiting for popup to be fully open and ready");
await TestUtils.waitForCondition(() => controller.input.popupOpen);
focused = waitForFocusOnOptionWithname("a");
info("Pressing ArrowDown to focus first item");
synthesizeKey("KEY_ArrowDown");
await focused;
focused = waitForFocusOnOptionWithname("b");
info("Pressing ArrowDown to focus the second item");
synthesizeKey("KEY_ArrowDown");
await focused;
focused = waitForEvent(EVENT_FOCUS, input);
info("Pressing enter to select the second item");
synthesizeKey("KEY_Enter");
await focused;
is(input.value, "b", "input value filled with second item");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTests);
</script>
</head>
<body>
<input id="input" list="list">
<datalist id="list">
<option id="a" value="a">
<option id="b" value="b">
</datalist>
</body>
</html>

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

@ -67,10 +67,10 @@ bool XULColumnItemAccessible::DoAction(uint8_t aIndex) const {
XULListboxAccessible::XULListboxAccessible(nsIContent* aContent, XULListboxAccessible::XULListboxAccessible(nsIContent* aContent,
DocAccessible* aDoc) DocAccessible* aDoc)
: XULSelectControlAccessible(aContent, aDoc) { : XULSelectControlAccessible(aContent, aDoc) {
nsIContent* parentContent = mContent->GetFlattenedTreeParent(); dom::Element* parentEl = mContent->GetParentElement();
if (parentContent) { if (parentEl) {
nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm = nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
parentContent->AsElement()->AsAutoCompletePopup(); parentEl->AsAutoCompletePopup();
if (autoCompletePopupElm) mGenericTypes |= eAutoCompletePopup; if (autoCompletePopupElm) mGenericTypes |= eAutoCompletePopup;
} }