Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / accessibility / browser_accessibility_manager_mac.mm
blobd4c1485d89939c9455921eb754e0c89eb6fc0492
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/accessibility/browser_accessibility_manager_mac.h"
7 #import "base/logging.h"
8 #import "content/browser/accessibility/browser_accessibility_cocoa.h"
9 #import "content/browser/accessibility/browser_accessibility_mac.h"
10 #include "content/common/accessibility_messages.h"
12 namespace content {
14 // static
15 BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
16     const ui::AXTreeUpdate& initial_tree,
17     BrowserAccessibilityDelegate* delegate,
18     BrowserAccessibilityFactory* factory) {
19   return new BrowserAccessibilityManagerMac(
20       NULL, initial_tree, delegate, factory);
23 BrowserAccessibilityManagerMac::BrowserAccessibilityManagerMac(
24     NSView* parent_view,
25     const ui::AXTreeUpdate& initial_tree,
26     BrowserAccessibilityDelegate* delegate,
27     BrowserAccessibilityFactory* factory)
28     : BrowserAccessibilityManager(delegate, factory),
29       parent_view_(parent_view) {
30   Initialize(initial_tree);
33 // static
34 ui::AXTreeUpdate BrowserAccessibilityManagerMac::GetEmptyDocument() {
35   ui::AXNodeData empty_document;
36   empty_document.id = 0;
37   empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA;
38   empty_document.state =
39       1 << ui::AX_STATE_READ_ONLY;
40   ui::AXTreeUpdate update;
41   update.nodes.push_back(empty_document);
42   return update;
45 BrowserAccessibility* BrowserAccessibilityManagerMac::GetFocus(
46     BrowserAccessibility* root) {
47   // On Mac, list boxes should always get focus on the whole list, otherwise
48   // information about the number of selected items will never be reported.
49   BrowserAccessibility* node = BrowserAccessibilityManager::GetFocus(root);
50   if (node && node->GetRole() == ui::AX_ROLE_LIST_BOX)
51     return node;
53   // For other roles, follow the active descendant.
54   return GetActiveDescendantFocus(root);
57 void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent(
58     ui::AXEvent event_type,
59     BrowserAccessibility* node) {
60   if (!node->IsNative())
61     return;
63   if (event_type == ui::AX_EVENT_FOCUS &&
64       node->GetRole() == ui::AX_ROLE_LIST_BOX_OPTION &&
65       node->HasState(ui::AX_STATE_SELECTED) &&
66       node->GetParent() &&
67       node->GetParent()->GetRole() == ui::AX_ROLE_LIST_BOX) {
68     node = node->GetParent();
69     SetFocus(node, false);
70   }
72   // Refer to AXObjectCache.mm (webkit).
73   NSString* event_id = @"";
74   switch (event_type) {
75     case ui::AX_EVENT_ACTIVEDESCENDANTCHANGED:
76       if (node->GetRole() == ui::AX_ROLE_TREE) {
77         event_id = NSAccessibilitySelectedRowsChangedNotification;
78       } else {
79         event_id = NSAccessibilityFocusedUIElementChangedNotification;
80         BrowserAccessibility* active_descendant_focus =
81             GetActiveDescendantFocus(GetRoot());
82         if (active_descendant_focus)
83           node = active_descendant_focus;
84       }
86       break;
87     case ui::AX_EVENT_ALERT:
88       // Not used on Mac.
89       return;
90     case ui::AX_EVENT_BLUR:
91       // A no-op on Mac.
92       return;
93     case ui::AX_EVENT_CHECKED_STATE_CHANGED:
94       // Not used on Mac.
95       return;
96     case ui::AX_EVENT_CHILDREN_CHANGED:
97       // TODO(dtseng): no clear equivalent on Mac.
98       return;
99     case ui::AX_EVENT_FOCUS:
100       event_id = NSAccessibilityFocusedUIElementChangedNotification;
101       break;
102     case ui::AX_EVENT_LAYOUT_COMPLETE:
103       event_id = @"AXLayoutComplete";
104       break;
105     case ui::AX_EVENT_LIVE_REGION_CHANGED:
106       event_id = @"AXLiveRegionChanged";
107       break;
108     case ui::AX_EVENT_LOAD_COMPLETE:
109       event_id = @"AXLoadComplete";
110       break;
111     case ui::AX_EVENT_MENU_LIST_VALUE_CHANGED:
112       // Not used on Mac.
113       return;
114     case ui::AX_EVENT_ROW_COUNT_CHANGED:
115       event_id = NSAccessibilityRowCountChangedNotification;
116       break;
117     case ui::AX_EVENT_ROW_COLLAPSED:
118       event_id = @"AXRowCollapsed";
119       break;
120     case ui::AX_EVENT_ROW_EXPANDED:
121       event_id = @"AXRowExpanded";
122       break;
123     case ui::AX_EVENT_SCROLLED_TO_ANCHOR:
124       // Not used on Mac.
125       return;
126     case ui::AX_EVENT_SELECTED_CHILDREN_CHANGED:
127       event_id = NSAccessibilitySelectedChildrenChangedNotification;
128       break;
129     case ui::AX_EVENT_TEXT_SELECTION_CHANGED:
130       event_id = NSAccessibilitySelectedTextChangedNotification;
131       break;
132     case ui::AX_EVENT_VALUE_CHANGED:
133       event_id = NSAccessibilityValueChangedNotification;
134       break;
135     case ui::AX_EVENT_ARIA_ATTRIBUTE_CHANGED:
136       // Not used on Mac.
137       return;
138     case ui::AX_EVENT_AUTOCORRECTION_OCCURED:
139       // Not used on Mac.
140       return;
141     case ui::AX_EVENT_INVALID_STATUS_CHANGED:
142       // Not used on Mac.
143       return;
144     case ui::AX_EVENT_LOCATION_CHANGED:
145       // Not used on Mac.
146       return;
147     case ui::AX_EVENT_MENU_LIST_ITEM_SELECTED:
148       // Not used on Mac.
149       return;
150     case ui::AX_EVENT_TEXT_CHANGED:
151       // Not used on Mac.
152       return;
153     default:
154       LOG(WARNING) << "Unknown accessibility event: " << event_type;
155       return;
156   }
158   BrowserAccessibilityCocoa* native_node = node->ToBrowserAccessibilityCocoa();
159   DCHECK(native_node);
160   NSAccessibilityPostNotification(native_node, event_id);
163 void BrowserAccessibilityManagerMac::OnAtomicUpdateFinished(
164     ui::AXTree* tree,
165     bool root_changed,
166     const std::vector<ui::AXTreeDelegate::Change>& changes) {
167   BrowserAccessibilityManager::OnAtomicUpdateFinished(
168       tree, root_changed, changes);
170   bool created_live_region = false;
171   for (size_t i = 0; i < changes.size(); ++i) {
172     if (changes[i].type != NODE_CREATED && changes[i].type != SUBTREE_CREATED)
173       continue;
174     BrowserAccessibility* obj = GetFromAXNode(changes[i].node);
175     if (obj && obj->HasStringAttribute(ui::AX_ATTR_LIVE_STATUS)) {
176       created_live_region = true;
177       break;
178     }
179   }
181   if (!created_live_region)
182     return;
184   // This code is to work around a bug in VoiceOver, where a new live
185   // region that gets added is ignored. VoiceOver seems to only scan the
186   // page for live regions once. By recreating the NSAccessibility
187   // object for the root of the tree, we force VoiceOver to clear out its
188   // internal state and find newly-added live regions this time.
189   BrowserAccessibilityMac* root =
190       static_cast<BrowserAccessibilityMac*>(GetRoot());
191   root->RecreateNativeObject();
192   NotifyAccessibilityEvent(ui::AX_EVENT_CHILDREN_CHANGED, root);
195 }  // namespace content