diff options
author | ctguil@chromium.org <ctguil@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-07 05:20:23 +0000 |
---|---|---|
committer | ctguil@chromium.org <ctguil@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-07 05:20:23 +0000 |
commit | f27e81c63be89c62d84105a9329c0744c27e1641 (patch) | |
tree | 011fa1f7421d32e5629a7628766ac7e0009e8dc4 /chrome/browser/accessibility/browser_accessibility_manager.cc | |
parent | 68e677bf27869d144da2131cf5d60df785d5b920 (diff) | |
download | chromium_src-f27e81c63be89c62d84105a9329c0744c27e1641.zip chromium_src-f27e81c63be89c62d84105a9329c0744c27e1641.tar.gz chromium_src-f27e81c63be89c62d84105a9329c0744c27e1641.tar.bz2 |
Make BrowserAccessibilityManager cross platform. Step 2.
1. Move common logic and fields from BrowserAccessibilityMangerWin to BrowserAccessibilityManager.
2. Move common logic and fields from BrowserAccessibilityWin to BrowserAccessibility.
BUG=55264
TEST=interactive_ui_tests:AccessibilityWinBrowserTest.*
TEST=unit_tests:BrowserAccessibilityTest.*
Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=61740
Review URL: http://codereview.chromium.org/3551015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@61765 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/accessibility/browser_accessibility_manager.cc')
-rw-r--r-- | chrome/browser/accessibility/browser_accessibility_manager.cc | 262 |
1 files changed, 257 insertions, 5 deletions
diff --git a/chrome/browser/accessibility/browser_accessibility_manager.cc b/chrome/browser/accessibility/browser_accessibility_manager.cc index 256c62c..c663666 100644 --- a/chrome/browser/accessibility/browser_accessibility_manager.cc +++ b/chrome/browser/accessibility/browser_accessibility_manager.cc @@ -4,17 +4,70 @@ #include "chrome/browser/accessibility/browser_accessibility_manager.h" -#include "chrome/common/render_messages_params.h" +#include "chrome/browser/accessibility/browser_accessibility.h" using webkit_glue::WebAccessibility; +// 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. +// static +int32 BrowserAccessibilityManager::next_child_id_ = -1; BrowserAccessibilityManager::BrowserAccessibilityManager( - gfx::NativeWindow parent_window) - : parent_window_(parent_window) { + gfx::NativeView parent_view, + const WebAccessibility& src, + BrowserAccessibilityDelegate* delegate, + BrowserAccessibilityFactory* factory) + : parent_view_(parent_view), + delegate_(delegate), + factory_(factory), + focus_(NULL) { + root_ = CreateAccessibilityTree(NULL, GetNextChildID(), src, 0); + if (!focus_) + focus_ = root_; +} + +// static +int32 BrowserAccessibilityManager::GetNextChildID() { + // 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. + next_child_id_--; + if (next_child_id_ == -2000000000) + next_child_id_ = -1; + + return next_child_id_; } 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_->ReleaseTree(); + root_->ReleaseReference(); +} + +BrowserAccessibility* BrowserAccessibilityManager::GetRoot() { + return root_; +} + +BrowserAccessibility* BrowserAccessibilityManager::GetFromChildID( + int32 child_id) { + base::hash_map<int32, BrowserAccessibility*>::iterator iter = + child_id_map_.find(child_id); + if (iter != child_id_map_.end()) { + return iter->second; + } else { + return NULL; + } +} + +void BrowserAccessibilityManager::Remove(int32 child_id) { + child_id_map_.erase(child_id); } void BrowserAccessibilityManager::OnAccessibilityNotifications( @@ -54,6 +107,205 @@ void BrowserAccessibilityManager::OnAccessibilityNotifications( } } -gfx::NativeWindow BrowserAccessibilityManager::GetParentWindow() { - return parent_window_; +void BrowserAccessibilityManager::OnAccessibilityObjectStateChange( + const WebAccessibility& acc_obj) { + BrowserAccessibility* new_browser_acc = UpdateTree(acc_obj); + if (!new_browser_acc) + return; + + NotifyAccessibilityEvent( + ViewHostMsg_AccessibilityNotification_Params:: + NOTIFICATION_TYPE_CHECK_STATE_CHANGED, + new_browser_acc); +} + +void BrowserAccessibilityManager::OnAccessibilityObjectChildrenChange( + const WebAccessibility& acc_obj) { + BrowserAccessibility* new_browser_acc = UpdateTree(acc_obj); + if (!new_browser_acc) + return; + + NotifyAccessibilityEvent( + ViewHostMsg_AccessibilityNotification_Params:: + NOTIFICATION_TYPE_CHILDREN_CHANGED, + new_browser_acc); +} + +void BrowserAccessibilityManager::OnAccessibilityObjectFocusChange( + const WebAccessibility& acc_obj) { + BrowserAccessibility* new_browser_acc = UpdateTree(acc_obj); + if (!new_browser_acc) + return; + + focus_ = new_browser_acc; + if (delegate_ && delegate_->HasFocus()) + GotFocus(); +} + +void BrowserAccessibilityManager::OnAccessibilityObjectLoadComplete( + const WebAccessibility& acc_obj) { + root_->ReleaseTree(); + root_->ReleaseReference(); + focus_ = NULL; + + root_ = CreateAccessibilityTree(NULL, GetNextChildID(), acc_obj, 0); + if (!focus_) + focus_ = root_; + + NotifyAccessibilityEvent( + ViewHostMsg_AccessibilityNotification_Params:: + NOTIFICATION_TYPE_LOAD_COMPLETE, + root_); + if (delegate_ && delegate_->HasFocus()) + GotFocus(); +} + +void BrowserAccessibilityManager::OnAccessibilityObjectValueChange( + const WebAccessibility& acc_obj) { + BrowserAccessibility* new_browser_acc = UpdateTree(acc_obj); + if (!new_browser_acc) + return; + + NotifyAccessibilityEvent( + ViewHostMsg_AccessibilityNotification_Params:: + NOTIFICATION_TYPE_VALUE_CHANGED, + root_); +} + +void BrowserAccessibilityManager::OnAccessibilityObjectTextChange( + const WebAccessibility& acc_obj) { + BrowserAccessibility* new_browser_acc = UpdateTree(acc_obj); + if (!new_browser_acc) + return; + + NotifyAccessibilityEvent( + ViewHostMsg_AccessibilityNotification_Params:: + NOTIFICATION_TYPE_SELECTED_TEXT_CHANGED, + root_); +} + +void BrowserAccessibilityManager::GotFocus() { + // TODO(ctguil): Remove when tree update logic handles focus changes. + if (!focus_) + return; + + NotifyAccessibilityEvent( + ViewHostMsg_AccessibilityNotification_Params:: + NOTIFICATION_TYPE_FOCUS_CHANGED, + focus_); +} + +gfx::NativeView BrowserAccessibilityManager::GetParentView() { + return parent_view_; +} + +BrowserAccessibility* BrowserAccessibilityManager::GetFocus( + BrowserAccessibility* root) { + if (focus_ && (!root || focus_->IsDescendantOf(root))) + return focus_; + + return NULL; +} + +void BrowserAccessibilityManager::SetFocus( + const BrowserAccessibility& node) { + if (delegate_) + delegate_->SetAccessibilityFocus(node.renderer_id()); +} + +void BrowserAccessibilityManager::DoDefaultAction( + const BrowserAccessibility& node) { + if (delegate_) + delegate_->AccessibilityDoDefaultAction(node.renderer_id()); +} + +bool BrowserAccessibilityManager::CanModifyTreeInPlace( + BrowserAccessibility* current_root, + const WebAccessibility& new_root) { + if (current_root->renderer_id() != new_root.id) + return false; + if (current_root->GetChildCount() != new_root.children.size()) + return false; + for (unsigned int i = 0; i < current_root->GetChildCount(); i++) { + if (!CanModifyTreeInPlace(current_root->GetChild(i), + new_root.children[i])) { + return false; + } + } + return true; +} + +void BrowserAccessibilityManager::ModifyTreeInPlace( + BrowserAccessibility* current_root, + const WebAccessibility& new_root) { + DCHECK_EQ(current_root->renderer_id(), new_root.id); + DCHECK_EQ(current_root->GetChildCount(), new_root.children.size()); + for (unsigned int i = 0; i < current_root->GetChildCount(); i++) + ModifyTreeInPlace(current_root->GetChild(i), new_root.children[i]); + current_root->Initialize( + this, + current_root->GetParent(), + current_root->child_id(), + current_root->index_in_parent(), + new_root); +} + + +BrowserAccessibility* BrowserAccessibilityManager::UpdateTree( + const WebAccessibility& acc_obj) { + base::hash_map<int, int32>::iterator iter = + renderer_id_to_child_id_map_.find(acc_obj.id); + if (iter == renderer_id_to_child_id_map_.end()) + return NULL; + + int32 child_id = iter->second; + BrowserAccessibility* old_browser_acc = GetFromChildID(child_id); + if (!old_browser_acc) + return NULL; + + if (CanModifyTreeInPlace(old_browser_acc, acc_obj)) { + ModifyTreeInPlace(old_browser_acc, acc_obj); + return old_browser_acc; + } + + BrowserAccessibility* new_browser_acc = CreateAccessibilityTree( + old_browser_acc->GetParent(), + child_id, + acc_obj, + old_browser_acc->index_in_parent()); + + if (old_browser_acc->GetParent()) { + old_browser_acc->GetParent()->ReplaceChild( + old_browser_acc, + new_browser_acc); + } else { + DCHECK_EQ(old_browser_acc, root_); + root_ = new_browser_acc; + } + old_browser_acc->ReleaseTree(); + old_browser_acc->ReleaseReference(); + child_id_map_[child_id] = new_browser_acc; + + return new_browser_acc; +} + +BrowserAccessibility* BrowserAccessibilityManager::CreateAccessibilityTree( + BrowserAccessibility* parent, + int child_id, + const WebAccessibility& src, + int index_in_parent) { + BrowserAccessibility* instance = factory_->Create(); + + 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, GetNextChildID(), src.children[i], i); + instance->AddChild(child); + } + + return instance; } |