summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-19 14:33:09 +0000
committerdmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-19 14:33:09 +0000
commit521d76f78a831a4465e25649f39b1315726b28df (patch)
treeb6e19a2f7683d32537781512247cd3066853c46e
parent0b55e380036cc1fb3391efeca7dda9bdab49a119 (diff)
downloadchromium_src-521d76f78a831a4465e25649f39b1315726b28df.zip
chromium_src-521d76f78a831a4465e25649f39b1315726b28df.tar.gz
chromium_src-521d76f78a831a4465e25649f39b1315726b28df.tar.bz2
Add infrastructure for supporting Views to the accessibility extension api.
Only a few controls actually generate accessibility events to make sure it works, this is mostly to get the infrastructure in place. Note that the new files are analogous to: chrome/browser/gtk/accessibility_event_router_gtk.cc chrome/browser/gtk/accessibility_event_router_gtk.h chrome/browser/gtk/accessibile_widget_helper_gtk.cc chrome/browser/gtk/accessibile_widget_helper_gtk.h Any design changes should be made to both sets of classes. BUG=none TEST=Added new unit test. Review URL: http://codereview.chromium.org/1518029 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@44907 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/views/about_chrome_view.cc5
-rw-r--r--chrome/browser/views/about_chrome_view.h3
-rw-r--r--chrome/browser/views/accessibility_event_router_views.cc178
-rw-r--r--chrome/browser/views/accessibility_event_router_views.h143
-rw-r--r--chrome/browser/views/accessibility_event_router_views_unittest.cc126
-rw-r--r--chrome/browser/views/accessible_view_helper.cc73
-rw-r--r--chrome/browser/views/accessible_view_helper.h69
-rw-r--r--chrome/browser/views/frame/browser_view.cc4
-rw-r--r--chrome/browser/views/frame/browser_view.h2
-rw-r--r--chrome/chrome_browser.gypi12
-rw-r--r--chrome/chrome_tests.gypi2
11 files changed, 615 insertions, 2 deletions
diff --git a/chrome/browser/views/about_chrome_view.cc b/chrome/browser/views/about_chrome_view.cc
index 4885b07..96e284d 100644
--- a/chrome/browser/views/about_chrome_view.cc
+++ b/chrome/browser/views/about_chrome_view.cc
@@ -13,6 +13,7 @@
#include "chrome/app/chrome_version_info.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/views/accessible_view_helper.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/platform_util.h"
#include "chrome/common/url_constants.h"
@@ -408,6 +409,10 @@ void AboutChromeView::Layout() {
throbber_topleft_y + 1,
parent_bounds.width() - update_label_x,
sz.height());
+
+ if (!accessible_view_helper_.get())
+ accessible_view_helper_.reset(
+ new AccessibleViewHelper(GetParent(), profile_));
}
diff --git a/chrome/browser/views/about_chrome_view.h b/chrome/browser/views/about_chrome_view.h
index 5bee7a9..56decd3 100644
--- a/chrome/browser/views/about_chrome_view.h
+++ b/chrome/browser/views/about_chrome_view.h
@@ -24,6 +24,7 @@ class Throbber;
class Window;
}
+class AccessibleViewHelper;
class Profile;
////////////////////////////////////////////////////////////////////////////////
@@ -169,6 +170,8 @@ class AboutChromeView : public views::View,
CancelableRequestConsumer consumer_;
#endif
+ scoped_ptr<AccessibleViewHelper> accessible_view_helper_;
+
DISALLOW_COPY_AND_ASSIGN(AboutChromeView);
};
diff --git a/chrome/browser/views/accessibility_event_router_views.cc b/chrome/browser/views/accessibility_event_router_views.cc
new file mode 100644
index 0000000..32dfaeb
--- /dev/null
+++ b/chrome/browser/views/accessibility_event_router_views.cc
@@ -0,0 +1,178 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/views/accessibility_event_router_views.h"
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/message_loop.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/extensions/extension_accessibility_api.h"
+#include "chrome/browser/profile.h"
+#include "chrome/common/notification_type.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"
+
+using views::FocusManager;
+using views::View;
+
+AccessibilityEventRouterViews::AccessibilityEventRouterViews()
+ : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
+}
+
+AccessibilityEventRouterViews::~AccessibilityEventRouterViews() {
+}
+
+// static
+AccessibilityEventRouterViews* AccessibilityEventRouterViews::GetInstance() {
+ return Singleton<AccessibilityEventRouterViews>::get();
+}
+
+bool AccessibilityEventRouterViews::AddViewTree(View* view, Profile* profile) {
+ if (view_tree_profile_map_[view] != NULL)
+ 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;
+}
+
+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) {
+ view_info_map_[view].ignore = true;
+}
+
+void AccessibilityEventRouterViews::SetViewName(View* view, std::string name) {
+ view_info_map_[view].name = name;
+}
+
+void AccessibilityEventRouterViews::RemoveView(View* view) {
+ DCHECK(view_info_map_.find(view) != view_info_map_.end());
+ 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);
+ }
+}
+
+//
+// Private methods
+//
+
+void AccessibilityEventRouterViews::FindView(
+ View* view, Profile** profile, bool* is_accessible) {
+ *is_accessible = false;
+
+ // First see if it's a descendant of an accessible view.
+ for (base::hash_map<View*, Profile*>::const_iterator iter =
+ view_tree_profile_map_.begin();
+ iter != view_tree_profile_map_.end();
+ ++iter) {
+ if (iter->first->IsParentOf(view)) {
+ *is_accessible = true;
+ if (profile)
+ *profile = iter->second;
+ break;
+ }
+ }
+ if (!*is_accessible)
+ return;
+
+ // Now make sure it's not marked as a widget to be ignored.
+ base::hash_map<View*, ViewInfo>::const_iterator iter =
+ view_info_map_.find(view);
+ if (iter != view_info_map_.end() && iter->second.ignore)
+ *is_accessible = false;
+}
+
+std::string AccessibilityEventRouterViews::GetViewName(View* view) {
+ std::string name;
+
+ // First see if we have a name registered for this view.
+ base::hash_map<View*, ViewInfo>::const_iterator iter =
+ view_info_map_.find(view);
+ if (iter != view_info_map_.end())
+ name = iter->second.name;
+
+ // Otherwise ask the view for its accessible name.
+ if (name.empty()) {
+ std::wstring wname;
+ view->GetAccessibleName(&wname);
+ name = WideToUTF8(wname);
+ }
+
+ return name;
+}
+
+void AccessibilityEventRouterViews::DispatchAccessibilityNotification(
+ View* view, NotificationType type) {
+ Profile* profile = NULL;
+ bool is_accessible;
+ FindView(view, &profile, &is_accessible);
+ if (!is_accessible)
+ return;
+
+ if (view->GetClassName() == views::ImageButton::kViewClassName) {
+ SendButtonNotification(view, type, profile);
+ } else if (view->GetClassName() == views::NativeButton::kViewClassName) {
+ SendButtonNotification(view, type, profile);
+ } else if (view->GetClassName() == views::Link::kViewClassName) {
+ SendLinkNotification(view, type, profile);
+ } else if (view->GetClassName() == views::MenuButton::kViewClassName) {
+ SendMenuNotification(view, type, profile);
+ }
+}
+
+void AccessibilityEventRouterViews::SendButtonNotification(
+ View* view, NotificationType type, Profile* profile) {
+ AccessibilityButtonInfo info(profile, GetViewName(view));
+ SendAccessibilityNotification(type, &info);
+}
+
+void AccessibilityEventRouterViews::SendLinkNotification(
+ View* view, NotificationType type, Profile* profile) {
+ AccessibilityLinkInfo info(profile, GetViewName(view));
+ SendAccessibilityNotification(type, &info);
+}
+
+void AccessibilityEventRouterViews::SendMenuNotification(
+ View* view, NotificationType type, Profile* profile) {
+ AccessibilityMenuInfo info(profile, GetViewName(view));
+ SendAccessibilityNotification(type, &info);
+}
diff --git a/chrome/browser/views/accessibility_event_router_views.h b/chrome/browser/views/accessibility_event_router_views.h
new file mode 100644
index 0000000..024faf1
--- /dev/null
+++ b/chrome/browser/views/accessibility_event_router_views.h
@@ -0,0 +1,143 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_VIEWS_ACCESSIBILITY_EVENT_ROUTER_VIEWS_H_
+#define CHROME_BROWSER_VIEWS_ACCESSIBILITY_EVENT_ROUTER_VIEWS_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/hash_tables.h"
+#include "base/singleton.h"
+#include "base/task.h"
+#include "chrome/browser/accessibility_events.h"
+#include "views/view.h"
+#include "views/widget/root_view.h"
+
+class Profile;
+
+// Allows us to use (View*) and (FocusManager*) 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);
+ }
+};
+} // namespace __gnu_cxx
+#endif // defined(COMPILER_GCC)
+
+// NOTE: This class is part of the Accessibility Extension API, which lets
+// extensions receive accessibility events. It's distinct from code that
+// implements platform accessibility APIs like MSAA or ATK.
+//
+// Singleton class that adds listeners to many views, then sends an
+// accessibility notification whenever a relevant event occurs in an
+// accessible view.
+//
+// Views are not accessible by default. When you register a root widget,
+// that widget and all of its descendants will start sending accessibility
+// event notifications. You can then override the default behavior for
+// specific descendants using other methods.
+//
+// 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 {
+ 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) {}
+
+ // 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.
+ static AccessibilityEventRouterViews* GetInstance();
+
+ // Start sending accessibility events for this view and all of its
+ // descendants. Notifications will go to the specified profile.
+ // Returns true on success, false if "view" was already registered.
+ // It is the responsibility of the caller to call RemoveViewTree if
+ // this view is ever deleted; consider using AccessibleViewHelper.
+ bool AddViewTree(views::View* view, Profile* profile);
+
+ // Stop sending accessibility events for this view and all of its
+ // descendants.
+ void RemoveViewTree(views::View* view);
+
+ // Don't send any events for this view.
+ void IgnoreView(views::View* view);
+
+ // Use the following string as the name of this view, instead of the
+ // gtk label associated with the view.
+ void SetViewName(views::View* view, std::string name);
+
+ // 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);
+
+ private:
+ // 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);
+
+ // Checks the type of the view and calls one of the more specific
+ // Send*Notification methods, below.
+ void DispatchAccessibilityNotification(
+ views::View* view, NotificationType type);
+
+ // Return the name of a view.
+ std::string GetViewName(views::View* view);
+
+ // Each of these methods constructs an AccessibilityControlInfo object
+ // and sends a notification of a specific accessibility event.
+ void SendButtonNotification(
+ views::View* view, NotificationType type, Profile* profile);
+ void SendLinkNotification(
+ views::View* view, NotificationType type, Profile* profile);
+ void SendMenuNotification(
+ views::View* view, NotificationType type, Profile* profile);
+
+ private:
+ AccessibilityEventRouterViews();
+ virtual ~AccessibilityEventRouterViews();
+
+ friend struct DefaultSingletonTraits<AccessibilityEventRouterViews>;
+
+ // The set of all view tree roots; only descendants of these will generate
+ // accessibility notifications.
+ base::hash_map<views::View*, Profile*> view_tree_profile_map_;
+
+ // 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_;
+
+ // Used to defer handling of some events until the next time
+ // through the event loop.
+ ScopedRunnableMethodFactory<AccessibilityEventRouterViews> method_factory_;
+};
+
+#endif // CHROME_BROWSER_VIEWS_ACCESSIBILITY_EVENT_ROUTER_VIEWS_H_
diff --git a/chrome/browser/views/accessibility_event_router_views_unittest.cc b/chrome/browser/views/accessibility_event_router_views_unittest.cc
new file mode 100644
index 0000000..11b5303c
--- /dev/null
+++ b/chrome/browser/views/accessibility_event_router_views_unittest.cc
@@ -0,0 +1,126 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/message_loop.h"
+#include "chrome/browser/extensions/extension_accessibility_api.h"
+#include "chrome/browser/views/accessibility_event_router_views.h"
+#include "chrome/browser/views/accessible_view_helper.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "views/controls/button/native_button.h"
+#include "views/grid_layout.h"
+#include "views/widget/root_view.h"
+#include "views/window/window.h"
+
+#if defined(OS_WIN)
+#include "views/widget/widget_win.h"
+#elif defined(OS_LINUX)
+#include "views/widget/widget_gtk.h"
+#endif
+
+#if defined(TOOLKIT_VIEWS)
+
+class AccessibilityEventRouterViewsTest
+ : public testing::Test,
+ public NotificationObserver {
+ public:
+ views::Widget* CreateWidget() {
+#if defined(OS_WIN)
+ return new views::WidgetWin();
+#elif defined(OS_LINUX)
+ return new views::WidgetGtk(views::WidgetGtk::TYPE_WINDOW);
+#endif
+ }
+ protected:
+ // Implement NotificationObserver::Observe and store information about a
+ // ACCESSIBILITY_CONTROL_FOCUSED event.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ ASSERT_EQ(type.value, NotificationType::ACCESSIBILITY_CONTROL_FOCUSED);
+ const AccessibilityControlInfo* info =
+ Details<const AccessibilityControlInfo>(details).ptr();
+ focus_event_count_++;
+ last_control_name_ = info->name();
+ }
+
+ MessageLoopForUI message_loop_;
+ int focus_event_count_;
+ std::string last_control_name_;
+};
+
+TEST_F(AccessibilityEventRouterViewsTest, TestFocusNotification) {
+ const char kButton1ASCII[] = "Button1";
+ const char kButton2ASCII[] = "Button2";
+ const char kButton3ASCII[] = "Button3";
+
+ // Create a window and layout.
+ views::Widget* window = CreateWidget();
+ window->Init(NULL, gfx::Rect(0, 0, 100, 100));
+ views::RootView* root_view = window->GetRootView();
+ views::GridLayout* layout = new views::GridLayout(root_view);
+ root_view->SetLayoutManager(layout);
+ views::ColumnSet* column_set = layout->AddColumnSet(0);
+ column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
+ views::GridLayout::USE_PREF, 0, 0);
+
+ // Add 3 buttons.
+ views::NativeButton* button1 = new views::NativeButton(
+ NULL, ASCIIToWide(kButton1ASCII));
+ layout->StartRow(0, 0);
+ layout->AddView(button1);
+ views::NativeButton* button2 = new views::NativeButton(
+ NULL, ASCIIToWide(kButton2ASCII));
+ layout->StartRow(0, 0);
+ layout->AddView(button2);
+ views::NativeButton* button3 = new views::NativeButton(
+ NULL, ASCIIToWide(kButton3ASCII));
+ layout->StartRow(0, 0);
+ layout->AddView(button3);
+
+ // Set focus to the first button initially.
+ button1->RequestFocus();
+
+ // Start listening to ACCESSIBILITY_CONTROL_FOCUSED notifications.
+ NotificationRegistrar registrar;
+ registrar.Add(this,
+ NotificationType::ACCESSIBILITY_CONTROL_FOCUSED,
+ NotificationService::AllSources());
+
+ // Switch on accessibility event notifications.
+ TestingProfile profile;
+ ExtensionAccessibilityEventRouter* accessibility_event_router =
+ ExtensionAccessibilityEventRouter::GetInstance();
+ accessibility_event_router->SetAccessibilityEnabled(true);
+
+ // Create an AccessibleViewHelper for this window, which will send
+ // accessibility notifications for all events that happen in child views.
+ // Tell it to ignore button 3.
+ AccessibleViewHelper accessible_view_helper(root_view, &profile);
+ accessible_view_helper.IgnoreView(button3);
+
+ // Advance focus to the next button and test that we got the
+ // expected notification with the name of button 2.
+ views::FocusManager* focus_manager = window->GetFocusManager();
+ focus_event_count_ = 0;
+ focus_manager->AdvanceFocus(false);
+ EXPECT_EQ(1, focus_event_count_);
+ EXPECT_EQ(kButton2ASCII, last_control_name_);
+
+ // Advance to button 3. We expect no notification because we told it
+ // to ignore this view.
+ focus_manager->AdvanceFocus(false);
+ EXPECT_EQ(1, focus_event_count_);
+
+ // Advance to button 1 and check the notification.
+ focus_manager->AdvanceFocus(false);
+ EXPECT_EQ(2, focus_event_count_);
+ EXPECT_EQ(kButton1ASCII, last_control_name_);
+}
+
+#endif // defined(TOOLKIT_VIEWS)
diff --git a/chrome/browser/views/accessible_view_helper.cc b/chrome/browser/views/accessible_view_helper.cc
new file mode 100644
index 0000000..8a42515
--- /dev/null
+++ b/chrome/browser/views/accessible_view_helper.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/views/accessible_view_helper.h"
+
+#include "app/l10n_util.h"
+#include "chrome/browser/accessibility_events.h"
+#include "chrome/browser/profile.h"
+#include "chrome/common/notification_service.h"
+
+using views::View;
+
+AccessibleViewHelper::AccessibleViewHelper(
+ View* view_tree, Profile* profile)
+ : accessibility_event_router_(AccessibilityEventRouterViews::GetInstance()),
+ profile_(profile),
+ view_tree_(view_tree) {
+ if (!accessibility_event_router_->AddViewTree(view_tree_, profile))
+ view_tree_ = NULL;
+}
+
+AccessibleViewHelper::~AccessibleViewHelper() {
+ if (!window_title_.empty()) {
+ AccessibilityWindowInfo info(profile_, window_title_);
+ NotificationService::current()->Notify(
+ NotificationType::ACCESSIBILITY_WINDOW_CLOSED,
+ Source<Profile>(profile_),
+ Details<AccessibilityWindowInfo>(&info));
+ }
+
+ if (view_tree_) {
+ accessibility_event_router_->RemoveViewTree(view_tree_);
+ for (std::vector<views::View*>::iterator iter = managed_views_.begin();
+ iter != managed_views_.end(); ++iter)
+ accessibility_event_router_->RemoveView(*iter);
+ }
+}
+
+void AccessibleViewHelper::SendOpenWindowNotification(
+ const std::string& window_title) {
+ window_title_ = window_title;
+ AccessibilityWindowInfo info(profile_, window_title);
+ NotificationService::current()->Notify(
+ NotificationType::ACCESSIBILITY_WINDOW_OPENED,
+ Source<Profile>(profile_),
+ Details<AccessibilityWindowInfo>(&info));
+}
+
+void AccessibleViewHelper::IgnoreView(View* view) {
+ if (!view_tree_)
+ return;
+
+ accessibility_event_router_->IgnoreView(view);
+ managed_views_.push_back(view);
+}
+
+void AccessibleViewHelper::SetViewName(View* view, std::string name) {
+ if (!view_tree_)
+ return;
+
+ accessibility_event_router_->SetViewName(view, name);
+ managed_views_.push_back(view);
+}
+
+void AccessibleViewHelper::SetViewName(View* view, int string_id) {
+ if (!view_tree_)
+ return;
+
+ std::string name = l10n_util::GetStringUTF8(string_id);
+ accessibility_event_router_->SetViewName(view, name);
+ managed_views_.push_back(view);
+}
diff --git a/chrome/browser/views/accessible_view_helper.h b/chrome/browser/views/accessible_view_helper.h
new file mode 100644
index 0000000..c5c1e15
--- /dev/null
+++ b/chrome/browser/views/accessible_view_helper.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_VIEWS_ACCESSIBLE_VIEW_HELPER_H_
+#define CHROME_BROWSER_VIEWS_ACCESSIBLE_VIEW_HELPER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/singleton.h"
+#include "chrome/browser/accessibility_events.h"
+#include "chrome/browser/views/accessibility_event_router_views.h"
+
+class Profile;
+
+// NOTE: This class is part of the Accessibility Extension API, which lets
+// extensions receive accessibility events. It's distinct from code that
+// implements platform accessibility APIs like MSAA or ATK.
+//
+// Helper class that helps to manage the accessibility information for a
+// view and all of its descendants. Create an instance of this class for
+// the root of a tree of views (like a dialog) that should send accessibility
+// events for all of its descendants.
+//
+// Most controls have default behavior for accessibility; when this needs
+// to be augmented, call one of the methods below to ignore a particular
+// view or change its details.
+//
+// All of the information managed by this class is registered with the
+// (global) AccessibilityEventRouterViews and unregistered when this object is
+// destroyed.
+class AccessibleViewHelper {
+ public:
+ // Constructs an AccessibleViewHelper that makes the given view and all
+ // of its descendants accessible for the lifetime of this object,
+ // sending accessibility notifications to the given profile.
+ AccessibleViewHelper(views::View* view_tree, Profile* profile);
+
+ virtual ~AccessibleViewHelper();
+
+ // Sends a notification that a new window was opened now, and a
+ // corresponding close window notification when this object
+ // goes out of scope.
+ void SendOpenWindowNotification(const std::string& window_title);
+
+ // Will not send accessibility events for this view.
+ void IgnoreView(views::View* view);
+
+ // Uses the following string as the name of this view, instead of
+ // view->GetAccessibleName().
+ void SetViewName(views::View* view, std::string name);
+
+ // Uses the following string id as the name of this view, instead of
+ // view->GetAccessibleName().
+ void SetViewName(views::View* view, int string_id);
+
+ private:
+ AccessibilityEventRouterViews* accessibility_event_router_;
+ Profile* profile_;
+ views::View* view_tree_;
+ std::string window_title_;
+ std::vector<views::View*> managed_views_;
+
+ DISALLOW_COPY_AND_ASSIGN(AccessibleViewHelper);
+};
+
+#endif // CHROME_BROWSER_VIEWS_ACCESSIBLE_VIEW_HELPER_H_
diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc
index dba7844..f96964a 100644
--- a/chrome/browser/views/frame/browser_view.cc
+++ b/chrome/browser/views/frame/browser_view.cc
@@ -27,6 +27,7 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/view_ids.h"
+#include "chrome/browser/views/accessible_view_helper.h"
#include "chrome/browser/views/bookmark_bar_view.h"
#include "chrome/browser/views/browser_dialogs.h"
#include "chrome/browser/views/download_shelf_view.h"
@@ -640,6 +641,9 @@ bool BrowserView::IsPositionInWindowCaption(const gfx::Point& point) {
// BrowserView, BrowserWindow implementation:
void BrowserView::Show() {
+ accessible_view_helper_.reset(new AccessibleViewHelper(
+ this, browser_->profile()));
+
#if defined(OS_LINUX)
if (!accessible_widget_helper_.get()) {
accessible_widget_helper_.reset(new AccessibleWidgetHelper(
diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h
index 8b6c120..1e5b361 100644
--- a/chrome/browser/views/frame/browser_view.h
+++ b/chrome/browser/views/frame/browser_view.h
@@ -35,6 +35,7 @@
// NOTE: For more information about the objects and files in this directory,
// view: http://dev.chromium.org/developers/design-documents/browser-window
+class AccessibleViewHelper;
class BookmarkBarView;
class Browser;
class BrowserBubble;
@@ -573,6 +574,7 @@ class BrowserView : public BrowserBubbleHost,
UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_;
+ scoped_ptr<AccessibleViewHelper> accessible_view_helper_;
#if defined(OS_LINUX)
scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_;
#endif
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 2d96990..3f84b65 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2121,8 +2121,12 @@
'browser/views/about_network_dialog.h',
'browser/views/accelerator_table_gtk.cc',
'browser/views/accelerator_table_gtk.h',
+ 'browser/views/accessibility_event_router_views.cc',
+ 'browser/views/accessibility_event_router_views.h',
'browser/views/accessible_toolbar_view.cc',
'browser/views/accessible_toolbar_view.h',
+ 'browser/views/accessible_view_helper.cc',
+ 'browser/views/accessible_view_helper.h',
'browser/views/app_launcher.cc',
'browser/views/app_launcher.h',
'browser/views/appcache_info_view.cc',
@@ -2777,13 +2781,17 @@
['include', '^browser/extensions/'],
['include', '^browser/views/about_chrome_view.cc'],
['include', '^browser/views/about_chrome_view.h'],
- ['include', '^browser/views/app_launcher.cc'],
- ['include', '^browser/views/app_launcher.h'],
['include', '^browser/views/accelerator_table_gtk.cc'],
['include', '^browser/views/accelerator_table_gtk.h'],
+ ['include', '^browser/views/accessibility_event_router_views.cc'],
+ ['include', '^browser/views/accessibility_event_router_views.h'],
['include', '^browser/views/accessible_toolbar_view.cc'],
['include', '^browser/views/accessible_toolbar_view.h'],
+ ['include', '^browser/views/accessible_view_helper.cc'],
+ ['include', '^browser/views/accessible_view_helper.h'],
['include', '^browser/views/app_launcher.cc'],
+ ['include', '^browser/views/app_launcher.cc'],
+ ['include', '^browser/views/app_launcher.h'],
['include', '^browser/views/app_launcher.h'],
['include', '^browser/views/autocomplete/autocomplete_popup_contents_view.cc'],
['include', '^browser/views/autocomplete/autocomplete_popup_contents_view.h'],
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index dc8cb1e..2c2a577 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -933,6 +933,7 @@
'browser/translate/translate_manager_unittest.cc',
'browser/theme_resources_util_unittest.cc',
'browser/user_style_sheet_watcher_unittest.cc',
+ 'browser/views/accessibility_event_router_views_unittest.cc',
'browser/views/bookmark_context_menu_test.cc',
'browser/views/bookmark_editor_view_unittest.cc',
'browser/views/extensions/browser_action_drag_data_unittest.cc',
@@ -1085,6 +1086,7 @@
'sources!': [
# Blocked on bookmark manager.
'browser/bookmarks/bookmark_context_menu_controller_unittest.cc',
+ 'browser/views/accessibility_event_router_views_unittest.cc',
'browser/views/bookmark_context_menu_test.cc',
'browser/gtk/go_button_gtk_unittest.cc',
'browser/gtk/tabs/tab_renderer_gtk_unittest.cc',