Commit d8314b72 authored by Joanmarie Diggs's avatar Joanmarie Diggs Committed by Commit Bot

Emit focus notifications when the active descendant changes

* Emit ATK focus and object:state-changed:focused events in response
  to ax::mojom::Event::kActiveDescendantChanged
* Add ATK_STATE_FOCUSED to the state set of the active descendant
* Update tests to reflect new events and states

Bug: 959857
Change-Id: Idb97671e1c4f65aa293e1e4e7dbd5a9ecf47fb2a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1631404Reviewed-by: default avatarMartin Robinson <mrobinson@igalia.com>
Commit-Queue: Joanmarie Diggs <jdiggs@igalia.com>
Auto-Submit: Joanmarie Diggs <jdiggs@igalia.com>
Cr-Commit-Position: refs/heads/master@{#663771}
parent 713731a9
......@@ -139,6 +139,9 @@ void BrowserAccessibilityManagerAuraLinux::FireGeneratedEvent(
FireEvent(focus_object, ax::mojom::Event::kTextSelectionChanged);
break;
}
case ui::AXEventGenerator::Event::ACTIVE_DESCENDANT_CHANGED:
FireEvent(node, ax::mojom::Event::kActiveDescendantChanged);
break;
case ui::AXEventGenerator::Event::CHECKED_STATE_CHANGED:
FireEvent(node, ax::mojom::Event::kCheckedStateChanged);
break;
......
CHILDREN-CHANGED index:0 CHILD:(role=ROLE_SECTION) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE
CHILDREN-CHANGED index:1 CHILD:(role=ROLE_LIST_BOX) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE
FOCUS-EVENT role=ROLE_LIST_ITEM name='Apple' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
STATE-CHANGE:FOCUSED:TRUE role=ROLE_LIST_ITEM name='Apple' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
......@@ -4,6 +4,7 @@
@WIN-DENY:EVENT_OBJECT_SHOW*
@WIN_DENY:IA2_EVENT_TEXT*
@UIA-WIN-DENY:StructureChanged/*
@AURALINUX-DENY:STATE-CHANGE:DEFUNCT*
-->
<!DOCTYPE html>
<html>
......
FOCUS-EVENT role=ROLE_LIST_ITEM name='Apple' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
SELECTION-CHANGED role=ROLE_LIST_BOX name='(null)' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
STATE-CHANGE:EXPANDED:TRUE role=ROLE_COMBO_BOX name='(null)' EDITABLE,ENABLED,EXPANDABLE,EXPANDED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,SINGLE-LINE,VISIBLE,SUPPORTS-AUTOCOMPLETION,SELECTABLE-TEXT
STATE-CHANGE:SELECTED:TRUE role=ROLE_LIST_ITEM name='Apple' ENABLED,FOCUSABLE,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
STATE-CHANGE:FOCUSED:TRUE role=ROLE_LIST_ITEM name='Apple' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
STATE-CHANGE:SELECTED:TRUE role=ROLE_LIST_ITEM name='Apple' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
FOCUS-EVENT role=ROLE_LIST_ITEM name='Banana' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
SELECTION-CHANGED role=ROLE_LIST_BOX name='(null)' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
STATE-CHANGE:SELECTED:TRUE role=ROLE_LIST_ITEM name='Banana' ENABLED,FOCUSABLE,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
STATE-CHANGE:FOCUSED:TRUE role=ROLE_LIST_ITEM name='Banana' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
STATE-CHANGE:SELECTED:TRUE role=ROLE_LIST_ITEM name='Banana' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
FOCUS-EVENT role=ROLE_TREE_ITEM name='Minor Ninth' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
SELECTION-CHANGED role=ROLE_TREE name='(null)' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
STATE-CHANGE:FOCUSED:TRUE role=ROLE_TREE_ITEM name='Minor Ninth' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
STATE-CHANGE:SELECTED:TRUE role=ROLE_TREE_ITEM name='Minor Ninth' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
......@@ -3,4 +3,4 @@ FOCUS-EVENT role=ROLE_LIST_ITEM name='Orange' ENABLED,FOCUSABLE,SELECTABLE,SELEC
SELECTION-CHANGED role=ROLE_LIST_BOX name='(null)' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
STATE-CHANGE:FOCUSED:FALSE role=ROLE_LIST_BOX name='(null)' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
STATE-CHANGE:FOCUSED:TRUE role=ROLE_LIST_ITEM name='Orange' ENABLED,FOCUSABLE,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
STATE-CHANGE:SELECTED:TRUE role=ROLE_LIST_ITEM name='Orange' ENABLED,FOCUSABLE,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
STATE-CHANGE:SELECTED:TRUE role=ROLE_LIST_ITEM name='Orange' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
......@@ -107,6 +107,12 @@ AXPlatformNode* g_root_application = nullptr;
// ATK_STATE_FOCUSED change to false.
AtkObject* g_current_focused = nullptr;
// The last AtkObject which was the active descendant in the currently-focused
// object (example: The highlighted option within a focused select element).
// As with g_current_focused, we track this to emit events when this object is
// no longer the active descendant.
AtkObject* g_current_active_descendant = nullptr;
// The last object which was selected. Tracking this is required because
// widgets in the browser UI only emit notifications upon becoming selected,
// but clients also expect notifications when items become unselected.
......@@ -2100,6 +2106,8 @@ void AXPlatformNodeAuraLinux::DestroyAtkObjects() {
if (atk_object_) {
if (atk_object_ == g_current_focused)
g_current_focused = nullptr;
if (atk_object_ == g_current_active_descendant)
SetWeakGPtrToAtkObject(&g_current_active_descendant, nullptr);
atk_object::Detach(AX_PLATFORM_NODE_AURALINUX(atk_object_));
g_object_unref(atk_object_);
......@@ -2515,6 +2523,19 @@ AtkRole AXPlatformNodeAuraLinux::GetAtkRole() {
}
}
static AtkObject* GetActiveDescendantOfCurrentFocused() {
if (!g_current_focused)
return nullptr;
auto* node = AtkObjectToAXPlatformNodeAuraLinux(g_current_focused);
int32_t id =
node->GetIntAttribute(ax::mojom::IntAttribute::kActivedescendantId);
if (auto* descendant = node->GetDelegate()->GetFromNodeID(id))
return descendant->GetNativeViewAccessible();
return nullptr;
}
void AXPlatformNodeAuraLinux::GetAtkState(AtkStateSet* atk_state_set) {
AXNodeData data = GetData();
......@@ -2614,6 +2635,14 @@ void AXPlatformNodeAuraLinux::GetAtkState(AtkStateSet* atk_state_set) {
if (delegate_->GetFocus() == GetNativeViewAccessible())
atk_state_set_add_state(atk_state_set, ATK_STATE_FOCUSED);
// It is insufficient to compare with g_current_activedescendant due to both
// timing and event ordering for objects which implement AtkSelection and also
// have an active descendant. For instance, if we check the state set of a
// selectable child, it will only have ATK_STATE_FOCUSED if we've processed
// the activedescendant change.
if (GetActiveDescendantOfCurrentFocused() == GetNativeViewAccessible())
atk_state_set_add_state(atk_state_set, ATK_STATE_FOCUSED);
}
struct AtkIntRelation {
......@@ -2948,6 +2977,43 @@ gfx::NativeViewAccessible AXPlatformNodeAuraLinux::GetNativeViewAccessible() {
return atk_object_;
}
void AXPlatformNodeAuraLinux::OnActiveDescendantChanged() {
DCHECK(atk_object_);
// Active-descendant-changed notifications are typically only relevant when
// the change is within the focused widget.
if (atk_object_ != g_current_focused)
return;
AtkObject* descendant = GetActiveDescendantOfCurrentFocused();
if (descendant == g_current_active_descendant)
return;
// If selection and focus are the same, when the active descendant changes
// as a result of selection, a focus event will be emitted. We don't want to
// emit duplicate notifications.
auto* node = AtkObjectToAXPlatformNodeAuraLinux(descendant);
if (node->SelectionAndFocusAreTheSame())
return;
// While there is an ATK active-descendant-changed event, it is meant for
// objects which manage their descendants (and claim to do so). The Core-AAM
// specification states that focus events should be emitted when the active
// descendant changes. This behavior is also consistent with Gecko.
if (g_current_active_descendant) {
g_signal_emit_by_name(g_current_active_descendant, "focus-event", false);
atk_object_notify_state_change(ATK_OBJECT(g_current_active_descendant),
ATK_STATE_FOCUSED, false);
}
SetWeakGPtrToAtkObject(&g_current_active_descendant, descendant);
if (g_current_active_descendant) {
g_signal_emit_by_name(g_current_active_descendant, "focus-event", true);
atk_object_notify_state_change(ATK_OBJECT(g_current_active_descendant),
ATK_STATE_FOCUSED, true);
}
}
void AXPlatformNodeAuraLinux::OnCheckedStateChanged() {
DCHECK(atk_object_);
......@@ -3272,6 +3338,9 @@ void AXPlatformNodeAuraLinux::NotifyAccessibilityEvent(
case ax::mojom::Event::kMenuPopupStart:
OnMenuPopupStart();
break;
case ax::mojom::Event::kActiveDescendantChanged:
OnActiveDescendantChanged();
break;
case ax::mojom::Event::kCheckedStateChanged:
OnCheckedStateChanged();
break;
......
......@@ -86,6 +86,7 @@ class AX_EXPORT AXPlatformNodeAuraLinux : public AXPlatformNodeBase {
void GetFloatAttributeInGValue(ax::mojom::FloatAttribute attr, GValue* value);
// Event helpers
void OnActiveDescendantChanged();
void OnCheckedStateChanged();
void OnExpandedStateChanged(bool is_expanded);
void OnFocused();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment