Index: chrome/browser/views/accessibility_event_router_views.cc |
=================================================================== |
--- chrome/browser/views/accessibility_event_router_views.cc (revision 55065) |
+++ chrome/browser/views/accessibility_event_router_views.cc (working copy) |
@@ -11,10 +11,13 @@ |
#include "chrome/browser/extensions/extension_accessibility_api.h" |
#include "chrome/browser/profile.h" |
#include "chrome/common/notification_type.h" |
+#include "views/accessibility/accessibility_types.h" |
#include "views/controls/button/image_button.h" |
#include "views/controls/button/menu_button.h" |
#include "views/controls/button/native_button.h" |
#include "views/controls/link.h" |
+#include "views/controls/menu/menu_item_view.h" |
+#include "views/controls/menu/submenu_view.h" |
using views::FocusManager; |
using views::View; |
@@ -36,18 +39,6 @@ |
return false; |
view_tree_profile_map_[view] = profile; |
- FocusManager* focus_manager = view->GetFocusManager(); |
- |
- // Add this object as a listener for this focus manager, but use a ref |
- // count to ensure we only call AddFocusChangeListener on any given |
- // focus manager once. Note that hash_map<FocusManager*, int>::operator[] |
- // will initialize the ref count to zero if it's not already in the map. |
- if (focus_manager_ref_count_[focus_manager] == 0) { |
- focus_manager->AddFocusChangeListener(this); |
- } |
- focus_manager_ref_count_[focus_manager]++; |
- |
- view_info_map_[view].focus_manager = focus_manager; |
return true; |
} |
@@ -55,15 +46,6 @@ |
DCHECK(view_tree_profile_map_.find(view) != |
view_tree_profile_map_.end()); |
view_tree_profile_map_.erase(view); |
- |
- // Decrement the ref count of the focus manager, and remove this object |
- // as a listener if the count reaches zero. |
- FocusManager* focus_manager = view_info_map_[view].focus_manager; |
- DCHECK(focus_manager); |
- focus_manager_ref_count_[focus_manager]--; |
- if (focus_manager_ref_count_[focus_manager] == 0) { |
- focus_manager->RemoveFocusChangeListener(this); |
- } |
} |
void AccessibilityEventRouterViews::IgnoreView(View* view) { |
@@ -79,15 +61,23 @@ |
view_info_map_.erase(view); |
} |
-// |
-// views::FocusChangeListener |
-// |
- |
-void AccessibilityEventRouterViews::FocusWillChange( |
- View* focused_before, View* focused_now) { |
- if (focused_now) { |
- DispatchAccessibilityNotification( |
- focused_now, NotificationType::ACCESSIBILITY_CONTROL_FOCUSED); |
+void AccessibilityEventRouterViews::HandleAccessibilityEvent( |
+ views::View* view, AccessibilityTypes::Event event_type) { |
+ switch (event_type) { |
+ case AccessibilityTypes::EVENT_FOCUS: |
+ DispatchAccessibilityNotification( |
+ view, NotificationType::ACCESSIBILITY_CONTROL_FOCUSED); |
+ break; |
+ case AccessibilityTypes::EVENT_MENUSTART: |
+ case AccessibilityTypes::EVENT_MENUPOPUPSTART: |
+ DispatchAccessibilityNotification( |
+ view, NotificationType::ACCESSIBILITY_MENU_OPENED); |
+ break; |
+ case AccessibilityTypes::EVENT_MENUEND: |
+ case AccessibilityTypes::EVENT_MENUPOPUPEND: |
+ DispatchAccessibilityNotification( |
+ view, NotificationType::ACCESSIBILITY_MENU_CLOSED); |
+ break; |
} |
} |
@@ -145,17 +135,38 @@ |
Profile* profile = NULL; |
bool is_accessible; |
FindView(view, &profile, &is_accessible); |
+ |
+ // Special case: a menu isn't associated with any particular top-level |
+ // window, so menu events get routed to the profile of the most recent |
+ // event that was associated with a window, which should be the window |
+ // that triggered opening the menu. |
+ bool is_menu_event = IsMenuEvent(view, type); |
+ if (is_menu_event && !profile && most_recent_profile_) { |
+ profile = most_recent_profile_; |
+ is_accessible = true; |
+ } |
+ |
if (!is_accessible) |
return; |
- if (view->GetClassName() == views::ImageButton::kViewClassName) { |
+ most_recent_profile_ = profile; |
+ |
+ AccessibilityTypes::Role role; |
+ view->GetAccessibleRole(&role); |
+ std::string class_name = view->GetClassName(); |
+ |
+ if (class_name == views::MenuButton::kViewClassName || |
+ type == NotificationType::ACCESSIBILITY_MENU_OPENED || |
+ type == NotificationType::ACCESSIBILITY_MENU_CLOSED) { |
+ SendMenuNotification(view, type, profile); |
+ } else if (is_menu_event) { |
+ SendMenuItemNotification(view, type, profile); |
+ } else if (class_name == views::ImageButton::kViewClassName || |
+ class_name == views::NativeButton::kViewClassName || |
+ class_name == views::TextButton::kViewClassName) { |
SendButtonNotification(view, type, profile); |
- } else if (view->GetClassName() == views::NativeButton::kViewClassName) { |
- SendButtonNotification(view, type, profile); |
- } else if (view->GetClassName() == views::Link::kViewClassName) { |
+ } else if (class_name == views::Link::kViewClassName) { |
SendLinkNotification(view, type, profile); |
- } else if (view->GetClassName() == views::MenuButton::kViewClassName) { |
- SendMenuNotification(view, type, profile); |
} |
} |
@@ -176,3 +187,66 @@ |
AccessibilityMenuInfo info(profile, GetViewName(view)); |
SendAccessibilityNotification(type, &info); |
} |
+ |
+void AccessibilityEventRouterViews::SendMenuItemNotification( |
+ View* view, NotificationType type, Profile* profile) { |
+ std::string name = GetViewName(view); |
+ |
+ bool has_submenu = false; |
+ int index = -1; |
+ int count = -1; |
+ |
+ if (view->GetClassName() == views::MenuItemView::kViewClassName) |
+ has_submenu = static_cast<views::MenuItemView*>(view)->HasSubmenu(); |
+ |
+ View* parent_menu = view->GetParent(); |
+ while (parent_menu != NULL && parent_menu->GetClassName() != |
+ views::SubmenuView::kViewClassName) { |
+ parent_menu = parent_menu->GetParent(); |
+ } |
+ if (parent_menu) { |
+ count = 0; |
+ RecursiveGetMenuItemIndexAndCount(parent_menu, view, &index, &count); |
+ } |
+ |
+ AccessibilityMenuItemInfo info(profile, name, has_submenu, index, count); |
+ SendAccessibilityNotification(type, &info); |
+} |
+ |
+void AccessibilityEventRouterViews::RecursiveGetMenuItemIndexAndCount( |
+ views::View* menu, views::View* item, int* index, int* count) { |
+ for (int i = 0; i < menu->GetChildViewCount(); ++i) { |
+ views::View* child = menu->GetChildViewAt(i); |
+ int previous_count = *count; |
+ RecursiveGetMenuItemIndexAndCount(child, item, index, count); |
+ if (child->GetClassName() == views::MenuItemView::kViewClassName && |
+ *count == previous_count) { |
+ if (item == child) |
+ *index = *count; |
+ (*count)++; |
+ } else if (child->GetClassName() == views::TextButton::kViewClassName) { |
+ if (item == child) |
+ *index = *count; |
+ (*count)++; |
+ } |
+ } |
+} |
+ |
+bool AccessibilityEventRouterViews::IsMenuEvent( |
+ View* view, NotificationType type) { |
+ if (type == NotificationType::ACCESSIBILITY_MENU_OPENED || |
+ type == NotificationType::ACCESSIBILITY_MENU_CLOSED) |
+ return true; |
+ |
+ while (view) { |
+ AccessibilityTypes::Role role; |
+ view->GetAccessibleRole(&role); |
+ if (role == AccessibilityTypes::ROLE_MENUITEM || |
+ role == AccessibilityTypes::ROLE_MENUPOPUP) { |
+ return true; |
+ } |
+ view = view->GetParent(); |
+ } |
+ |
+ return false; |
+} |