diff options
author | ctguil@chromium.org <ctguil@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-06 23:58:42 +0000 |
---|---|---|
committer | ctguil@chromium.org <ctguil@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-06 23:58:42 +0000 |
commit | 54b254841cd7c8054821f7e43f14b1847f9d0b7d (patch) | |
tree | df5a1d503167d238696ad327fb4caa90dcacbd20 /chrome/browser/accessibility | |
parent | b03a138eb0c4d308dc0ac31e252debba26da17cf (diff) | |
download | chromium_src-54b254841cd7c8054821f7e43f14b1847f9d0b7d.zip chromium_src-54b254841cd7c8054821f7e43f14b1847f9d0b7d.tar.gz chromium_src-54b254841cd7c8054821f7e43f14b1847f9d0b7d.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.*
Review URL: http://codereview.chromium.org/3551015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@61740 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/accessibility')
9 files changed, 912 insertions, 801 deletions
diff --git a/chrome/browser/accessibility/browser_accessibility.cc b/chrome/browser/accessibility/browser_accessibility.cc index fa87e09..38cf5cc 100644 --- a/chrome/browser/accessibility/browser_accessibility.cc +++ b/chrome/browser/accessibility/browser_accessibility.cc @@ -4,8 +4,102 @@ #include "chrome/browser/accessibility/browser_accessibility.h" +#include "base/logging.h" +#include "chrome/browser/accessibility/browser_accessibility_manager.h" + BrowserAccessibility::BrowserAccessibility() { } BrowserAccessibility::~BrowserAccessibility() { } + +void BrowserAccessibility::Initialize( + BrowserAccessibilityManager* manager, + BrowserAccessibility* parent, + int32 child_id, + int32 index_in_parent, + const webkit_glue::WebAccessibility& src) { + manager_ = manager; + parent_ = parent; + child_id_ = child_id; + index_in_parent_ = index_in_parent; + + renderer_id_ = src.id; + name_ = src.name; + value_ = src.value; + attributes_ = src.attributes; + html_attributes_ = src.html_attributes; + location_ = src.location; + role_ = src.role; + state_ = src.state; + + Initialize(); +} + +void BrowserAccessibility::ReleaseTree() { + // Now we can safely call InactivateTree on our children and remove + // references to them, so that as much of the tree as possible will be + // destroyed now - however, nodes that still have references to them + // might stick around a while until all clients have released them. + for (std::vector<BrowserAccessibility*>::iterator iter = + children_.begin(); + iter != children_.end(); ++iter) { + (*iter)->ReleaseTree(); + (*iter)->ReleaseReference(); + } + children_.clear(); + manager_->Remove(child_id_); +} + +void BrowserAccessibility::AddChild(BrowserAccessibility* child) { + children_.push_back(child); +} + +bool BrowserAccessibility::IsDescendantOf( + BrowserAccessibility* ancestor) { + if (this == ancestor) { + return true; + } else if (parent_) { + return parent_->IsDescendantOf(ancestor); + } + + return false; +} + +BrowserAccessibility* BrowserAccessibility::GetParent() { + return parent_; +} + +uint32 BrowserAccessibility::GetChildCount() { + return children_.size(); +} + +BrowserAccessibility* BrowserAccessibility::GetChild(uint32 child_index) { + DCHECK(child_index < children_.size()); + return children_[child_index]; +} + +BrowserAccessibility* BrowserAccessibility::GetPreviousSibling() { + if (parent_ && index_in_parent_ > 0) + return parent_->children_[index_in_parent_ - 1]; + + return NULL; +} + +BrowserAccessibility* BrowserAccessibility::GetNextSibling() { + if (parent_ && + index_in_parent_ >= 0 && + index_in_parent_ < static_cast<int>(parent_->children_.size() - 1)) { + return parent_->children_[index_in_parent_ + 1]; + } + + return NULL; +} + +void BrowserAccessibility::ReplaceChild( + const BrowserAccessibility* old_acc, BrowserAccessibility* new_acc) { + DCHECK_EQ(children_[old_acc->index_in_parent_], old_acc); + + old_acc = children_[old_acc->index_in_parent_]; + children_[old_acc->index_in_parent_] = new_acc; +} diff --git a/chrome/browser/accessibility/browser_accessibility.h b/chrome/browser/accessibility/browser_accessibility.h index a7d9719..bdf374e 100644 --- a/chrome/browser/accessibility/browser_accessibility.h +++ b/chrome/browser/accessibility/browser_accessibility.h @@ -6,7 +6,20 @@ #define CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_H_ #pragma once +#include <map> +#include <utility> +#include <vector> + #include "base/basictypes.h" +#include "build/build_config.h" +#include "webkit/glue/webaccessibility.h" + +class BrowserAccessibilityManager; +#if defined(OS_WIN) +class BrowserAccessibilityWin; +#endif + +using webkit_glue::WebAccessibility; //////////////////////////////////////////////////////////////////////////////// // @@ -22,13 +35,104 @@ //////////////////////////////////////////////////////////////////////////////// class BrowserAccessibility { public: - // Creates the platform specific BrowserAccessibility. Ownership passes to the + // Creates a platform specific BrowserAccessibility. Ownership passes to the // caller. + static BrowserAccessibility* Create(); + virtual ~BrowserAccessibility(); + // Perform platform specific initialization. This can be called multiple times + // during the lifetime of this instance after the members of this base object + // have been reset with new values from the renderer process. + virtual void Initialize() = 0; + + // Remove references to all children and delete them if possible. + virtual void ReleaseTree(); + + // Release a reference to this node. This may be a no-op on platforms other + // than windows. + virtual void ReleaseReference() = 0; + + // Initialize this object + void Initialize(BrowserAccessibilityManager* manager, + BrowserAccessibility* parent, + int32 child_id, + int32 index_in_parent, + const WebAccessibility& src); + + // Add a child of this object. + void AddChild(BrowserAccessibility* child); + + // Return true if this object is equal to or a descendant of |ancestor|. + bool IsDescendantOf(BrowserAccessibility* ancestor); + + // Returns the parent of this object, or NULL if it's the root. + BrowserAccessibility* GetParent(); + + // Returns the number of children of this object. + uint32 GetChildCount(); + + // Return a pointer to the child with the given index. + BrowserAccessibility* GetChild(uint32 child_index); + + // Return the previous sibling of this object, or NULL if it's the first + // child of its parent. + BrowserAccessibility* GetPreviousSibling(); + + // Return the next sibling of this object, or NULL if it's the last child + // of its parent. + BrowserAccessibility* GetNextSibling(); + + // Replace a child object. Used when updating the accessibility tree. + void ReplaceChild( + const BrowserAccessibility* old_acc, + BrowserAccessibility* new_acc); + + // Accessors + int32 child_id() const { return child_id_; } + const std::vector<BrowserAccessibility*>& children() const { + return children_; + } + int32 renderer_id() const { return renderer_id_; } + int32 index_in_parent() const { return index_in_parent_; } + WebKit::WebRect location() const { return location_; } + +#if defined(OS_WIN) + BrowserAccessibilityWin* toBrowserAccessibilityWin(); +#endif + protected: BrowserAccessibility(); + // The manager of this tree of accessibility objects; needed for + // global operations like focus tracking. + BrowserAccessibilityManager* manager_; + + // The parent of this object, may be NULL if we're the root object. + BrowserAccessibility* parent_; + + // The ID of this object; globally unique within the browser process. + int32 child_id_; + + // The index of this within its parent object. + int32 index_in_parent_; + + // The ID of this object in the renderer process. + int32 renderer_id_; + + // The children of this object. + std::vector<BrowserAccessibility*> children_; + + // Accessibility metadata from the renderer + string16 name_; + string16 value_; + std::map<int32, string16> attributes_; + std::vector<std::pair<string16, string16> > html_attributes_; + int32 role_; + int32 state_; + string16 role_name_; + WebKit::WebRect location_; + private: DISALLOW_COPY_AND_ASSIGN(BrowserAccessibility); }; diff --git a/chrome/browser/accessibility/browser_accessibility_manager.cc b/chrome/browser/accessibility/browser_accessibility_manager.cc index 256c62c..8506e7a 100644 --- a/chrome/browser/accessibility/browser_accessibility_manager.cc +++ b/chrome/browser/accessibility/browser_accessibility_manager.cc @@ -4,17 +4,74 @@ #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; + +BrowserAccessibility* BrowserAccessibilityFactory::Create() { + return BrowserAccessibility::Create(); +} 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 +111,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; } diff --git a/chrome/browser/accessibility/browser_accessibility_manager.h b/chrome/browser/accessibility/browser_accessibility_manager.h index 4fe5f85..ff96e56 100644 --- a/chrome/browser/accessibility/browser_accessibility_manager.h +++ b/chrome/browser/accessibility/browser_accessibility_manager.h @@ -6,18 +6,20 @@ #define CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_H_ #pragma once -#include "build/build_config.h" - -#if defined(OS_WIN) -#include <oleacc.h> -#endif - #include <vector> +#include "base/hash_tables.h" +#include "base/scoped_ptr.h" +#include "build/build_config.h" +#include "chrome/common/render_messages_params.h" #include "gfx/native_widget_types.h" #include "webkit/glue/webaccessibility.h" -struct ViewHostMsg_AccessibilityNotification_Params; + +class BrowserAccessibility; +#if defined(OS_WIN) +class BrowserAccessibilityManagerWin; +#endif using webkit_glue::WebAccessibility; @@ -30,52 +32,143 @@ class BrowserAccessibilityDelegate { virtual bool HasFocus() = 0; }; +class BrowserAccessibilityFactory { + public: + virtual ~BrowserAccessibilityFactory() {} + + // Create an instance of BrowserAccessibility and return a new + // reference to it. + virtual BrowserAccessibility* Create(); +}; + // Manages a tree of BrowserAccessibility objects. class BrowserAccessibilityManager { public: // Creates the platform specific BrowserAccessibilityManager. Ownership passes // to the caller. static BrowserAccessibilityManager* Create( - gfx::NativeWindow parent_window, - const webkit_glue::WebAccessibility& src, - BrowserAccessibilityDelegate* delegate); + gfx::NativeView parent_view, + const WebAccessibility& src, + BrowserAccessibilityDelegate* delegate, + BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory()); virtual ~BrowserAccessibilityManager(); + virtual void NotifyAccessibilityEvent( + ViewHostMsg_AccessibilityNotification_Params::NotificationType n, + BrowserAccessibility* node) = 0; + + // Returns the next unique child id. + static int32 GetNextChildID(); + + // Return a pointer to the root of the tree, does not make a new reference. + BrowserAccessibility* GetRoot(); + + // Removes the BrowserAccessibility child_id from the manager. + void Remove(int32 child_id); + + // Return a pointer to the object corresponding to the given child_id, + // does not make a new reference. + BrowserAccessibility* GetFromChildID(int32 child_id); + // Called to notify the accessibility manager that its associated native - // window got focused. - virtual void GotFocus() = 0; + // view got focused. + void GotFocus(); + + // Tell the renderer to set focus to this node. + void SetFocus(const BrowserAccessibility& node); + + // Tell the renderer to do the default action for this node. + void DoDefaultAction(const BrowserAccessibility& node); // Called when the renderer process has notified us of about tree changes. // Send a notification to MSAA clients of the change. void OnAccessibilityNotifications( const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params); - gfx::NativeWindow GetParentWindow(); + gfx::NativeView GetParentView(); #if defined(OS_WIN) - virtual IAccessible* GetRootAccessible() = 0; + BrowserAccessibilityManagerWin* toBrowserAccessibilityManagerWin(); #endif + // Return the object that has focus, if it's a descandant of the + // given root (inclusive). Does not make a new reference. + BrowserAccessibility* GetFocus(BrowserAccessibility* root); + protected: - explicit BrowserAccessibilityManager(gfx::NativeWindow parent_window); - - virtual void OnAccessibilityObjectStateChange( - const webkit_glue::WebAccessibility& acc_obj) = 0; - virtual void OnAccessibilityObjectChildrenChange( - const webkit_glue::WebAccessibility& acc_obj) = 0; - virtual void OnAccessibilityObjectFocusChange( - const webkit_glue::WebAccessibility& acc_obj) = 0; - virtual void OnAccessibilityObjectLoadComplete( - const webkit_glue::WebAccessibility& acc_obj) = 0; - virtual void OnAccessibilityObjectValueChange( - const webkit_glue::WebAccessibility& acc_obj) = 0; - virtual void OnAccessibilityObjectTextChange( - const webkit_glue::WebAccessibility& acc_obj) = 0; + BrowserAccessibilityManager( + gfx::NativeView parent_view, + const WebAccessibility& src, + BrowserAccessibilityDelegate* delegate, + BrowserAccessibilityFactory* factory); private: - // The parent window. - gfx::NativeWindow parent_window_; + void OnAccessibilityObjectStateChange( + const WebAccessibility& acc_obj); + void OnAccessibilityObjectChildrenChange( + const WebAccessibility& acc_obj); + void OnAccessibilityObjectFocusChange( + const WebAccessibility& acc_obj); + void OnAccessibilityObjectLoadComplete( + const WebAccessibility& acc_obj); + void OnAccessibilityObjectValueChange( + const WebAccessibility& acc_obj); + void OnAccessibilityObjectTextChange( + const WebAccessibility& acc_obj); + + // Recursively compare the IDs of our subtree to a new subtree received + // from the renderer and return true if their IDs match exactly. + bool CanModifyTreeInPlace( + BrowserAccessibility* current_root, + const WebAccessibility& new_root); + + // Recursively modify a subtree (by reinitializing) to match a new + // subtree received from the renderer process. Should only be called + // if CanModifyTreeInPlace returned true. + void ModifyTreeInPlace( + BrowserAccessibility* current_root, + const WebAccessibility& new_root); + + // Update the accessibility tree with an updated WebAccessibility tree or + // subtree received from the renderer process. First attempts to modify + // the tree in place, and if that fails, replaces the entire subtree. + // Returns the updated node or NULL if no node was updated. + BrowserAccessibility* UpdateTree( + const WebAccessibility& acc_obj); + + // Recursively build a tree of BrowserAccessibility objects from + // the WebAccessibility tree received from the renderer process. + BrowserAccessibility* CreateAccessibilityTree( + BrowserAccessibility* parent, + int child_id, + const WebAccessibility& src, + int index_in_parent); + + protected: + // The next unique id for a BrowserAccessibility instance. + static int32 next_child_id_; + + // The parent view. + gfx::NativeView parent_view_; + + // The object that can perform actions on our behalf. + BrowserAccessibilityDelegate* delegate_; + + // Factory to create BrowserAccessibility objects (for dependency injection). + scoped_ptr<BrowserAccessibilityFactory> factory_; + + // The root of the tree of IAccessible objects and the element that + // currently has focus, if any. + BrowserAccessibility* root_; + BrowserAccessibility* focus_; + + // A mapping from the IDs of objects in the renderer, to the child IDs + // we use internally here. + base::hash_map<int, int32> renderer_id_to_child_id_map_; + + // A mapping from child IDs to BrowserAccessibility objects. + base::hash_map<int32, BrowserAccessibility*> child_id_map_; DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManager); }; diff --git a/chrome/browser/accessibility/browser_accessibility_manager_win.cc b/chrome/browser/accessibility/browser_accessibility_manager_win.cc index 2bcd599..9c1e277 100644 --- a/chrome/browser/accessibility/browser_accessibility_manager_win.cc +++ b/chrome/browser/accessibility/browser_accessibility_manager_win.cc @@ -5,304 +5,75 @@ #include "chrome/browser/accessibility/browser_accessibility_manager_win.h" #include "chrome/browser/accessibility/browser_accessibility_win.h" -#include "chrome/browser/renderer_host/render_process_host.h" -#include "chrome/browser/renderer_host/render_view_host.h" -#include "chrome/common/render_messages.h" -#include "chrome/common/render_messages_params.h" using webkit_glue::WebAccessibility; // static BrowserAccessibilityManager* BrowserAccessibilityManager::Create( - gfx::NativeWindow parent_window, - const webkit_glue::WebAccessibility& src, - BrowserAccessibilityDelegate* delegate) { + gfx::NativeView parent_view, + const WebAccessibility& src, + BrowserAccessibilityDelegate* delegate, + BrowserAccessibilityFactory* factory) { return new BrowserAccessibilityManagerWin( - parent_window, src, delegate, new BrowserAccessibilityWinFactory()); + parent_view, + src, + delegate, + factory); } -// Factory method to create an instance of BrowserAccessibility -BrowserAccessibilityWin* BrowserAccessibilityWinFactory::Create() { - CComObject<BrowserAccessibilityWin>* instance; - HRESULT hr = CComObject<BrowserAccessibilityWin>::CreateInstance(&instance); - DCHECK(SUCCEEDED(hr)); - return instance->NewReference(); +BrowserAccessibilityManagerWin* +BrowserAccessibilityManager::toBrowserAccessibilityManagerWin() { + return static_cast<BrowserAccessibilityManagerWin*>(this); } -// 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 BrowserAccessibilityManagerWin::next_child_id_ = -1; - BrowserAccessibilityManagerWin::BrowserAccessibilityManagerWin( - HWND parent_window, - const webkit_glue::WebAccessibility& src, + HWND parent_view, + const WebAccessibility& src, BrowserAccessibilityDelegate* delegate, - BrowserAccessibilityWinFactory* factory) - : BrowserAccessibilityManager(parent_window), - delegate_(delegate), - factory_(factory), - focus_(NULL) { + BrowserAccessibilityFactory* factory) + : BrowserAccessibilityManager(parent_view, src, delegate, factory) { HRESULT hr = ::CreateStdAccessibleObject( - parent_window, OBJID_WINDOW, IID_IAccessible, + parent_view, OBJID_WINDOW, IID_IAccessible, reinterpret_cast<void **>(&window_iaccessible_)); DCHECK(SUCCEEDED(hr)); - root_ = CreateAccessibilityTree(NULL, GetNextChildID(), src, 0); - if (!focus_) - focus_ = root_; } BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() { - // 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(); -} - -BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetRoot() { - return root_; -} - -void BrowserAccessibilityManagerWin::Remove(LONG child_id) { - child_id_map_.erase(child_id); -} - -BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFromChildID( - LONG child_id) { - base::hash_map<LONG, BrowserAccessibilityWin*>::iterator iter = - child_id_map_.find(child_id); - if (iter != child_id_map_.end()) { - return iter->second; - } else { - return NULL; - } } IAccessible* BrowserAccessibilityManagerWin::GetParentWindowIAccessible() { return window_iaccessible_; } -BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFocus( - BrowserAccessibilityWin* root) { - if (focus_ && (!root || focus_->IsDescendantOf(root))) - return focus_; - - return NULL; -} - -void BrowserAccessibilityManagerWin::SetFocus( - const BrowserAccessibilityWin& node) { - if (delegate_) - delegate_->SetAccessibilityFocus(node.renderer_id()); -} - -void BrowserAccessibilityManagerWin::DoDefaultAction( - const BrowserAccessibilityWin& node) { - if (delegate_) - delegate_->AccessibilityDoDefaultAction(node.renderer_id()); -} - -bool BrowserAccessibilityManagerWin::CanModifyTreeInPlace( - BrowserAccessibilityWin* current_root, - const webkit_glue::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 BrowserAccessibilityManagerWin::ModifyTreeInPlace( - BrowserAccessibilityWin* current_root, - const webkit_glue::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); -} - - -BrowserAccessibilityWin* BrowserAccessibilityManagerWin::UpdateTree( - const webkit_glue::WebAccessibility& acc_obj) { - base::hash_map<int, LONG>::iterator iter = - renderer_id_to_child_id_map_.find(acc_obj.id); - if (iter == renderer_id_to_child_id_map_.end()) - return NULL; - - LONG child_id = iter->second; - BrowserAccessibilityWin* 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; - } - - BrowserAccessibilityWin* 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->InactivateTree(); - old_browser_acc->Release(); - child_id_map_[child_id] = new_browser_acc; - - return new_browser_acc; -} - -void BrowserAccessibilityManagerWin::GotFocus() { - // TODO(ctguil): Remove when tree update logic handles focus changes. - if (!focus_) - return; - - NotifyWinEvent( - EVENT_OBJECT_FOCUS, - GetParentWindow(), - OBJID_CLIENT, - focus_->child_id()); -} - -IAccessible* BrowserAccessibilityManagerWin::GetRootAccessible() { - return root_; -} - -void BrowserAccessibilityManagerWin::OnAccessibilityObjectStateChange( - const webkit_glue::WebAccessibility& acc_obj) { - BrowserAccessibilityWin* new_browser_acc = UpdateTree(acc_obj); - if (!new_browser_acc) - return; - - LONG child_id = new_browser_acc->child_id(); - NotifyWinEvent( - EVENT_OBJECT_STATECHANGE, GetParentWindow(), OBJID_CLIENT, child_id); -} - -void BrowserAccessibilityManagerWin::OnAccessibilityObjectChildrenChange( - const webkit_glue::WebAccessibility& acc_obj) { - BrowserAccessibilityWin* new_browser_acc = UpdateTree(acc_obj); - if (!new_browser_acc) - return; - - LONG child_id; - if (root_ != new_browser_acc) { - child_id = new_browser_acc->GetParent()->child_id(); - } else { - child_id = CHILDID_SELF; - } - - NotifyWinEvent( - EVENT_OBJECT_REORDER, GetParentWindow(), OBJID_CLIENT, child_id); -} - -void BrowserAccessibilityManagerWin::OnAccessibilityObjectFocusChange( - const webkit_glue::WebAccessibility& acc_obj) { - BrowserAccessibilityWin* new_browser_acc = UpdateTree(acc_obj); - if (!new_browser_acc) - return; - - focus_ = new_browser_acc; - LONG child_id = new_browser_acc->child_id(); - if (delegate_ && delegate_->HasFocus()) - GotFocus(); -} - -void BrowserAccessibilityManagerWin::OnAccessibilityObjectLoadComplete( - const webkit_glue::WebAccessibility& acc_obj) { - root_->InactivateTree(); - root_->Release(); - focus_ = NULL; - - root_ = CreateAccessibilityTree(NULL, GetNextChildID(), acc_obj, 0); - if (!focus_) - focus_ = root_; - - NotifyWinEvent( - IA2_EVENT_DOCUMENT_LOAD_COMPLETE, - GetParentWindow(), - OBJID_CLIENT, - root_->child_id()); - if (delegate_ && delegate_->HasFocus()) - GotFocus(); -} - -void BrowserAccessibilityManagerWin::OnAccessibilityObjectValueChange( - const webkit_glue::WebAccessibility& acc_obj) { - BrowserAccessibilityWin* new_browser_acc = UpdateTree(acc_obj); - if (!new_browser_acc) - return; - - LONG child_id = new_browser_acc->child_id(); - NotifyWinEvent( - EVENT_OBJECT_VALUECHANGE, GetParentWindow(), OBJID_CLIENT, child_id); -} - -void BrowserAccessibilityManagerWin::OnAccessibilityObjectTextChange( - const webkit_glue::WebAccessibility& acc_obj) { - BrowserAccessibilityWin* new_browser_acc = UpdateTree(acc_obj); - if (!new_browser_acc) - return; - - LONG child_id = new_browser_acc->child_id(); - NotifyWinEvent( - IA2_EVENT_TEXT_CARET_MOVED, GetParentWindow(), OBJID_CLIENT, child_id); -} - -LONG BrowserAccessibilityManagerWin::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_; -} - -BrowserAccessibilityWin* -BrowserAccessibilityManagerWin::CreateAccessibilityTree( - BrowserAccessibilityWin* parent, - int child_id, - const webkit_glue::WebAccessibility& src, - int index_in_parent) { - BrowserAccessibilityWin* 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) { - BrowserAccessibilityWin* child = CreateAccessibilityTree( - instance, GetNextChildID(), src.children[i], i); - instance->AddChild(child); +void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent( + ViewHostMsg_AccessibilityNotification_Params::NotificationType n, + BrowserAccessibility* node) { + LONG event_id; + switch (n) { + case ViewHostMsg_AccessibilityNotification_Params:: + NOTIFICATION_TYPE_CHECK_STATE_CHANGED: + event_id = EVENT_OBJECT_STATECHANGE; + break; + case ViewHostMsg_AccessibilityNotification_Params:: + NOTIFICATION_TYPE_CHILDREN_CHANGED: + event_id = EVENT_OBJECT_REORDER; + break; + case ViewHostMsg_AccessibilityNotification_Params:: + NOTIFICATION_TYPE_FOCUS_CHANGED: + event_id = EVENT_OBJECT_FOCUS; + break; + case ViewHostMsg_AccessibilityNotification_Params:: + NOTIFICATION_TYPE_LOAD_COMPLETE: + event_id = IA2_EVENT_DOCUMENT_LOAD_COMPLETE; + break; + case ViewHostMsg_AccessibilityNotification_Params:: + NOTIFICATION_TYPE_VALUE_CHANGED: + event_id = EVENT_OBJECT_VALUECHANGE; + break; + case ViewHostMsg_AccessibilityNotification_Params:: + NOTIFICATION_TYPE_SELECTED_TEXT_CHANGED: + event_id = IA2_EVENT_TEXT_CARET_MOVED; } - return instance; + NotifyWinEvent(event_id, GetParentView(), OBJID_CLIENT, node->child_id()); } diff --git a/chrome/browser/accessibility/browser_accessibility_manager_win.h b/chrome/browser/accessibility/browser_accessibility_manager_win.h index d216796..9ee396f 100644 --- a/chrome/browser/accessibility/browser_accessibility_manager_win.h +++ b/chrome/browser/accessibility/browser_accessibility_manager_win.h @@ -6,140 +6,44 @@ #define CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_WIN_H_ #pragma once -#include <atlbase.h> -#include <atlcom.h> #include <oleacc.h> -#include <hash_map> -#include <vector> - -#include "chrome/browser/accessibility/browser_accessibility_manager.h" -#include "base/hash_tables.h" #include "base/scoped_comptr_win.h" -#include "base/scoped_ptr.h" +#include "chrome/browser/accessibility/browser_accessibility_manager.h" +#include "chrome/common/render_messages_params.h" #include "webkit/glue/webaccessibility.h" class BrowserAccessibilityWin; struct ViewHostMsg_AccessibilityNotification_Params; -class BrowserAccessibilityWinFactory { - public: - virtual ~BrowserAccessibilityWinFactory() {} - - // Create an instance of BrowserAccessibilityWin and return a new - // reference to it. - virtual BrowserAccessibilityWin* Create(); -}; +using webkit_glue::WebAccessibility; // Manages a tree of BrowserAccessibilityWin objects. class BrowserAccessibilityManagerWin : public BrowserAccessibilityManager { public: - BrowserAccessibilityManagerWin( - HWND parent_window, - const webkit_glue::WebAccessibility& src, - BrowserAccessibilityDelegate* delegate, - BrowserAccessibilityWinFactory* factory = - new BrowserAccessibilityWinFactory()); - virtual ~BrowserAccessibilityManagerWin(); - // Return a pointer to the root of the tree, does not make a new reference. - BrowserAccessibilityWin* GetRoot(); - - // Removes the BrowserAccessibilityWin child_id from the manager. - void Remove(LONG child_id); - - // Return a pointer to the object corresponding to the given child_id, - // does not make a new reference. - BrowserAccessibilityWin* GetFromChildID(LONG child_id); - // Get a the default IAccessible for the parent window, does not make a // new reference. IAccessible* GetParentWindowIAccessible(); - // Return the object that has focus, if it's a descandant of the - // given root (inclusive). Does not make a new reference. - BrowserAccessibilityWin* GetFocus(BrowserAccessibilityWin* root); - - // Tell the renderer to set focus to this node. - void SetFocus(const BrowserAccessibilityWin& node); - - // Tell the renderer to do the default action for this node. - void DoDefaultAction(const BrowserAccessibilityWin& node); - - // BrowserAccessibilityManager Methods - virtual void GotFocus(); - virtual IAccessible* GetRootAccessible(); - virtual void OnAccessibilityObjectStateChange( - const webkit_glue::WebAccessibility& acc_obj); - virtual void OnAccessibilityObjectChildrenChange( - const webkit_glue::WebAccessibility& acc_obj); - virtual void OnAccessibilityObjectFocusChange( - const webkit_glue::WebAccessibility& acc_obj); - virtual void OnAccessibilityObjectLoadComplete( - const webkit_glue::WebAccessibility& acc_obj); - virtual void OnAccessibilityObjectValueChange( - const webkit_glue::WebAccessibility& acc_obj); - virtual void OnAccessibilityObjectTextChange( - const webkit_glue::WebAccessibility& acc_obj); + // BrowserAccessibilityManager methods + virtual void NotifyAccessibilityEvent( + ViewHostMsg_AccessibilityNotification_Params::NotificationType n, + BrowserAccessibility* node); private: - // Recursively compare the IDs of our subtree to a new subtree received - // from the renderer and return true if their IDs match exactly. - bool CanModifyTreeInPlace( - BrowserAccessibilityWin* current_root, - const webkit_glue::WebAccessibility& new_root); - - // Recursively modify a subtree (by reinitializing) to match a new - // subtree received from the renderer process. Should only be called - // if CanModifyTreeInPlace returned true. - void ModifyTreeInPlace( - BrowserAccessibilityWin* current_root, - const webkit_glue::WebAccessibility& new_root); - - // Update the accessibility tree with an updated WebAccessibility tree or - // subtree received from the renderer process. First attempts to modify - // the tree in place, and if that fails, replaces the entire subtree. - // Returns the updated node or NULL if no node was updated. - BrowserAccessibilityWin* UpdateTree( - const webkit_glue::WebAccessibility& acc_obj); - - // Returns the next MSAA child id. - static LONG GetNextChildID(); - - // Recursively build a tree of BrowserAccessibilityWin objects from - // the WebAccessibility tree received from the renderer process. - BrowserAccessibilityWin* CreateAccessibilityTree( - BrowserAccessibilityWin* parent, - int child_id, - const webkit_glue::WebAccessibility& src, - int index_in_parent); - - // The object that can perform actions on our behalf. - BrowserAccessibilityDelegate* delegate_; - - // Factory to create BrowserAccessibility objects (for dependency injection). - scoped_ptr<BrowserAccessibilityWinFactory> factory_; + BrowserAccessibilityManagerWin( + HWND parent_window, + const WebAccessibility& src, + BrowserAccessibilityDelegate* delegate, + BrowserAccessibilityFactory* factory); // A default IAccessible instance for the parent window. ScopedComPtr<IAccessible> window_iaccessible_; - // The root of the tree of IAccessible objects and the element that - // currently has focus, if any. - BrowserAccessibilityWin* root_; - BrowserAccessibilityWin* focus_; - - // A mapping from the IDs of objects in the renderer, to the child IDs - // we use internally here. - base::hash_map<int, LONG> renderer_id_to_child_id_map_; - - // A mapping from child IDs to BrowserAccessibilityWin objects. - base::hash_map<LONG, BrowserAccessibilityWin*> child_id_map_; - - // The next child ID to use; static so that they're global to the process. - // Screen readers cache these IDs to see if they've seen the same object - // before so we should avoid reusing them within the same project. - static LONG next_child_id_; + // Give BrowserAccessibilityManager::Create access to our constructor. + friend class BrowserAccessibilityManager; DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManagerWin); }; diff --git a/chrome/browser/accessibility/browser_accessibility_win.cc b/chrome/browser/accessibility/browser_accessibility_win.cc index f3520ee..432eb1a 100644 --- a/chrome/browser/accessibility/browser_accessibility_win.cc +++ b/chrome/browser/accessibility/browser_accessibility_win.cc @@ -12,133 +12,24 @@ using webkit_glue::WebAccessibility; -BrowserAccessibilityWin::BrowserAccessibilityWin() - : manager_(NULL), - parent_(NULL), - child_id_(-1), - index_in_parent_(-1), - renderer_id_(-1), - instance_active_(false) { -} - -BrowserAccessibilityWin::~BrowserAccessibilityWin() { - InactivateTree(); -} - -void BrowserAccessibilityWin::Initialize( - BrowserAccessibilityManagerWin* manager, - BrowserAccessibilityWin* parent, - LONG child_id, - LONG index_in_parent, - const webkit_glue::WebAccessibility& src) { - manager_ = manager; - parent_ = parent; - child_id_ = child_id; - index_in_parent_ = index_in_parent; - - renderer_id_ = src.id; - name_ = src.name; - value_ = src.value; - attributes_ = src.attributes; - html_attributes_ = src.html_attributes; - location_ = src.location; - src_role_ = src.role; - InitRoleAndState(src.role, src.state); - - // Expose headings levels to NVDA with the "level" object attribute. - if (src.role == WebAccessibility::ROLE_HEADING && role_name_.size() == 2 && - IsAsciiDigit(role_name_[1])) { - html_attributes_.push_back(std::make_pair(L"level", role_name_.substr(1))); - } - - // If this object doesn't have a name but it does have a description, - // use the description as its name - because some screen readers only - // announce the name. - if (name_.empty() && HasAttribute(WebAccessibility::ATTR_DESCRIPTION)) { - GetAttribute(WebAccessibility::ATTR_DESCRIPTION, &name_); - } - - instance_active_ = true; -} - -void BrowserAccessibilityWin::AddChild(BrowserAccessibilityWin* child) { - children_.push_back(child); -} - -void BrowserAccessibilityWin::InactivateTree() { - if (!instance_active_) - return; - - // Mark this object as inactive, so calls to all COM methods will return - // failure. - instance_active_ = false; - - // Now we can safely call InactivateTree on our children and remove - // references to them, so that as much of the tree as possible will be - // destroyed now - however, nodes that still have references to them - // might stick around a while until all clients have released them. - for (std::vector<BrowserAccessibilityWin*>::iterator iter = - children_.begin(); - iter != children_.end(); ++iter) { - (*iter)->InactivateTree(); - (*iter)->Release(); - } - children_.clear(); - manager_->Remove(child_id_); -} - -bool BrowserAccessibilityWin::IsDescendantOf( - BrowserAccessibilityWin* ancestor) { - if (this == ancestor) { - return true; - } else if (parent_) { - return parent_->IsDescendantOf(ancestor); - } - - return false; -} - -BrowserAccessibilityWin* BrowserAccessibilityWin::GetParent() { - return parent_; -} - -uint32 BrowserAccessibilityWin::GetChildCount() { - return children_.size(); -} - -BrowserAccessibilityWin* BrowserAccessibilityWin::GetChild(uint32 child_index) { - DCHECK(child_index >= 0 && child_index < children_.size()); - return children_[child_index]; -} - -BrowserAccessibilityWin* BrowserAccessibilityWin::GetPreviousSibling() { - if (parent_ && index_in_parent_ > 0) - return parent_->children_[index_in_parent_ - 1]; - - return NULL; +// static +BrowserAccessibility* BrowserAccessibility::Create() { + CComObject<BrowserAccessibilityWin>* instance; + HRESULT hr = CComObject<BrowserAccessibilityWin>::CreateInstance(&instance); + DCHECK(SUCCEEDED(hr)); + return instance->NewReference(); } -BrowserAccessibilityWin* BrowserAccessibilityWin::GetNextSibling() { - if (parent_ && - index_in_parent_ >= 0 && - index_in_parent_ < static_cast<int>(parent_->children_.size() - 1)) { - return parent_->children_[index_in_parent_ + 1]; - } - - return NULL; +BrowserAccessibilityWin* BrowserAccessibility::toBrowserAccessibilityWin() { + return static_cast<BrowserAccessibilityWin*>(this); } -void BrowserAccessibilityWin::ReplaceChild( - const BrowserAccessibilityWin* old_acc, BrowserAccessibilityWin* new_acc) { - DCHECK_EQ(children_[old_acc->index_in_parent_], old_acc); - - old_acc = children_[old_acc->index_in_parent_]; - children_[old_acc->index_in_parent_] = new_acc; +BrowserAccessibilityWin::BrowserAccessibilityWin() + : instance_active_(false) { } -BrowserAccessibilityWin* BrowserAccessibilityWin::NewReference() { - AddRef(); - return this; +BrowserAccessibilityWin::~BrowserAccessibilityWin() { + ReleaseTree(); } // @@ -188,7 +79,7 @@ STDMETHODIMP BrowserAccessibilityWin::accLocation(LONG* x_left, LONG* y_top, // Find the top left corner of the containing window in screen coords, and // adjust the output position by this amount. - HWND parent_hwnd = manager_->GetParentWindow(); + HWND parent_hwnd = manager_->GetParentView(); POINT top_left = {0, 0}; ::ClientToScreen(parent_hwnd, &top_left); @@ -212,7 +103,7 @@ STDMETHODIMP BrowserAccessibilityWin::accNavigate( return E_INVALIDARG; } - BrowserAccessibilityWin* result = NULL; + BrowserAccessibility* result = NULL; switch (nav_dir) { case NAVDIR_DOWN: case NAVDIR_UP: @@ -242,7 +133,7 @@ STDMETHODIMP BrowserAccessibilityWin::accNavigate( } end->vt = VT_DISPATCH; - end->pdispVal = result->NewReference(); + end->pdispVal = result->toBrowserAccessibilityWin()->NewReference(); return S_OK; } @@ -384,11 +275,12 @@ STDMETHODIMP BrowserAccessibilityWin::get_accParent(IDispatch** disp_parent) { if (!disp_parent) return E_INVALIDARG; - IAccessible* parent = parent_; + IAccessible* parent = parent_->toBrowserAccessibilityWin(); if (parent == NULL) { // This happens if we're the root of the tree; // return the IAccessible for the window. - parent = manager_->GetParentWindowIAccessible(); + parent = manager_->toBrowserAccessibilityManagerWin()-> + GetParentWindowIAccessible(); } parent->AddRef(); @@ -413,7 +305,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_accRole( role->bstrVal = SysAllocString(target->role_name_.c_str()); } else { role->vt = VT_I4; - role->lVal = target->role_; + role->lVal = target->ia_role_; } return S_OK; } @@ -431,7 +323,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_accState(VARIANT var_id, return E_INVALIDARG; state->vt = VT_I4; - state->lVal = target->state_; + state->lVal = target->ia_state_; if (manager_->GetFocus(NULL) == this) state->lVal |= STATE_SYSTEM_FOCUSED; @@ -553,7 +445,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_windowHandle(HWND* window_handle) { if (!window_handle) return E_INVALIDARG; - *window_handle = manager_->GetParentWindow(); + *window_handle = manager_->GetParentView(); return S_OK; } @@ -591,7 +483,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_imagePosition( return E_INVALIDARG; if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) { - HWND parent_hwnd = manager_->GetParentWindow(); + HWND parent_hwnd = manager_->GetParentView(); POINT top_left = {0, 0}; ::ClientToScreen(parent_hwnd, &top_left); *x = location_.x + top_left.x; @@ -600,8 +492,8 @@ STDMETHODIMP BrowserAccessibilityWin::get_imagePosition( *x = location_.x; *y = location_.y; if (parent_) { - *x -= parent_->location_.x; - *y -= parent_->location_.y; + *x -= parent_->location().x; + *y -= parent_->location().y; } } else { return E_INVALIDARG; @@ -633,7 +525,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_nCharacters(LONG* n_characters) { if (!n_characters) return E_INVALIDARG; - if (src_role_ == WebAccessibility::ROLE_TEXT_FIELD) { + if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { *n_characters = value_.length(); } else { *n_characters = name_.length(); @@ -651,7 +543,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_text( return E_INVALIDARG; string16 text_str; - if (src_role_ == WebAccessibility::ROLE_TEXT_FIELD) { + if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { text_str = value_; } else { text_str = name_; @@ -688,7 +580,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) { if (!offset) return E_INVALIDARG; - if (src_role_ == WebAccessibility::ROLE_TEXT_FIELD) { + if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { int sel_start = 0; if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start)) { *offset = sel_start; @@ -709,7 +601,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_nSelections(LONG* n_selections) { if (!n_selections) return E_INVALIDARG; - if (src_role_ == WebAccessibility::ROLE_TEXT_FIELD) { + if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { int sel_start = 0; int sel_end = 0; if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start) && @@ -735,7 +627,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_selection(LONG selection_index, if (!start_offset || !end_offset || selection_index != 0) return E_INVALIDARG; - if (src_role_ == WebAccessibility::ROLE_TEXT_FIELD) { + if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { int sel_start = 0; int sel_end = 0; if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start) && @@ -828,9 +720,9 @@ STDMETHODIMP BrowserAccessibilityWin::get_nodeInfo( *num_children = children_.size(); *unique_id = child_id_; - if (role_ == ROLE_SYSTEM_DOCUMENT) { + if (ia_role_ == ROLE_SYSTEM_DOCUMENT) { *node_type = NODETYPE_DOCUMENT; - } else if (role_ == ROLE_SYSTEM_TEXT && + } else if (ia_role_ == ROLE_SYSTEM_TEXT && ((ia2_state_ & IA2_STATE_EDITABLE) == 0)) { *node_type = NODETYPE_TEXT; } else { @@ -961,7 +853,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_parentNode(ISimpleDOMNode** node) { if (!node) return E_INVALIDARG; - *node = parent_->NewReference(); + *node = parent_->toBrowserAccessibilityWin()->NewReference(); return S_OK; } @@ -973,7 +865,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_firstChild(ISimpleDOMNode** node) { return E_INVALIDARG; if (children_.size()) { - *node = children_[0]->NewReference(); + *node = children_[0]->toBrowserAccessibilityWin()->NewReference(); return S_OK; } else { *node = NULL; @@ -989,7 +881,8 @@ STDMETHODIMP BrowserAccessibilityWin::get_lastChild(ISimpleDOMNode** node) { return E_INVALIDARG; if (children_.size()) { - *node = children_[children_.size() - 1]->NewReference(); + *node = children_[children_.size() - 1]->toBrowserAccessibilityWin()-> + NewReference(); return S_OK; } else { *node = NULL; @@ -1006,7 +899,8 @@ STDMETHODIMP BrowserAccessibilityWin::get_previousSibling( return E_INVALIDARG; if (parent_ && index_in_parent_ > 0) { - *node = parent_->children_[index_in_parent_ - 1]->NewReference(); + *node = parent_->children()[index_in_parent_ - 1]-> + toBrowserAccessibilityWin()->NewReference(); return S_OK; } else { *node = NULL; @@ -1023,8 +917,9 @@ STDMETHODIMP BrowserAccessibilityWin::get_nextSibling(ISimpleDOMNode** node) { if (parent_ && index_in_parent_ >= 0 && - index_in_parent_ < static_cast<int>(parent_->children_.size()) - 1) { - *node = parent_->children_[index_in_parent_ + 1]->NewReference(); + index_in_parent_ < static_cast<int>(parent_->children().size()) - 1) { + *node = parent_->children()[index_in_parent_ + 1]-> + toBrowserAccessibilityWin()->NewReference(); return S_OK; } else { *node = NULL; @@ -1042,7 +937,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_childAt( return E_INVALIDARG; if (child_index < children_.size()) { - *node = children_[child_index]->NewReference(); + *node = children_[child_index]->toBrowserAccessibilityWin()->NewReference(); return S_OK; } else { *node = NULL; @@ -1102,17 +997,17 @@ HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface( REFIID iid, void** object) { if (iid == IID_IAccessibleText) { - if (role_ != ROLE_SYSTEM_LINK && role_ != ROLE_SYSTEM_TEXT) { + if (ia_role_ != ROLE_SYSTEM_LINK && ia_role_ != ROLE_SYSTEM_TEXT) { *object = NULL; return E_NOINTERFACE; } } else if (iid == IID_IAccessibleImage) { - if (role_ != ROLE_SYSTEM_GRAPHIC) { + if (ia_role_ != ROLE_SYSTEM_GRAPHIC) { *object = NULL; return E_NOINTERFACE; } } else if (iid == IID_ISimpleDOMDocument) { - if (role_ != ROLE_SYSTEM_DOCUMENT) { + if (ia_role_ != ROLE_SYSTEM_DOCUMENT) { *object = NULL; return E_NOINTERFACE; } @@ -1126,6 +1021,50 @@ HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface( // Private methods. // +// Initialize this object and mark it as active. +void BrowserAccessibilityWin::Initialize() { + InitRoleAndState(); + + // Expose headings levels to NVDA with the "level" object attribute. + if (role_ == WebAccessibility::ROLE_HEADING && role_name_.size() == 2 && + IsAsciiDigit(role_name_[1])) { + html_attributes_.push_back(std::make_pair(L"level", role_name_.substr(1))); + } + + // If this object doesn't have a name but it does have a description, + // use the description as its name - because some screen readers only + // announce the name. + if (name_.empty() && HasAttribute(WebAccessibility::ATTR_DESCRIPTION)) { + GetAttribute(WebAccessibility::ATTR_DESCRIPTION, &name_); + } + + instance_active_ = true; +} + +// Mark this object as inactive, and remove references to all children. +// When no other clients hold any references to this object it will be +// deleted, and in the meantime, calls to any methods will return E_FAIL. +void BrowserAccessibilityWin::ReleaseTree() { + if (!instance_active_) + return; + + // Mark this object as inactive, so calls to all COM methods will return + // failure. + instance_active_ = false; + + BrowserAccessibility::ReleaseTree(); +} + +void BrowserAccessibilityWin::ReleaseReference() { + Release(); +} + + +BrowserAccessibilityWin* BrowserAccessibilityWin::NewReference() { + AddRef(); + return this; +} + BrowserAccessibilityWin* BrowserAccessibilityWin::GetTargetFromChildID( const VARIANT& var_id) { if (var_id.vt != VT_I4) @@ -1136,9 +1075,9 @@ BrowserAccessibilityWin* BrowserAccessibilityWin::GetTargetFromChildID( return this; if (child_id >= 1 && child_id <= static_cast<LONG>(children_.size())) - return children_[child_id - 1]; + return children_[child_id - 1]->toBrowserAccessibilityWin(); - return manager_->GetFromChildID(child_id); + return manager_->GetFromChildID(child_id)->toBrowserAccessibilityWin(); } bool BrowserAccessibilityWin::HasAttribute( @@ -1190,110 +1129,109 @@ string16 BrowserAccessibilityWin::Escape(string16 str) { return EscapeQueryParamValueUTF8(str, false); } -void BrowserAccessibilityWin::InitRoleAndState(LONG web_role, - LONG web_state) { - state_ = 0; +void BrowserAccessibilityWin::InitRoleAndState() { + ia_state_ = 0; ia2_state_ = IA2_STATE_OPAQUE; - if ((web_state >> WebAccessibility::STATE_CHECKED) & 1) - state_ |= STATE_SYSTEM_CHECKED; - if ((web_state >> WebAccessibility::STATE_COLLAPSED) & 1) - state_ |= STATE_SYSTEM_COLLAPSED; - if ((web_state >> WebAccessibility::STATE_EXPANDED) & 1) - state_ |= STATE_SYSTEM_EXPANDED; - if ((web_state >> WebAccessibility::STATE_FOCUSABLE) & 1) - state_ |= STATE_SYSTEM_FOCUSABLE; - if ((web_state >> WebAccessibility::STATE_HASPOPUP) & 1) - state_ |= STATE_SYSTEM_HASPOPUP; - if ((web_state >> WebAccessibility::STATE_HOTTRACKED) & 1) - state_ |= STATE_SYSTEM_HOTTRACKED; - if ((web_state >> WebAccessibility::STATE_INDETERMINATE) & 1) - state_ |= STATE_SYSTEM_INDETERMINATE; - if ((web_state >> WebAccessibility::STATE_INVISIBLE) & 1) - state_ |= STATE_SYSTEM_INVISIBLE; - if ((web_state >> WebAccessibility::STATE_LINKED) & 1) - state_ |= STATE_SYSTEM_LINKED; - if ((web_state >> WebAccessibility::STATE_MULTISELECTABLE) & 1) - state_ |= STATE_SYSTEM_MULTISELECTABLE; + if ((state_ >> WebAccessibility::STATE_CHECKED) & 1) + ia_state_ |= STATE_SYSTEM_CHECKED; + if ((state_ >> WebAccessibility::STATE_COLLAPSED) & 1) + ia_state_|= STATE_SYSTEM_COLLAPSED; + if ((state_ >> WebAccessibility::STATE_EXPANDED) & 1) + ia_state_|= STATE_SYSTEM_EXPANDED; + if ((state_ >> WebAccessibility::STATE_FOCUSABLE) & 1) + ia_state_|= STATE_SYSTEM_FOCUSABLE; + if ((state_ >> WebAccessibility::STATE_HASPOPUP) & 1) + ia_state_|= STATE_SYSTEM_HASPOPUP; + if ((state_ >> WebAccessibility::STATE_HOTTRACKED) & 1) + ia_state_|= STATE_SYSTEM_HOTTRACKED; + if ((state_ >> WebAccessibility::STATE_INDETERMINATE) & 1) + ia_state_|= STATE_SYSTEM_INDETERMINATE; + if ((state_ >> WebAccessibility::STATE_INVISIBLE) & 1) + ia_state_|= STATE_SYSTEM_INVISIBLE; + if ((state_ >> WebAccessibility::STATE_LINKED) & 1) + ia_state_|= STATE_SYSTEM_LINKED; + if ((state_ >> WebAccessibility::STATE_MULTISELECTABLE) & 1) + ia_state_|= STATE_SYSTEM_MULTISELECTABLE; // TODO(ctguil): Support STATE_SYSTEM_EXTSELECTABLE/accSelect. - if ((web_state >> WebAccessibility::STATE_OFFSCREEN) & 1) - state_ |= STATE_SYSTEM_OFFSCREEN; - if ((web_state >> WebAccessibility::STATE_PRESSED) & 1) - state_ |= STATE_SYSTEM_PRESSED; - if ((web_state >> WebAccessibility::STATE_PROTECTED) & 1) - state_ |= STATE_SYSTEM_PROTECTED; - if ((web_state >> WebAccessibility::STATE_SELECTABLE) & 1) - state_ |= STATE_SYSTEM_SELECTABLE; - if ((web_state >> WebAccessibility::STATE_SELECTED) & 1) - state_ |= STATE_SYSTEM_SELECTED; - if ((web_state >> WebAccessibility::STATE_READONLY) & 1) - state_ |= STATE_SYSTEM_READONLY; - if ((web_state >> WebAccessibility::STATE_TRAVERSED) & 1) - state_ |= STATE_SYSTEM_TRAVERSED; - if ((web_state >> WebAccessibility::STATE_BUSY) & 1) - state_ |= STATE_SYSTEM_BUSY; - if ((web_state >> WebAccessibility::STATE_UNAVAILABLE) & 1) - state_ |= STATE_SYSTEM_UNAVAILABLE; - - role_ = 0; + if ((state_ >> WebAccessibility::STATE_OFFSCREEN) & 1) + ia_state_|= STATE_SYSTEM_OFFSCREEN; + if ((state_ >> WebAccessibility::STATE_PRESSED) & 1) + ia_state_|= STATE_SYSTEM_PRESSED; + if ((state_ >> WebAccessibility::STATE_PROTECTED) & 1) + ia_state_|= STATE_SYSTEM_PROTECTED; + if ((state_ >> WebAccessibility::STATE_SELECTABLE) & 1) + ia_state_|= STATE_SYSTEM_SELECTABLE; + if ((state_ >> WebAccessibility::STATE_SELECTED) & 1) + ia_state_|= STATE_SYSTEM_SELECTED; + if ((state_ >> WebAccessibility::STATE_READONLY) & 1) + ia_state_|= STATE_SYSTEM_READONLY; + if ((state_ >> WebAccessibility::STATE_TRAVERSED) & 1) + ia_state_|= STATE_SYSTEM_TRAVERSED; + if ((state_ >> WebAccessibility::STATE_BUSY) & 1) + ia_state_|= STATE_SYSTEM_BUSY; + if ((state_ >> WebAccessibility::STATE_UNAVAILABLE) & 1) + ia_state_|= STATE_SYSTEM_UNAVAILABLE; + + ia_role_ = 0; ia2_role_ = 0; - switch (web_role) { + switch (role_) { case WebAccessibility::ROLE_ALERT: case WebAccessibility::ROLE_ALERT_DIALOG: - role_ = ROLE_SYSTEM_ALERT; + ia_role_ = ROLE_SYSTEM_ALERT; break; case WebAccessibility::ROLE_APPLICATION: - role_ = ROLE_SYSTEM_APPLICATION; + ia_role_ = ROLE_SYSTEM_APPLICATION; break; case WebAccessibility::ROLE_ARTICLE: - role_ = ROLE_SYSTEM_GROUPING; + ia_role_ = ROLE_SYSTEM_GROUPING; ia2_role_ = IA2_ROLE_SECTION; break; case WebAccessibility::ROLE_BUTTON: - role_ = ROLE_SYSTEM_PUSHBUTTON; + ia_role_ = ROLE_SYSTEM_PUSHBUTTON; break; case WebAccessibility::ROLE_CELL: - role_ = ROLE_SYSTEM_CELL; + ia_role_ = ROLE_SYSTEM_CELL; break; case WebAccessibility::ROLE_CHECKBOX: - role_ = ROLE_SYSTEM_CHECKBUTTON; + ia_role_ = ROLE_SYSTEM_CHECKBUTTON; break; case WebAccessibility::ROLE_COLOR_WELL: - role_ = ROLE_SYSTEM_CLIENT; + ia_role_ = ROLE_SYSTEM_CLIENT; ia2_role_ = IA2_ROLE_COLOR_CHOOSER; break; case WebAccessibility::ROLE_COLUMN: - role_ = ROLE_SYSTEM_COLUMN; + ia_role_ = ROLE_SYSTEM_COLUMN; break; case WebAccessibility::ROLE_COLUMN_HEADER: - role_ = ROLE_SYSTEM_COLUMNHEADER; + ia_role_ = ROLE_SYSTEM_COLUMNHEADER; break; case WebAccessibility::ROLE_COMBO_BOX: - role_ = ROLE_SYSTEM_COMBOBOX; + ia_role_ = ROLE_SYSTEM_COMBOBOX; break; case WebAccessibility::ROLE_DEFINITION_LIST_DEFINITION: GetAttribute(WebAccessibility::ATTR_HTML_TAG, &role_name_); ia2_role_ = IA2_ROLE_PARAGRAPH; break; case WebAccessibility::ROLE_DEFINITION_LIST_TERM: - role_ = ROLE_SYSTEM_LISTITEM; + ia_role_ = ROLE_SYSTEM_LISTITEM; break; case WebAccessibility::ROLE_DIALOG: - role_ = ROLE_SYSTEM_DIALOG; + ia_role_ = ROLE_SYSTEM_DIALOG; break; case WebAccessibility::ROLE_DOCUMENT: case WebAccessibility::ROLE_WEB_AREA: - role_ = ROLE_SYSTEM_DOCUMENT; - state_ |= STATE_SYSTEM_READONLY; - state_ |= STATE_SYSTEM_FOCUSABLE; + ia_role_ = ROLE_SYSTEM_DOCUMENT; + ia_state_|= STATE_SYSTEM_READONLY; + ia_state_|= STATE_SYSTEM_FOCUSABLE; break; case WebAccessibility::ROLE_EDITABLE_TEXT: - role_ = ROLE_SYSTEM_TEXT; + ia_role_ = ROLE_SYSTEM_TEXT; ia2_state_ |= IA2_STATE_SINGLE_LINE; ia2_state_ |= IA2_STATE_EDITABLE; break; case WebAccessibility::ROLE_GRID: - role_ = ROLE_SYSTEM_TABLE; + ia_role_ = ROLE_SYSTEM_TABLE; break; case WebAccessibility::ROLE_GROUP: GetAttribute(WebAccessibility::ATTR_HTML_TAG, &role_name_); @@ -1306,15 +1244,15 @@ void BrowserAccessibilityWin::InitRoleAndState(LONG web_role, ia2_role_ = IA2_ROLE_HEADING; break; case WebAccessibility::ROLE_IMAGE: - role_ = ROLE_SYSTEM_GRAPHIC; + ia_role_ = ROLE_SYSTEM_GRAPHIC; break; case WebAccessibility::ROLE_IMAGE_MAP: GetAttribute(WebAccessibility::ATTR_HTML_TAG, &role_name_); ia2_role_ = IA2_ROLE_IMAGE_MAP; break; case WebAccessibility::ROLE_IMAGE_MAP_LINK: - role_ = ROLE_SYSTEM_LINK; - state_ |= STATE_SYSTEM_LINKED; + ia_role_ = ROLE_SYSTEM_LINK; + ia_state_|= STATE_SYSTEM_LINKED; break; case WebAccessibility::ROLE_LANDMARK_APPLICATION: case WebAccessibility::ROLE_LANDMARK_BANNER: @@ -1323,136 +1261,136 @@ void BrowserAccessibilityWin::InitRoleAndState(LONG web_role, case WebAccessibility::ROLE_LANDMARK_MAIN: case WebAccessibility::ROLE_LANDMARK_NAVIGATION: case WebAccessibility::ROLE_LANDMARK_SEARCH: - role_ = ROLE_SYSTEM_GROUPING; + ia_role_ = ROLE_SYSTEM_GROUPING; ia2_role_ = IA2_ROLE_SECTION; break; case WebAccessibility::ROLE_LINK: case WebAccessibility::ROLE_WEBCORE_LINK: - role_ = ROLE_SYSTEM_LINK; - state_ |= STATE_SYSTEM_LINKED; + ia_role_ = ROLE_SYSTEM_LINK; + ia_state_|= STATE_SYSTEM_LINKED; break; case WebAccessibility::ROLE_LIST: - role_ = ROLE_SYSTEM_LIST; + ia_role_ = ROLE_SYSTEM_LIST; break; case WebAccessibility::ROLE_LISTBOX: - role_ = ROLE_SYSTEM_LIST; + ia_role_ = ROLE_SYSTEM_LIST; break; case WebAccessibility::ROLE_LISTBOX_OPTION: case WebAccessibility::ROLE_LIST_ITEM: case WebAccessibility::ROLE_LIST_MARKER: - role_ = ROLE_SYSTEM_LISTITEM; + ia_role_ = ROLE_SYSTEM_LISTITEM; break; case WebAccessibility::ROLE_MENU: case WebAccessibility::ROLE_MENU_BUTTON: - role_ = ROLE_SYSTEM_MENUPOPUP; + ia_role_ = ROLE_SYSTEM_MENUPOPUP; break; case WebAccessibility::ROLE_MENU_BAR: - role_ = ROLE_SYSTEM_MENUBAR; + ia_role_ = ROLE_SYSTEM_MENUBAR; break; case WebAccessibility::ROLE_MENU_ITEM: case WebAccessibility::ROLE_MENU_LIST_OPTION: - role_ = ROLE_SYSTEM_MENUITEM; + ia_role_ = ROLE_SYSTEM_MENUITEM; break; case WebAccessibility::ROLE_MENU_LIST_POPUP: - role_ = ROLE_SYSTEM_MENUPOPUP; + ia_role_ = ROLE_SYSTEM_MENUPOPUP; break; case WebAccessibility::ROLE_NOTE: - role_ = ROLE_SYSTEM_GROUPING; + ia_role_ = ROLE_SYSTEM_GROUPING; ia2_role_ = IA2_ROLE_NOTE; break; case WebAccessibility::ROLE_OUTLINE: - role_ = ROLE_SYSTEM_OUTLINE; + ia_role_ = ROLE_SYSTEM_OUTLINE; break; case WebAccessibility::ROLE_POPUP_BUTTON: - role_ = ROLE_SYSTEM_COMBOBOX; + ia_role_ = ROLE_SYSTEM_COMBOBOX; break; case WebAccessibility::ROLE_PROGRESS_INDICATOR: - role_ = ROLE_SYSTEM_PROGRESSBAR; + ia_role_ = ROLE_SYSTEM_PROGRESSBAR; break; case WebAccessibility::ROLE_RADIO_BUTTON: - role_ = ROLE_SYSTEM_RADIOBUTTON; + ia_role_ = ROLE_SYSTEM_RADIOBUTTON; break; case WebAccessibility::ROLE_RADIO_GROUP: - role_ = ROLE_SYSTEM_GROUPING; + ia_role_ = ROLE_SYSTEM_GROUPING; ia2_role_ = IA2_ROLE_SECTION; break; case WebAccessibility::ROLE_REGION: - role_ = ROLE_SYSTEM_GROUPING; + ia_role_ = ROLE_SYSTEM_GROUPING; ia2_role_ = IA2_ROLE_SECTION; break; case WebAccessibility::ROLE_ROW: - role_ = ROLE_SYSTEM_ROW; + ia_role_ = ROLE_SYSTEM_ROW; break; case WebAccessibility::ROLE_ROW_HEADER: - role_ = ROLE_SYSTEM_ROWHEADER; + ia_role_ = ROLE_SYSTEM_ROWHEADER; break; case WebAccessibility::ROLE_RULER: - role_ = ROLE_SYSTEM_CLIENT; + ia_role_ = ROLE_SYSTEM_CLIENT; ia2_role_ = IA2_ROLE_RULER; break; case WebAccessibility::ROLE_SCROLLAREA: - role_ = ROLE_SYSTEM_CLIENT; + ia_role_ = ROLE_SYSTEM_CLIENT; ia2_role_ = IA2_ROLE_SCROLL_PANE; break; case WebAccessibility::ROLE_SCROLLBAR: - role_ = ROLE_SYSTEM_SCROLLBAR; + ia_role_ = ROLE_SYSTEM_SCROLLBAR; break; case WebAccessibility::ROLE_SLIDER: - role_ = ROLE_SYSTEM_SLIDER; + ia_role_ = ROLE_SYSTEM_SLIDER; break; case WebAccessibility::ROLE_SPLIT_GROUP: - role_ = ROLE_SYSTEM_CLIENT; + ia_role_ = ROLE_SYSTEM_CLIENT; ia2_role_ = IA2_ROLE_SPLIT_PANE; break; case WebAccessibility::ROLE_ANNOTATION: case WebAccessibility::ROLE_STATIC_TEXT: - role_ = ROLE_SYSTEM_TEXT; + ia_role_ = ROLE_SYSTEM_TEXT; break; case WebAccessibility::ROLE_STATUS: - role_ = ROLE_SYSTEM_STATUSBAR; + ia_role_ = ROLE_SYSTEM_STATUSBAR; break; case WebAccessibility::ROLE_TAB: - role_ = ROLE_SYSTEM_PAGETAB; + ia_role_ = ROLE_SYSTEM_PAGETAB; break; case WebAccessibility::ROLE_TABLE: - role_ = ROLE_SYSTEM_TABLE; + ia_role_ = ROLE_SYSTEM_TABLE; break; case WebAccessibility::ROLE_TABLE_HEADER_CONTAINER: - role_ = ROLE_SYSTEM_GROUPING; + ia_role_ = ROLE_SYSTEM_GROUPING; ia2_role_ = IA2_ROLE_SECTION; break; case WebAccessibility::ROLE_TAB_GROUP: case WebAccessibility::ROLE_TAB_LIST: case WebAccessibility::ROLE_TAB_PANEL: - role_ = ROLE_SYSTEM_PAGETABLIST; + ia_role_ = ROLE_SYSTEM_PAGETABLIST; break; case WebAccessibility::ROLE_TEXTAREA: - role_ = ROLE_SYSTEM_TEXT; + ia_role_ = ROLE_SYSTEM_TEXT; ia2_state_ |= IA2_STATE_MULTI_LINE; ia2_state_ |= IA2_STATE_EDITABLE; break; case WebAccessibility::ROLE_TEXT_FIELD: - role_ = ROLE_SYSTEM_TEXT; + ia_role_ = ROLE_SYSTEM_TEXT; ia2_state_ |= IA2_STATE_SINGLE_LINE; ia2_state_ |= IA2_STATE_EDITABLE; break; case WebAccessibility::ROLE_TOOLBAR: - role_ = ROLE_SYSTEM_TOOLBAR; + ia_role_ = ROLE_SYSTEM_TOOLBAR; break; case WebAccessibility::ROLE_TOOLTIP: - role_ = ROLE_SYSTEM_TOOLTIP; + ia_role_ = ROLE_SYSTEM_TOOLTIP; break; case WebAccessibility::ROLE_TREE: - role_ = ROLE_SYSTEM_OUTLINE; + ia_role_ = ROLE_SYSTEM_OUTLINE; break; case WebAccessibility::ROLE_TREE_GRID: - role_ = ROLE_SYSTEM_OUTLINE; + ia_role_ = ROLE_SYSTEM_OUTLINE; break; case WebAccessibility::ROLE_TREE_ITEM: - role_ = ROLE_SYSTEM_OUTLINEITEM; + ia_role_ = ROLE_SYSTEM_OUTLINEITEM; break; case WebAccessibility::ROLE_WINDOW: - role_ = ROLE_SYSTEM_WINDOW; + ia_role_ = ROLE_SYSTEM_WINDOW; break; // TODO(dmazzoni): figure out the proper MSAA role for all of these. @@ -1477,15 +1415,15 @@ void BrowserAccessibilityWin::InitRoleAndState(LONG web_role, case WebAccessibility::ROLE_TIMER: case WebAccessibility::ROLE_VALUE_INDICATOR: default: - role_ = ROLE_SYSTEM_CLIENT; + ia_role_ = ROLE_SYSTEM_CLIENT; break; } // The role should always be set. - DCHECK(!role_name_.empty() || role_); + DCHECK(!role_name_.empty() || ia_role_); // If we didn't explicitly set the IAccessible2 role, make it the same // as the MSAA role. if (!ia2_role_) - ia2_role_ = role_; + ia2_role_ = ia_role_; } diff --git a/chrome/browser/accessibility/browser_accessibility_win.h b/chrome/browser/accessibility/browser_accessibility_win.h index 26522b1..dbd014f 100644 --- a/chrome/browser/accessibility/browser_accessibility_win.h +++ b/chrome/browser/accessibility/browser_accessibility_win.h @@ -60,56 +60,12 @@ class BrowserAccessibilityWin virtual ~BrowserAccessibilityWin(); - // Initialize this object and mark it as active. - void Initialize(BrowserAccessibilityManagerWin* manager, - BrowserAccessibilityWin* parent, - LONG child_id, - LONG index_in_parent, - const webkit_glue::WebAccessibility& src); - - // Add a child of this object. - void AddChild(BrowserAccessibilityWin* child); - - // Mark this object as inactive, and remove references to all children. - // When no other clients hold any references to this object it will be - // deleted, and in the meantime, calls to any methods will return E_FAIL. - void InactivateTree(); - - // Return true if this object is equal to or a descendant of |ancestor|. - bool IsDescendantOf(BrowserAccessibilityWin* ancestor); - - // Returns the parent of this object, or NULL if it's the - // BrowserAccessibilityWin root. - BrowserAccessibilityWin* GetParent(); - - // Returns the number of children of this BrowserAccessibilityWin object. - uint32 GetChildCount(); - - // Return a pointer to the child with the given index. - BrowserAccessibilityWin* GetChild(uint32 child_index); - - // Return the previous sibling of this object, or NULL if it's the first - // child of its parent. - BrowserAccessibilityWin* GetPreviousSibling(); - - // Return the next sibling of this object, or NULL if it's the last child - // of its parent. - BrowserAccessibilityWin* GetNextSibling(); - - // Replace a child BrowserAccessibilityWin object. Used when updating the - // accessibility tree. - void ReplaceChild( - const BrowserAccessibilityWin* old_acc, BrowserAccessibilityWin* new_acc); - - // Accessors - LONG child_id() const { return child_id_; } - int32 renderer_id() const { return renderer_id_; } - LONG index_in_parent() const { return index_in_parent_; } - - // Add one to the reference count and return the same object. Always - // use this method when returning a BrowserAccessibilityWin object as - // an output parameter to a COM interface, never use it otherwise. - BrowserAccessibilityWin* NewReference(); + // + // BrowserAccessibility methods. + // + virtual void Initialize(); + virtual void ReleaseTree(); + virtual void ReleaseReference(); // // IAccessible methods. @@ -489,6 +445,11 @@ class BrowserAccessibilityWin void** object); private: + // Add one to the reference count and return the same object. Always + // use this method when returning a BrowserAccessibilityWin object as + // an output parameter to a COM interface, never use it otherwise. + BrowserAccessibilityWin* NewReference(); + // Many MSAA methods take a var_id parameter indicating that the operation // should be performed on a particular child ID, rather than this object. // This method tries to figure out the target object from |var_id| and @@ -498,8 +459,7 @@ class BrowserAccessibilityWin // Initialize the role and state metadata from the role enum and state // bitmasks defined in webkit/glue/webaccessibility.h. - void InitRoleAndState(LONG web_accessibility_role, - LONG web_accessibility_state); + void InitRoleAndState(); // Return true if this attribute is in the attributes map. bool HasAttribute(WebAccessibility::Attribute attribute); @@ -524,36 +484,6 @@ class BrowserAccessibilityWin // Escape a string like it would be escaped for a URL or HTML form. string16 Escape(string16 str); - // The manager of this tree of accessibility objects; needed for - // global operations like focus tracking. - BrowserAccessibilityManagerWin* manager_; - // The parent of this object, may be NULL if we're the root object. - BrowserAccessibilityWin* parent_; - // The ID of this object; globally unique within the browser process. - LONG child_id_; - // The index of this within its parent object. - LONG index_in_parent_; - // The ID of this object in the renderer process. - int32 renderer_id_; - - // The children of this object. - std::vector<BrowserAccessibilityWin*> children_; - - // Accessibility metadata from the renderer, used to respond to MSAA - // events. - string16 name_; - string16 value_; - std::map<int32, string16> attributes_; - std::vector<std::pair<string16, string16> > html_attributes_; - - int src_role_; - LONG role_; - LONG state_; - string16 role_name_; - LONG ia2_role_; - LONG ia2_state_; - WebKit::WebRect location_; - // COM objects are reference-counted. When we're done with this object // and it's removed from our accessibility tree, a client may still be // holding onto a pointer to this object, so we mark it as inactive @@ -561,6 +491,17 @@ class BrowserAccessibilityWin // failure. bool instance_active_; + // IAccessible role and state. + int32 ia_state_; + int32 ia_role_; + + // IAccessible2 role and state. + int32 ia2_role_; + int32 ia2_state_; + + // Give BrowserAccessibility::Create access to our constructor. + friend class BrowserAccessibility; + DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityWin); }; diff --git a/chrome/browser/accessibility/browser_accessibility_win_unittest.cc b/chrome/browser/accessibility/browser_accessibility_win_unittest.cc index abcb388..549700a 100644 --- a/chrome/browser/accessibility/browser_accessibility_win_unittest.cc +++ b/chrome/browser/accessibility/browser_accessibility_win_unittest.cc @@ -4,34 +4,35 @@ #include "base/scoped_ptr.h" #include "base/scoped_comptr_win.h" -#include "chrome/browser/accessibility/browser_accessibility_manager_win.h" +#include "chrome/browser/accessibility/browser_accessibility_manager.h" #include "chrome/browser/accessibility/browser_accessibility_win.h" #include "chrome/common/render_messages_params.h" #include "testing/gtest/include/gtest/gtest.h" using webkit_glue::WebAccessibility; -// Subclass of BrowserAccessibility that counts the number of instances. -class CountedBrowserAccessibilityWin : public BrowserAccessibilityWin { +// Subclass of BrowserAccessibilityWin that counts the number of instances. +class CountedBrowserAccessibility : public BrowserAccessibilityWin { public: - CountedBrowserAccessibilityWin() { global_obj_count_++; } - virtual ~CountedBrowserAccessibilityWin() { global_obj_count_--; } + CountedBrowserAccessibility() { global_obj_count_++; } + virtual ~CountedBrowserAccessibility() { global_obj_count_--; } static int global_obj_count_; }; -int CountedBrowserAccessibilityWin::global_obj_count_ = 0; +int CountedBrowserAccessibility::global_obj_count_ = 0; -// Factory that creates a CountedBrowserAccessibilityWin. -class CountedBrowserAccessibilityWinFactory - : public BrowserAccessibilityWinFactory { +// Factory that creates a CountedBrowserAccessibility. +class CountedBrowserAccessibilityFactory + : public BrowserAccessibilityFactory { public: - virtual ~CountedBrowserAccessibilityWinFactory() {} - virtual BrowserAccessibilityWin* Create() { - CComObject<CountedBrowserAccessibilityWin>* instance; - HRESULT hr = CComObject<CountedBrowserAccessibilityWin>::CreateInstance( + virtual ~CountedBrowserAccessibilityFactory() {} + virtual BrowserAccessibility* Create() { + CComObject<CountedBrowserAccessibility>* instance; + HRESULT hr = CComObject<CountedBrowserAccessibility>::CreateInstance( &instance); DCHECK(SUCCEEDED(hr)); - return instance->NewReference(); + instance->AddRef(); + return instance; } }; @@ -90,25 +91,30 @@ TEST_F(BrowserAccessibilityTest, TestNoLeaks) { // and a factory for an instance-counting BrowserAccessibility, and ensure // that exactly 3 instances were created. Note that the manager takes // ownership of the factory. - CountedBrowserAccessibilityWin::global_obj_count_ = 0; - // TODO: Use BrowserAccessibilityManager::Create instead of new below. + CountedBrowserAccessibility::global_obj_count_ = 0; BrowserAccessibilityManager* manager = - new BrowserAccessibilityManagerWin( - GetDesktopWindow(), root, NULL, - new CountedBrowserAccessibilityWinFactory()); - ASSERT_EQ(3, CountedBrowserAccessibilityWin::global_obj_count_); + BrowserAccessibilityManager::Create( + GetDesktopWindow(), + root, + NULL, + new CountedBrowserAccessibilityFactory()); + ASSERT_EQ(3, CountedBrowserAccessibility::global_obj_count_); // Delete the manager and test that all 3 instances are deleted. delete manager; - ASSERT_EQ(0, CountedBrowserAccessibilityWin::global_obj_count_); + ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_); // Construct a manager again, and this time use the IAccessible interface // to get new references to two of the three nodes in the tree. - manager = new BrowserAccessibilityManagerWin( - GetDesktopWindow(), root, NULL, - new CountedBrowserAccessibilityWinFactory()); - ASSERT_EQ(3, CountedBrowserAccessibilityWin::global_obj_count_); - IAccessible* root_accessible = manager->GetRootAccessible(); + manager = + BrowserAccessibilityManager::Create( + GetDesktopWindow(), + root, + NULL, + new CountedBrowserAccessibilityFactory()); + ASSERT_EQ(3, CountedBrowserAccessibility::global_obj_count_); + IAccessible* root_accessible = + manager->GetRoot()->toBrowserAccessibilityWin(); IDispatch* root_iaccessible = NULL; IDispatch* child1_iaccessible = NULL; VARIANT var_child; @@ -123,14 +129,14 @@ TEST_F(BrowserAccessibilityTest, TestNoLeaks) { // Now delete the manager, and only one of the three nodes in the tree // should be released. delete manager; - ASSERT_EQ(2, CountedBrowserAccessibilityWin::global_obj_count_); + ASSERT_EQ(2, CountedBrowserAccessibility::global_obj_count_); // Release each of our references and make sure that each one results in // the instance being deleted as its reference count hits zero. root_iaccessible->Release(); - ASSERT_EQ(1, CountedBrowserAccessibilityWin::global_obj_count_); + ASSERT_EQ(1, CountedBrowserAccessibility::global_obj_count_); child1_iaccessible->Release(); - ASSERT_EQ(0, CountedBrowserAccessibilityWin::global_obj_count_); + ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_); } TEST_F(BrowserAccessibilityTest, TestChildrenChange) { @@ -152,16 +158,18 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChange) { // Construct a BrowserAccessibilityManager with this WebAccessibility tree // and a factory for an instance-counting BrowserAccessibility. - CountedBrowserAccessibilityWin::global_obj_count_ = 0; + CountedBrowserAccessibility::global_obj_count_ = 0; BrowserAccessibilityManager* manager = - new BrowserAccessibilityManagerWin( - GetDesktopWindow(), root, NULL, - new CountedBrowserAccessibilityWinFactory()); + BrowserAccessibilityManager::Create( + GetDesktopWindow(), + root, + NULL, + new CountedBrowserAccessibilityFactory()); // Query for the text IAccessible and verify that it returns "old text" as its // value. ScopedComPtr<IDispatch> text_dispatch; - HRESULT hr = manager->GetRootAccessible()->get_accChild( + HRESULT hr = manager->GetRoot()->toBrowserAccessibilityWin()->get_accChild( CreateI4Variant(1), text_dispatch.Receive()); ASSERT_EQ(S_OK, hr); @@ -190,7 +198,7 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChange) { // Query for the text IAccessible and verify that it now returns "new text" // as its value. - hr = manager->GetRootAccessible()->get_accChild( + hr = manager->GetRoot()->toBrowserAccessibilityWin()->get_accChild( CreateI4Variant(1), text_dispatch.Receive()); ASSERT_EQ(S_OK, hr); @@ -208,7 +216,7 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChange) { // Delete the manager and test that all BrowserAccessibility instances are // deleted. delete manager; - ASSERT_EQ(0, CountedBrowserAccessibilityWin::global_obj_count_); + ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_); } TEST_F(BrowserAccessibilityTest, TestChildrenChangeNoLeaks) { @@ -239,12 +247,14 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChangeNoLeaks) { // and a factory for an instance-counting BrowserAccessibility and ensure // that exactly 4 instances were created. Note that the manager takes // ownership of the factory. - CountedBrowserAccessibilityWin::global_obj_count_ = 0; + CountedBrowserAccessibility::global_obj_count_ = 0; BrowserAccessibilityManager* manager = - new BrowserAccessibilityManagerWin( - GetDesktopWindow(), root, NULL, - new CountedBrowserAccessibilityWinFactory()); - ASSERT_EQ(4, CountedBrowserAccessibilityWin::global_obj_count_); + BrowserAccessibilityManager::Create( + GetDesktopWindow(), + root, + NULL, + new CountedBrowserAccessibilityFactory()); + ASSERT_EQ(4, CountedBrowserAccessibility::global_obj_count_); // Notify the BrowserAccessibilityManager that the div node and its children // were removed and ensure that only one BrowserAccessibility instance exists. @@ -257,10 +267,10 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChangeNoLeaks) { std::vector<ViewHostMsg_AccessibilityNotification_Params> notifications; notifications.push_back(param); manager->OnAccessibilityNotifications(notifications); - ASSERT_EQ(1, CountedBrowserAccessibilityWin::global_obj_count_); + ASSERT_EQ(1, CountedBrowserAccessibility::global_obj_count_); // Delete the manager and test that all BrowserAccessibility instances are // deleted. delete manager; - ASSERT_EQ(0, CountedBrowserAccessibilityWin::global_obj_count_); + ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_); } |