summaryrefslogtreecommitdiffstats
path: root/chrome/browser/browser_accessibility_manager.cc
diff options
context:
space:
mode:
authorzork@chromium.org <zork@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-07 00:39:41 +0000
committerzork@chromium.org <zork@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-07 00:39:41 +0000
commit2ee0e7564803f87b195d63c497a1101a2b29ab4f (patch)
tree0795001761a54463b710c58799cc41655dd842c0 /chrome/browser/browser_accessibility_manager.cc
parent3a51cfdd1775075f13dab50f6d8a9cb04bd6beb9 (diff)
downloadchromium_src-2ee0e7564803f87b195d63c497a1101a2b29ab4f.zip
chromium_src-2ee0e7564803f87b195d63c497a1101a2b29ab4f.tar.gz
chromium_src-2ee0e7564803f87b195d63c497a1101a2b29ab4f.tar.bz2
Revert 46567 - Reimplement accessibility of web content by caching the entire
accessibility tree in the browser process. Adds new RPCs for a browser tab to request accessibility info from a renderer; the renderer responds with a complete tree of accessibility metadata for the entire DOM, which is then cached in the RenderWidgetHostView. This part is crossplatform and will help with accessibility on both Windows and Mac OS X. For Windows, MSAA support for web content has been rewritten to use this new cache. Tested in JAWS and NVDA screen readers. Using Chrome with a screen reader is now fast and stable, unlike the previous implementation. However, note that most advanced functionality is still not supported, and much work remains to make Chrome work well with a screen reader. This is a necessary step to improve stability first. BUG=25564 BUG=13291 TEST=See http://codereview.chromium.org/1806001 Review URL: http://codereview.chromium.org/1637018 TBR=dmazzoni@chromium.org Review URL: http://codereview.chromium.org/2031004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@46642 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/browser_accessibility_manager.cc')
-rw-r--r--chrome/browser/browser_accessibility_manager.cc231
1 files changed, 131 insertions, 100 deletions
diff --git a/chrome/browser/browser_accessibility_manager.cc b/chrome/browser/browser_accessibility_manager.cc
index 8e37719..cd53e72 100644
--- a/chrome/browser/browser_accessibility_manager.cc
+++ b/chrome/browser/browser_accessibility_manager.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2008 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.
@@ -8,130 +8,161 @@
#include "chrome/browser/browser_accessibility.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"
using webkit_glue::WebAccessibility;
-// Factory method to create an instance of BrowserAccessibility
-BrowserAccessibility* BrowserAccessibilityFactory::Create() {
- CComObject<BrowserAccessibility>* instance;
- HRESULT hr = CComObject<BrowserAccessibility>::CreateInstance(&instance);
- DCHECK(SUCCEEDED(hr));
- return instance->NewReference();
-}
+// The time in ms after which we give up and return an error when processing an
+// accessibility message and no response has been received from the renderer.
+static const int kAccessibilityMessageTimeOut = 10000;
// static
-// Start child IDs at -1 and decrement each time, because clients use
-// child IDs of 1, 2, 3, ... to access the children of an object by
-// index, so we use negative IDs to clearly distinguish between indices
-// and unique IDs.
-LONG BrowserAccessibilityManager::next_child_id_ = -1;
-
-BrowserAccessibilityManager::BrowserAccessibilityManager(
- HWND parent_hwnd,
- const webkit_glue::WebAccessibility& src,
- BrowserAccessibilityFactory* factory)
- : parent_hwnd_(parent_hwnd),
- factory_(factory) {
- HRESULT hr = ::CreateStdAccessibleObject(
- parent_hwnd_, OBJID_WINDOW, IID_IAccessible,
- reinterpret_cast<void **>(&window_iaccessible_));
- DCHECK(SUCCEEDED(hr));
- root_ = CreateAccessibilityTree(NULL, src, 0);
- if (!focus_)
- focus_ = root_;
+BrowserAccessibilityManager* BrowserAccessibilityManager::GetInstance() {
+ return Singleton<BrowserAccessibilityManager>::get();
}
-BrowserAccessibilityManager::~BrowserAccessibilityManager() {
- // Clients could still hold references to some nodes of the tree, so
- // calling Inactivate will make sure that as many nodes as possible are
- // released now, and remaining nodes are marked as inactive so that
- // calls to any methods on them will return E_FAIL;
- root_->InactivateTree();
- root_->Release();
+BrowserAccessibilityManager::BrowserAccessibilityManager() {
+ registrar_.Add(this, NotificationType::RENDERER_PROCESS_TERMINATED,
+ NotificationService::AllSources());
}
-BrowserAccessibility* BrowserAccessibilityManager::GetRoot() {
- return root_;
+BrowserAccessibilityManager::~BrowserAccessibilityManager() {
+ // Clear hashmap.
+ render_process_host_map_.clear();
}
-BrowserAccessibility* BrowserAccessibilityManager::GetFromChildID(
- LONG child_id) {
- base::hash_map<LONG, BrowserAccessibility*>::iterator iter =
- child_id_map_.find(child_id);
- if (iter != child_id_map_.end()) {
- return iter->second;
- } else {
- return NULL;
+STDMETHODIMP BrowserAccessibilityManager::CreateAccessibilityInstance(
+ REFIID iid, int acc_obj_id, int routing_id, int process_id,
+ HWND parent_hwnd, void** interface_ptr) {
+ if (IID_IUnknown == iid || IID_IDispatch == iid || IID_IAccessible == iid) {
+ CComObject<BrowserAccessibility>* instance = NULL;
+
+ HRESULT hr = CComObject<BrowserAccessibility>::CreateInstance(&instance);
+ DCHECK(SUCCEEDED(hr));
+
+ if (!instance)
+ return E_FAIL;
+
+ ScopedComPtr<IAccessible> accessibility_instance(instance);
+
+ // Set class member variables.
+ instance->Initialize(acc_obj_id, routing_id, process_id, parent_hwnd);
+
+ // Retrieve the RenderViewHost connected to this request.
+ RenderViewHost* rvh = RenderViewHost::FromID(process_id, routing_id);
+
+ // Update cache with RenderProcessHost/BrowserAccessibility pair.
+ if (rvh && rvh->process()) {
+ render_process_host_map_.insert(MapEntry(rvh->process()->id(), instance));
+ } else {
+ // No RenderProcess active for this instance.
+ return E_FAIL;
+ }
+
+ // All is well, assign the temp instance to the output pointer.
+ *interface_ptr = accessibility_instance.Detach();
+ return S_OK;
}
+ // No supported interface found, return error.
+ *interface_ptr = NULL;
+ return E_NOINTERFACE;
}
-IAccessible* BrowserAccessibilityManager::GetParentWindowIAccessible() {
- return window_iaccessible_;
+bool BrowserAccessibilityManager::RequestAccessibilityInfo(
+ WebAccessibility::InParams* in, int routing_id, int process_id) {
+ // Create and populate IPC message structure, for retrieval of accessibility
+ // information from the renderer.
+ WebAccessibility::InParams in_params;
+ in_params.object_id = in->object_id;
+ in_params.function_id = in->function_id;
+ in_params.child_id = in->child_id;
+ in_params.input_long1 = in->input_long1;
+ in_params.input_long2 = in->input_long2;
+
+ // Retrieve the RenderViewHost connected to this request.
+ RenderViewHost* rvh = RenderViewHost::FromID(process_id, routing_id);
+
+ // Send accessibility information retrieval message to the renderer.
+ bool success = false;
+ if (rvh && rvh->process() && rvh->process()->HasConnection()) {
+ IPC::SyncMessage* msg =
+ new ViewMsg_GetAccessibilityInfo(routing_id, in_params, &out_params_);
+ // Necessary for the send to keep the UI responsive.
+ msg->EnableMessagePumping();
+ success = rvh->process()->SendWithTimeout(msg,
+ kAccessibilityMessageTimeOut);
+ }
+ return success;
}
-HWND BrowserAccessibilityManager::GetParentHWND() {
- return parent_hwnd_;
+bool BrowserAccessibilityManager::ChangeAccessibilityFocus(int acc_obj_id,
+ int process_id,
+ int routing_id) {
+ BrowserAccessibility* browser_acc =
+ GetBrowserAccessibility(process_id, routing_id);
+ if (browser_acc) {
+ // Notify Access Technology that there was a change in keyboard focus.
+ ::NotifyWinEvent(EVENT_OBJECT_FOCUS, browser_acc->parent_hwnd(),
+ OBJID_CLIENT, static_cast<LONG>(acc_obj_id));
+ return true;
+ }
+ return false;
}
-BrowserAccessibility* BrowserAccessibilityManager::GetFocus(
- BrowserAccessibility* root) {
- if (focus_ && (!root || focus_->IsDescendantOf(root)))
- return focus_;
-
- return NULL;
+bool BrowserAccessibilityManager::OnAccessibilityObjectStateChange(
+ int acc_obj_id, int process_id, int routing_id) {
+ BrowserAccessibility* browser_acc =
+ GetBrowserAccessibility(process_id, routing_id);
+ if (browser_acc) {
+ // Notify Access Technology that there was a change in state.
+ ::NotifyWinEvent(EVENT_OBJECT_STATECHANGE, browser_acc->parent_hwnd(),
+ OBJID_CLIENT, static_cast<LONG>(acc_obj_id));
+ return true;
+ }
+ return false;
}
-void BrowserAccessibilityManager::OnAccessibilityFocusChange(int renderer_id) {
- base::hash_map<int, LONG>::iterator iter =
- renderer_id_to_child_id_map_.find(renderer_id);
- if (iter == renderer_id_to_child_id_map_.end())
- return;
-
- LONG child_id = iter->second;
- base::hash_map<LONG, BrowserAccessibility*>::iterator uniq_iter =
- child_id_map_.find(child_id);
- if (uniq_iter != child_id_map_.end())
- focus_ = uniq_iter->second;
- ::NotifyWinEvent(EVENT_OBJECT_FOCUS, parent_hwnd_, OBJID_CLIENT, child_id);
+const WebAccessibility::OutParams& BrowserAccessibilityManager::response() {
+ return out_params_;
}
-void BrowserAccessibilityManager::OnAccessibilityObjectStateChange(
- int renderer_id) {
- base::hash_map<int, LONG>::iterator iter =
- renderer_id_to_child_id_map_.find(renderer_id);
- if (iter == renderer_id_to_child_id_map_.end())
- return;
+BrowserAccessibility* BrowserAccessibilityManager::GetBrowserAccessibility(
+ int process_id, int routing_id) {
+ // Retrieve the BrowserAccessibility connected to the requester's id. There
+ // could be multiple BrowserAccessibility connected to the given |process_id|,
+ // but they all have the same parent HWND, so using the first hit is fine.
+ RenderProcessHostMap::iterator it =
+ render_process_host_map_.lower_bound(process_id);
- LONG child_id = iter->second;
- ::NotifyWinEvent(EVENT_OBJECT_FOCUS, parent_hwnd_, OBJID_CLIENT, child_id);
-}
+ RenderProcessHostMap::iterator end_of_matching_objects =
+ render_process_host_map_.upper_bound(process_id);
-BrowserAccessibility* BrowserAccessibilityManager::CreateAccessibilityTree(
- BrowserAccessibility* parent,
- const webkit_glue::WebAccessibility& src,
- int index_in_parent) {
- BrowserAccessibility* instance = factory_->Create();
-
- // Get the next child ID, and wrap around when we get near the end
- // of a 32-bit integer range. It's okay to wrap around; we just want
- // to avoid it as long as possible because clients may cache the ID of
- // an object for a while to determine if they've seen it before.
- LONG child_id = next_child_id_;
- next_child_id_--;
- if (next_child_id_ == -2000000000)
- next_child_id_ = -1;
-
- instance->Initialize(this, parent, child_id, index_in_parent, src);
- child_id_map_[child_id] = instance;
- renderer_id_to_child_id_map_[src.id] = child_id;
- if ((src.state >> WebAccessibility::STATE_FOCUSED) & 1)
- focus_ = instance;
- for (int i = 0; i < static_cast<int>(src.children.size()); ++i) {
- BrowserAccessibility* child = CreateAccessibilityTree(
- instance, src.children[i], i);
- instance->AddChild(child);
+ for (; it != end_of_matching_objects; ++it) {
+ if (it->second && it->second->routing_id() == routing_id)
+ return it->second;
}
+ return NULL;
+}
- return instance;
+void BrowserAccessibilityManager::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(type == NotificationType::RENDERER_PROCESS_TERMINATED);
+ RenderProcessHost* rph = Source<RenderProcessHost>(source).ptr();
+ DCHECK(rph);
+
+ RenderProcessHostMap::iterator it =
+ render_process_host_map_.lower_bound(rph->id());
+
+ RenderProcessHostMap::iterator end_of_matching_objects =
+ render_process_host_map_.upper_bound(rph->id());
+
+ for (; it != end_of_matching_objects; ++it) {
+ if (it->second) {
+ // Set all matching BrowserAccessibility instances to inactive state.
+ // TODO(klink): Do more active memory cleanup as well.
+ it->second->set_instance_active(false);
+ }
+ }
}