Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / browser / accessibility / browser_accessibility_manager_mac.mm
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.
4
5 #include "content/browser/accessibility/browser_accessibility_manager_mac.h"
6
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"
11
12 namespace content {
13
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);
21 }
22
23 BrowserAccessibilityManagerMac::BrowserAccessibilityManagerMac(
24     NSView* parent_view,
25     const ui::AXTreeUpdate& initial_tree,
26     BrowserAccessibilityDelegate* delegate,
27     BrowserAccessibilityFactory* factory)
28     : BrowserAccessibilityManager(initial_tree, delegate, factory),
29       parent_view_(parent_view),
30       created_live_region_(false) {
31 }
32
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;
43 }
44
45 BrowserAccessibility* BrowserAccessibilityManagerMac::GetFocus(
46     BrowserAccessibility* root) {
47   BrowserAccessibility* node = GetActiveDescendantFocus(root);
48   return node;
49 }
50
51 void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent(
52     ui::AXEvent event_type,
53     BrowserAccessibility* node) {
54   if (!node->IsNative())
55     return;
56
57   // Refer to AXObjectCache.mm (webkit).
58   NSString* event_id = @"";
59   switch (event_type) {
60     case ui::AX_EVENT_ACTIVEDESCENDANTCHANGED:
61       if (node->GetRole() == ui::AX_ROLE_TREE) {
62         event_id = NSAccessibilitySelectedRowsChangedNotification;
63       } else {
64         event_id = NSAccessibilityFocusedUIElementChangedNotification;
65         BrowserAccessibility* active_descendant_focus =
66             GetActiveDescendantFocus(GetRoot());
67         if (active_descendant_focus)
68           node = active_descendant_focus;
69       }
70
71       break;
72     case ui::AX_EVENT_ALERT:
73       // Not used on Mac.
74       return;
75     case ui::AX_EVENT_BLUR:
76       // A no-op on Mac.
77       return;
78     case ui::AX_EVENT_CHECKED_STATE_CHANGED:
79       // Not used on Mac.
80       return;
81     case ui::AX_EVENT_CHILDREN_CHANGED:
82       // TODO(dtseng): no clear equivalent on Mac.
83       return;
84     case ui::AX_EVENT_FOCUS:
85       event_id = NSAccessibilityFocusedUIElementChangedNotification;
86       break;
87     case ui::AX_EVENT_LAYOUT_COMPLETE:
88       event_id = @"AXLayoutComplete";
89       break;
90     case ui::AX_EVENT_LIVE_REGION_CHANGED:
91       event_id = @"AXLiveRegionChanged";
92       break;
93     case ui::AX_EVENT_LOAD_COMPLETE:
94       event_id = @"AXLoadComplete";
95       break;
96     case ui::AX_EVENT_MENU_LIST_VALUE_CHANGED:
97       // Not used on Mac.
98       return;
99     case ui::AX_EVENT_ROW_COUNT_CHANGED:
100       event_id = NSAccessibilityRowCountChangedNotification;
101       break;
102     case ui::AX_EVENT_ROW_COLLAPSED:
103       event_id = @"AXRowCollapsed";
104       break;
105     case ui::AX_EVENT_ROW_EXPANDED:
106       event_id = @"AXRowExpanded";
107       break;
108     case ui::AX_EVENT_SCROLLED_TO_ANCHOR:
109       // Not used on Mac.
110       return;
111     case ui::AX_EVENT_SELECTED_CHILDREN_CHANGED:
112       event_id = NSAccessibilitySelectedChildrenChangedNotification;
113       break;
114     case ui::AX_EVENT_TEXT_SELECTION_CHANGED:
115       event_id = NSAccessibilitySelectedTextChangedNotification;
116       break;
117     case ui::AX_EVENT_VALUE_CHANGED:
118       event_id = NSAccessibilityValueChangedNotification;
119       break;
120     case ui::AX_EVENT_ARIA_ATTRIBUTE_CHANGED:
121       // Not used on Mac.
122       return;
123     case ui::AX_EVENT_AUTOCORRECTION_OCCURED:
124       // Not used on Mac.
125       return;
126     case ui::AX_EVENT_INVALID_STATUS_CHANGED:
127       // Not used on Mac.
128       return;
129     case ui::AX_EVENT_LOCATION_CHANGED:
130       // Not used on Mac.
131       return;
132     case ui::AX_EVENT_MENU_LIST_ITEM_SELECTED:
133       // Not used on Mac.
134       return;
135     case ui::AX_EVENT_TEXT_CHANGED:
136       // Not used on Mac.
137       return;
138     default:
139       LOG(WARNING) << "Unknown accessibility event: " << event_type;
140       return;
141   }
142   BrowserAccessibilityCocoa* native_node = node->ToBrowserAccessibilityCocoa();
143   DCHECK(native_node);
144   NSAccessibilityPostNotification(native_node, event_id);
145 }
146
147 void BrowserAccessibilityManagerMac::OnNodeCreationFinished(ui::AXNode* node) {
148   BrowserAccessibility* obj = GetFromAXNode(node);
149   if (obj && obj->HasStringAttribute(ui::AX_ATTR_LIVE_STATUS))
150     created_live_region_ = true;
151 }
152
153 void BrowserAccessibilityManagerMac::OnTreeUpdateFinished() {
154   if (!created_live_region_)
155     return;
156
157   // This code is to work around a bug in VoiceOver, where a new live
158   // region that gets added is ignored. VoiceOver seems to only scan the
159   // page for live regions once. By recreating the NSAccessibility
160   // object for the root of the tree, we force VoiceOver to clear out its
161   // internal state and find newly-added live regions this time.
162   BrowserAccessibilityMac* root =
163       static_cast<BrowserAccessibilityMac*>(GetRoot());
164   root->RecreateNativeObject();
165   NotifyAccessibilityEvent(ui::AX_EVENT_CHILDREN_CHANGED, root);
166
167   created_live_region_ = false;
168 }
169
170 }  // namespace content