summaryrefslogtreecommitdiffstats
path: root/chrome/browser/views
diff options
context:
space:
mode:
authordmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-06 07:07:18 +0000
committerdmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-06 07:07:18 +0000
commit6a054ffaae82f5ac8d6b876d7c85f0d87d892e42 (patch)
tree86b4d5a0c5386f3d50742af099b5009ad1dad14d /chrome/browser/views
parent6ca800b9b2618e6ae4b92e189a9b1ae73746e49f (diff)
downloadchromium_src-6a054ffaae82f5ac8d6b876d7c85f0d87d892e42.zip
chromium_src-6a054ffaae82f5ac8d6b876d7c85f0d87d892e42.tar.gz
chromium_src-6a054ffaae82f5ac8d6b876d7c85f0d87d892e42.tar.bz2
Improvements to accessibility extension api support for "views":
1. Handles the new wrench menu. 2. Uses NotifyAccessibilityEvent to find out when focus changes, rather than installing focus change listeners that need to be cleaned up. BUG=none TEST=Updated AccessibilityEventRouterViewsTest.TestFocusNotification Review URL: http://codereview.chromium.org/3056045 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@55196 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/views')
-rw-r--r--chrome/browser/views/accessibility_event_router_views.cc146
-rw-r--r--chrome/browser/views/accessibility_event_router_views.h52
-rw-r--r--chrome/browser/views/accessibility_event_router_views_unittest.cc46
-rw-r--r--chrome/browser/views/chrome_views_delegate.cc7
-rw-r--r--chrome/browser/views/chrome_views_delegate.h2
5 files changed, 193 insertions, 60 deletions
diff --git a/chrome/browser/views/accessibility_event_router_views.cc b/chrome/browser/views/accessibility_event_router_views.cc
index 32dfaeb..670e2f0 100644
--- a/chrome/browser/views/accessibility_event_router_views.cc
+++ b/chrome/browser/views/accessibility_event_router_views.cc
@@ -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 @@ bool AccessibilityEventRouterViews::AddViewTree(View* view, Profile* profile) {
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 @@ void AccessibilityEventRouterViews::RemoveViewTree(View* view) {
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 @@ void AccessibilityEventRouterViews::RemoveView(View* view) {
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 @@ void AccessibilityEventRouterViews::DispatchAccessibilityNotification(
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) {
- SendButtonNotification(view, type, profile);
- } else if (view->GetClassName() == views::NativeButton::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::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 @@ void AccessibilityEventRouterViews::SendMenuNotification(
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;
+}
diff --git a/chrome/browser/views/accessibility_event_router_views.h b/chrome/browser/views/accessibility_event_router_views.h
index 403e011..aa2054f 100644
--- a/chrome/browser/views/accessibility_event_router_views.h
+++ b/chrome/browser/views/accessibility_event_router_views.h
@@ -9,6 +9,7 @@
#include <string>
#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
#include "base/hash_tables.h"
#include "base/singleton.h"
#include "base/task.h"
@@ -18,16 +19,10 @@
class Profile;
-// Allows us to use (View*) and (FocusManager*) in a hash_map with gcc.
+// Allows us to use (View*) in a hash_map with gcc.
#if defined(COMPILER_GCC)
namespace __gnu_cxx {
template<>
-struct hash<views::FocusManager*> {
- size_t operator()(views::FocusManager* focus_manager) const {
- return reinterpret_cast<size_t>(focus_manager);
- }
-};
-template<>
struct hash<views::View*> {
size_t operator()(views::View* view) const {
return reinterpret_cast<size_t>(view);
@@ -51,23 +46,18 @@ struct hash<views::View*> {
//
// You can use Profile::PauseAccessibilityEvents to prevent a flurry
// of accessibility events when a window is being created or initialized.
-class AccessibilityEventRouterViews
- : public views::FocusChangeListener {
+class AccessibilityEventRouterViews {
public:
// Internal information about a particular view to override the
// information we get directly from the view.
struct ViewInfo {
- ViewInfo() : ignore(false), focus_manager(NULL) {}
+ ViewInfo() : ignore(false) {}
// If nonempty, will use this name instead of the view's label.
std::string name;
// If true, will ignore this widget and not send accessibility events.
bool ignore;
-
- // The focus manager that this view is part of - saved because
- // GetFocusManager may not succeed while a view is being deleted.
- views::FocusManager* focus_manager;
};
// Get the single instance of this class.
@@ -94,11 +84,18 @@ class AccessibilityEventRouterViews
// Forget all information about this view.
void RemoveView(views::View* view);
- // Implementation of views::FocusChangeListener:
- virtual void FocusWillChange(
- views::View* focused_before, views::View* focused_now);
+ // Handle an accessibility event generated by a view.
+ void HandleAccessibilityEvent(
+ views::View* view, AccessibilityTypes::Event event_type);
private:
+ AccessibilityEventRouterViews();
+ virtual ~AccessibilityEventRouterViews();
+
+ friend struct DefaultSingletonTraits<AccessibilityEventRouterViews>;
+ FRIEND_TEST_ALL_PREFIXES(AccessibilityEventRouterViewsTest,
+ TestFocusNotification);
+
// Given a view, determine if it's part of a view tree that's mapped to
// a profile and if so, if it's marked as accessible.
void FindView(views::View* view, Profile** profile, bool* is_accessible);
@@ -119,12 +116,19 @@ class AccessibilityEventRouterViews
views::View* view, NotificationType type, Profile* profile);
void SendMenuNotification(
views::View* view, NotificationType type, Profile* profile);
+ void SendMenuItemNotification(
+ views::View* view, NotificationType type, Profile* profile);
- private:
- AccessibilityEventRouterViews();
- virtual ~AccessibilityEventRouterViews();
+ // Return true if it's an event on a menu.
+ bool IsMenuEvent(views::View* view, NotificationType type);
- friend struct DefaultSingletonTraits<AccessibilityEventRouterViews>;
+ // Recursively explore all menu items of |menu| and return in |count|
+ // the total number of items, and in |index| the 0-based index of
+ // |item|, if found. Initialize |count| to zero before calling this
+ // method. |index| will be unchanged if the item is not found, so
+ // initialize it to -1 to detect this case.
+ void RecursiveGetMenuItemIndexAndCount(
+ views::View* menu, views::View* item, int* index, int* count);
// The set of all view tree roots; only descendants of these will generate
// accessibility notifications.
@@ -133,8 +137,10 @@ class AccessibilityEventRouterViews
// Extra information about specific views.
base::hash_map<views::View*, ViewInfo> view_info_map_;
- // Count of the number of references to each focus manager.
- base::hash_map<views::FocusManager*, int> focus_manager_ref_count_;
+ // The profile associated with the most recent window event - used to
+ // figure out where to route a few events that can't be directly traced
+ // to a window with a profile (like menu events).
+ Profile* most_recent_profile_;
// Used to defer handling of some events until the next time
// through the event loop.
diff --git a/chrome/browser/views/accessibility_event_router_views_unittest.cc b/chrome/browser/views/accessibility_event_router_views_unittest.cc
index 4788a40..700499d 100644
--- a/chrome/browser/views/accessibility_event_router_views_unittest.cc
+++ b/chrome/browser/views/accessibility_event_router_views_unittest.cc
@@ -16,6 +16,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "views/controls/button/native_button.h"
#include "views/grid_layout.h"
+#include "views/views_delegate.h"
#include "views/widget/root_view.h"
#include "views/window/window.h"
@@ -27,10 +28,54 @@
#if defined(TOOLKIT_VIEWS)
+class AccessibilityViewsDelegate : public views::ViewsDelegate {
+ public:
+ AccessibilityViewsDelegate() {}
+ virtual ~AccessibilityViewsDelegate() {}
+
+ // Overridden from views::ViewsDelegate:
+ virtual Clipboard* GetClipboard() const { return NULL; }
+ virtual void SaveWindowPlacement(const std::wstring& window_name,
+ const gfx::Rect& bounds,
+ bool maximized) {
+ }
+ virtual bool GetSavedWindowBounds(const std::wstring& window_name,
+ gfx::Rect* bounds) const {
+ return false;
+ }
+ virtual bool GetSavedMaximizedState(const std::wstring& window_name,
+ bool* maximized) const {
+ return false;
+ }
+ virtual void NotifyAccessibilityEvent(
+ views::View* view, AccessibilityTypes::Event event_type) {
+ AccessibilityEventRouterViews::GetInstance()->HandleAccessibilityEvent(
+ view, event_type);
+ }
+#if defined(OS_WIN)
+ virtual HICON GetDefaultWindowIcon() const {
+ return NULL;
+ }
+#endif
+ virtual void AddRef() {}
+ virtual void ReleaseRef() {}
+
+ DISALLOW_COPY_AND_ASSIGN(AccessibilityViewsDelegate);
+};
+
class AccessibilityEventRouterViewsTest
: public testing::Test,
public NotificationObserver {
public:
+ virtual void SetUp() {
+ views::ViewsDelegate::views_delegate = new AccessibilityViewsDelegate();
+ }
+
+ virtual void TearDown() {
+ delete views::ViewsDelegate::views_delegate;
+ views::ViewsDelegate::views_delegate = NULL;
+ }
+
views::Widget* CreateWidget() {
#if defined(OS_WIN)
return new views::WidgetWin();
@@ -38,6 +83,7 @@ class AccessibilityEventRouterViewsTest
return new views::WidgetGtk(views::WidgetGtk::TYPE_WINDOW);
#endif
}
+
protected:
// Implement NotificationObserver::Observe and store information about a
// ACCESSIBILITY_CONTROL_FOCUSED event.
diff --git a/chrome/browser/views/chrome_views_delegate.cc b/chrome/browser/views/chrome_views_delegate.cc
index b0f8028..de824db 100644
--- a/chrome/browser/views/chrome_views_delegate.cc
+++ b/chrome/browser/views/chrome_views_delegate.cc
@@ -8,6 +8,7 @@
#include "base/scoped_ptr.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/pref_service.h"
+#include "chrome/browser/views/accessibility_event_router_views.h"
#include "chrome/browser/window_sizer.h"
#include "gfx/rect.h"
@@ -77,6 +78,12 @@ bool ChromeViewsDelegate::GetSavedMaximizedState(
maximized;
}
+void ChromeViewsDelegate::NotifyAccessibilityEvent(
+ views::View* view, AccessibilityTypes::Event event_type) {
+ AccessibilityEventRouterViews::GetInstance()->HandleAccessibilityEvent(
+ view, event_type);
+}
+
#if defined(OS_WIN)
HICON ChromeViewsDelegate::GetDefaultWindowIcon() const {
return GetAppIcon();
diff --git a/chrome/browser/views/chrome_views_delegate.h b/chrome/browser/views/chrome_views_delegate.h
index 285d6b5..2d14c9c 100644
--- a/chrome/browser/views/chrome_views_delegate.h
+++ b/chrome/browser/views/chrome_views_delegate.h
@@ -24,7 +24,7 @@ class ChromeViewsDelegate : public views::ViewsDelegate {
virtual bool GetSavedMaximizedState(const std::wstring& window_name,
bool* maximized) const;
virtual void NotifyAccessibilityEvent(
- views::View* view, AccessibilityTypes::Event event_type) {}
+ views::View* view, AccessibilityTypes::Event event_type);
#if defined(OS_WIN)
virtual HICON GetDefaultWindowIcon() const;
#endif