зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
2f5b54bbea
Коммит
f2a0bfe104
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче