| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/views/accessibility_event_router_views.h" | 5 #include "chrome/browser/views/accessibility_event_router_views.h" |
| 6 | 6 |
| 7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 8 #include "base/callback.h" | 8 #include "base/callback.h" |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
| 11 #include "chrome/browser/extensions/extension_accessibility_api.h" | 11 #include "chrome/browser/extensions/extension_accessibility_api.h" |
| 12 #include "chrome/browser/profile.h" | 12 #include "chrome/browser/profile.h" |
| 13 #include "chrome/common/notification_type.h" | 13 #include "chrome/common/notification_type.h" |
| 14 #include "views/accessibility/accessibility_types.h" |
| 14 #include "views/controls/button/image_button.h" | 15 #include "views/controls/button/image_button.h" |
| 15 #include "views/controls/button/menu_button.h" | 16 #include "views/controls/button/menu_button.h" |
| 16 #include "views/controls/button/native_button.h" | 17 #include "views/controls/button/native_button.h" |
| 17 #include "views/controls/link.h" | 18 #include "views/controls/link.h" |
| 19 #include "views/controls/menu/menu_item_view.h" |
| 20 #include "views/controls/menu/submenu_view.h" |
| 18 | 21 |
| 19 using views::FocusManager; | 22 using views::FocusManager; |
| 20 using views::View; | 23 using views::View; |
| 21 | 24 |
| 22 AccessibilityEventRouterViews::AccessibilityEventRouterViews() | 25 AccessibilityEventRouterViews::AccessibilityEventRouterViews() |
| 23 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { | 26 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { |
| 24 } | 27 } |
| 25 | 28 |
| 26 AccessibilityEventRouterViews::~AccessibilityEventRouterViews() { | 29 AccessibilityEventRouterViews::~AccessibilityEventRouterViews() { |
| 27 } | 30 } |
| 28 | 31 |
| 29 // static | 32 // static |
| 30 AccessibilityEventRouterViews* AccessibilityEventRouterViews::GetInstance() { | 33 AccessibilityEventRouterViews* AccessibilityEventRouterViews::GetInstance() { |
| 31 return Singleton<AccessibilityEventRouterViews>::get(); | 34 return Singleton<AccessibilityEventRouterViews>::get(); |
| 32 } | 35 } |
| 33 | 36 |
| 34 bool AccessibilityEventRouterViews::AddViewTree(View* view, Profile* profile) { | 37 bool AccessibilityEventRouterViews::AddViewTree(View* view, Profile* profile) { |
| 35 if (view_tree_profile_map_[view] != NULL) | 38 if (view_tree_profile_map_[view] != NULL) |
| 36 return false; | 39 return false; |
| 37 | 40 |
| 38 view_tree_profile_map_[view] = profile; | 41 view_tree_profile_map_[view] = profile; |
| 39 FocusManager* focus_manager = view->GetFocusManager(); | |
| 40 | |
| 41 // Add this object as a listener for this focus manager, but use a ref | |
| 42 // count to ensure we only call AddFocusChangeListener on any given | |
| 43 // focus manager once. Note that hash_map<FocusManager*, int>::operator[] | |
| 44 // will initialize the ref count to zero if it's not already in the map. | |
| 45 if (focus_manager_ref_count_[focus_manager] == 0) { | |
| 46 focus_manager->AddFocusChangeListener(this); | |
| 47 } | |
| 48 focus_manager_ref_count_[focus_manager]++; | |
| 49 | |
| 50 view_info_map_[view].focus_manager = focus_manager; | |
| 51 return true; | 42 return true; |
| 52 } | 43 } |
| 53 | 44 |
| 54 void AccessibilityEventRouterViews::RemoveViewTree(View* view) { | 45 void AccessibilityEventRouterViews::RemoveViewTree(View* view) { |
| 55 DCHECK(view_tree_profile_map_.find(view) != | 46 DCHECK(view_tree_profile_map_.find(view) != |
| 56 view_tree_profile_map_.end()); | 47 view_tree_profile_map_.end()); |
| 57 view_tree_profile_map_.erase(view); | 48 view_tree_profile_map_.erase(view); |
| 58 | |
| 59 // Decrement the ref count of the focus manager, and remove this object | |
| 60 // as a listener if the count reaches zero. | |
| 61 FocusManager* focus_manager = view_info_map_[view].focus_manager; | |
| 62 DCHECK(focus_manager); | |
| 63 focus_manager_ref_count_[focus_manager]--; | |
| 64 if (focus_manager_ref_count_[focus_manager] == 0) { | |
| 65 focus_manager->RemoveFocusChangeListener(this); | |
| 66 } | |
| 67 } | 49 } |
| 68 | 50 |
| 69 void AccessibilityEventRouterViews::IgnoreView(View* view) { | 51 void AccessibilityEventRouterViews::IgnoreView(View* view) { |
| 70 view_info_map_[view].ignore = true; | 52 view_info_map_[view].ignore = true; |
| 71 } | 53 } |
| 72 | 54 |
| 73 void AccessibilityEventRouterViews::SetViewName(View* view, std::string name) { | 55 void AccessibilityEventRouterViews::SetViewName(View* view, std::string name) { |
| 74 view_info_map_[view].name = name; | 56 view_info_map_[view].name = name; |
| 75 } | 57 } |
| 76 | 58 |
| 77 void AccessibilityEventRouterViews::RemoveView(View* view) { | 59 void AccessibilityEventRouterViews::RemoveView(View* view) { |
| 78 DCHECK(view_info_map_.find(view) != view_info_map_.end()); | 60 DCHECK(view_info_map_.find(view) != view_info_map_.end()); |
| 79 view_info_map_.erase(view); | 61 view_info_map_.erase(view); |
| 80 } | 62 } |
| 81 | 63 |
| 82 // | 64 void AccessibilityEventRouterViews::HandleAccessibilityEvent( |
| 83 // views::FocusChangeListener | 65 views::View* view, AccessibilityTypes::Event event_type) { |
| 84 // | 66 switch (event_type) { |
| 85 | 67 case AccessibilityTypes::EVENT_FOCUS: |
| 86 void AccessibilityEventRouterViews::FocusWillChange( | 68 DispatchAccessibilityNotification( |
| 87 View* focused_before, View* focused_now) { | 69 view, NotificationType::ACCESSIBILITY_CONTROL_FOCUSED); |
| 88 if (focused_now) { | 70 break; |
| 89 DispatchAccessibilityNotification( | 71 case AccessibilityTypes::EVENT_MENUSTART: |
| 90 focused_now, NotificationType::ACCESSIBILITY_CONTROL_FOCUSED); | 72 case AccessibilityTypes::EVENT_MENUPOPUPSTART: |
| 73 DispatchAccessibilityNotification( |
| 74 view, NotificationType::ACCESSIBILITY_MENU_OPENED); |
| 75 break; |
| 76 case AccessibilityTypes::EVENT_MENUEND: |
| 77 case AccessibilityTypes::EVENT_MENUPOPUPEND: |
| 78 DispatchAccessibilityNotification( |
| 79 view, NotificationType::ACCESSIBILITY_MENU_CLOSED); |
| 80 break; |
| 91 } | 81 } |
| 92 } | 82 } |
| 93 | 83 |
| 94 // | 84 // |
| 95 // Private methods | 85 // Private methods |
| 96 // | 86 // |
| 97 | 87 |
| 98 void AccessibilityEventRouterViews::FindView( | 88 void AccessibilityEventRouterViews::FindView( |
| 99 View* view, Profile** profile, bool* is_accessible) { | 89 View* view, Profile** profile, bool* is_accessible) { |
| 100 *is_accessible = false; | 90 *is_accessible = false; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 138 } | 128 } |
| 139 | 129 |
| 140 return name; | 130 return name; |
| 141 } | 131 } |
| 142 | 132 |
| 143 void AccessibilityEventRouterViews::DispatchAccessibilityNotification( | 133 void AccessibilityEventRouterViews::DispatchAccessibilityNotification( |
| 144 View* view, NotificationType type) { | 134 View* view, NotificationType type) { |
| 145 Profile* profile = NULL; | 135 Profile* profile = NULL; |
| 146 bool is_accessible; | 136 bool is_accessible; |
| 147 FindView(view, &profile, &is_accessible); | 137 FindView(view, &profile, &is_accessible); |
| 138 |
| 139 // Special case: a menu isn't associated with any particular top-level |
| 140 // window, so menu events get routed to the profile of the most recent |
| 141 // event that was associated with a window, which should be the window |
| 142 // that triggered opening the menu. |
| 143 bool is_menu_event = IsMenuEvent(view, type); |
| 144 if (is_menu_event && !profile && most_recent_profile_) { |
| 145 profile = most_recent_profile_; |
| 146 is_accessible = true; |
| 147 } |
| 148 |
| 148 if (!is_accessible) | 149 if (!is_accessible) |
| 149 return; | 150 return; |
| 150 | 151 |
| 151 if (view->GetClassName() == views::ImageButton::kViewClassName) { | 152 most_recent_profile_ = profile; |
| 153 |
| 154 AccessibilityTypes::Role role; |
| 155 view->GetAccessibleRole(&role); |
| 156 std::string class_name = view->GetClassName(); |
| 157 |
| 158 if (class_name == views::MenuButton::kViewClassName || |
| 159 type == NotificationType::ACCESSIBILITY_MENU_OPENED || |
| 160 type == NotificationType::ACCESSIBILITY_MENU_CLOSED) { |
| 161 SendMenuNotification(view, type, profile); |
| 162 } else if (is_menu_event) { |
| 163 SendMenuItemNotification(view, type, profile); |
| 164 } else if (class_name == views::ImageButton::kViewClassName || |
| 165 class_name == views::NativeButton::kViewClassName || |
| 166 class_name == views::TextButton::kViewClassName) { |
| 152 SendButtonNotification(view, type, profile); | 167 SendButtonNotification(view, type, profile); |
| 153 } else if (view->GetClassName() == views::NativeButton::kViewClassName) { | 168 } else if (class_name == views::Link::kViewClassName) { |
| 154 SendButtonNotification(view, type, profile); | |
| 155 } else if (view->GetClassName() == views::Link::kViewClassName) { | |
| 156 SendLinkNotification(view, type, profile); | 169 SendLinkNotification(view, type, profile); |
| 157 } else if (view->GetClassName() == views::MenuButton::kViewClassName) { | |
| 158 SendMenuNotification(view, type, profile); | |
| 159 } | 170 } |
| 160 } | 171 } |
| 161 | 172 |
| 162 void AccessibilityEventRouterViews::SendButtonNotification( | 173 void AccessibilityEventRouterViews::SendButtonNotification( |
| 163 View* view, NotificationType type, Profile* profile) { | 174 View* view, NotificationType type, Profile* profile) { |
| 164 AccessibilityButtonInfo info(profile, GetViewName(view)); | 175 AccessibilityButtonInfo info(profile, GetViewName(view)); |
| 165 SendAccessibilityNotification(type, &info); | 176 SendAccessibilityNotification(type, &info); |
| 166 } | 177 } |
| 167 | 178 |
| 168 void AccessibilityEventRouterViews::SendLinkNotification( | 179 void AccessibilityEventRouterViews::SendLinkNotification( |
| 169 View* view, NotificationType type, Profile* profile) { | 180 View* view, NotificationType type, Profile* profile) { |
| 170 AccessibilityLinkInfo info(profile, GetViewName(view)); | 181 AccessibilityLinkInfo info(profile, GetViewName(view)); |
| 171 SendAccessibilityNotification(type, &info); | 182 SendAccessibilityNotification(type, &info); |
| 172 } | 183 } |
| 173 | 184 |
| 174 void AccessibilityEventRouterViews::SendMenuNotification( | 185 void AccessibilityEventRouterViews::SendMenuNotification( |
| 175 View* view, NotificationType type, Profile* profile) { | 186 View* view, NotificationType type, Profile* profile) { |
| 176 AccessibilityMenuInfo info(profile, GetViewName(view)); | 187 AccessibilityMenuInfo info(profile, GetViewName(view)); |
| 177 SendAccessibilityNotification(type, &info); | 188 SendAccessibilityNotification(type, &info); |
| 178 } | 189 } |
| 190 |
| 191 void AccessibilityEventRouterViews::SendMenuItemNotification( |
| 192 View* view, NotificationType type, Profile* profile) { |
| 193 std::string name = GetViewName(view); |
| 194 |
| 195 bool has_submenu = false; |
| 196 int index = -1; |
| 197 int count = -1; |
| 198 |
| 199 if (view->GetClassName() == views::MenuItemView::kViewClassName) |
| 200 has_submenu = static_cast<views::MenuItemView*>(view)->HasSubmenu(); |
| 201 |
| 202 View* parent_menu = view->GetParent(); |
| 203 while (parent_menu != NULL && parent_menu->GetClassName() != |
| 204 views::SubmenuView::kViewClassName) { |
| 205 parent_menu = parent_menu->GetParent(); |
| 206 } |
| 207 if (parent_menu) { |
| 208 count = 0; |
| 209 RecursiveGetMenuItemIndexAndCount(parent_menu, view, &index, &count); |
| 210 } |
| 211 |
| 212 AccessibilityMenuItemInfo info(profile, name, has_submenu, index, count); |
| 213 SendAccessibilityNotification(type, &info); |
| 214 } |
| 215 |
| 216 void AccessibilityEventRouterViews::RecursiveGetMenuItemIndexAndCount( |
| 217 views::View* menu, views::View* item, int* index, int* count) { |
| 218 for (int i = 0; i < menu->GetChildViewCount(); ++i) { |
| 219 views::View* child = menu->GetChildViewAt(i); |
| 220 int previous_count = *count; |
| 221 RecursiveGetMenuItemIndexAndCount(child, item, index, count); |
| 222 if (child->GetClassName() == views::MenuItemView::kViewClassName && |
| 223 *count == previous_count) { |
| 224 if (item == child) |
| 225 *index = *count; |
| 226 (*count)++; |
| 227 } else if (child->GetClassName() == views::TextButton::kViewClassName) { |
| 228 if (item == child) |
| 229 *index = *count; |
| 230 (*count)++; |
| 231 } |
| 232 } |
| 233 } |
| 234 |
| 235 bool AccessibilityEventRouterViews::IsMenuEvent( |
| 236 View* view, NotificationType type) { |
| 237 if (type == NotificationType::ACCESSIBILITY_MENU_OPENED || |
| 238 type == NotificationType::ACCESSIBILITY_MENU_CLOSED) |
| 239 return true; |
| 240 |
| 241 while (view) { |
| 242 AccessibilityTypes::Role role; |
| 243 view->GetAccessibleRole(&role); |
| 244 if (role == AccessibilityTypes::ROLE_MENUITEM || |
| 245 role == AccessibilityTypes::ROLE_MENUPOPUP) { |
| 246 return true; |
| 247 } |
| 248 view = view->GetParent(); |
| 249 } |
| 250 |
| 251 return false; |
| 252 } |
| OLD | NEW |