diff options
12 files changed, 806 insertions, 921 deletions
diff --git a/chrome/browser/accessibility/browser_accessibility.cc b/chrome/browser/accessibility/browser_accessibility.cc index 38cf5cc..fa87e09 100644 --- a/chrome/browser/accessibility/browser_accessibility.cc +++ b/chrome/browser/accessibility/browser_accessibility.cc @@ -4,102 +4,8 @@ #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 bdf374e..a7d9719 100644 --- a/chrome/browser/accessibility/browser_accessibility.h +++ b/chrome/browser/accessibility/browser_accessibility.h @@ -6,20 +6,7 @@ #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; //////////////////////////////////////////////////////////////////////////////// // @@ -35,104 +22,13 @@ using webkit_glue::WebAccessibility; //////////////////////////////////////////////////////////////////////////////// class BrowserAccessibility { public: - // Creates a platform specific BrowserAccessibility. Ownership passes to the + // Creates the 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 8506e7a..256c62c 100644 --- a/chrome/browser/accessibility/browser_accessibility_manager.cc +++ b/chrome/browser/accessibility/browser_accessibility_manager.cc @@ -4,74 +4,17 @@ #include "chrome/browser/accessibility/browser_accessibility_manager.h" -#include "chrome/browser/accessibility/browser_accessibility.h" +#include "chrome/common/render_messages_params.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::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_; + gfx::NativeWindow parent_window) + : parent_window_(parent_window) { } 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( @@ -111,205 +54,6 @@ void BrowserAccessibilityManager::OnAccessibilityNotifications( } } -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; +gfx::NativeWindow BrowserAccessibilityManager::GetParentWindow() { + return parent_window_; } diff --git a/chrome/browser/accessibility/browser_accessibility_manager.h b/chrome/browser/accessibility/browser_accessibility_manager.h index ff96e56..4fe5f85 100644 --- a/chrome/browser/accessibility/browser_accessibility_manager.h +++ b/chrome/browser/accessibility/browser_accessibility_manager.h @@ -6,20 +6,18 @@ #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" - -class BrowserAccessibility; -#if defined(OS_WIN) -class BrowserAccessibilityManagerWin; -#endif +struct ViewHostMsg_AccessibilityNotification_Params; using webkit_glue::WebAccessibility; @@ -32,143 +30,52 @@ 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::NativeView parent_view, - const WebAccessibility& src, - BrowserAccessibilityDelegate* delegate, - BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory()); + gfx::NativeWindow parent_window, + const webkit_glue::WebAccessibility& src, + BrowserAccessibilityDelegate* delegate); 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 - // 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); + // window got focused. + virtual void GotFocus() = 0; // 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::NativeView GetParentView(); + gfx::NativeWindow GetParentWindow(); #if defined(OS_WIN) - BrowserAccessibilityManagerWin* toBrowserAccessibilityManagerWin(); + virtual IAccessible* GetRootAccessible() = 0; #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: - BrowserAccessibilityManager( - gfx::NativeView parent_view, - const WebAccessibility& src, - BrowserAccessibilityDelegate* delegate, - BrowserAccessibilityFactory* factory); + 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; private: - 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_; + // The parent window. + gfx::NativeWindow parent_window_; 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 9c1e277..2bcd599 100644 --- a/chrome/browser/accessibility/browser_accessibility_manager_win.cc +++ b/chrome/browser/accessibility/browser_accessibility_manager_win.cc @@ -5,75 +5,304 @@ #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::NativeView parent_view, - const WebAccessibility& src, - BrowserAccessibilityDelegate* delegate, - BrowserAccessibilityFactory* factory) { + gfx::NativeWindow parent_window, + const webkit_glue::WebAccessibility& src, + BrowserAccessibilityDelegate* delegate) { return new BrowserAccessibilityManagerWin( - parent_view, - src, - delegate, - factory); + parent_window, src, delegate, new BrowserAccessibilityWinFactory()); } -BrowserAccessibilityManagerWin* -BrowserAccessibilityManager::toBrowserAccessibilityManagerWin() { - return static_cast<BrowserAccessibilityManagerWin*>(this); +// 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(); } +// 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_view, - const WebAccessibility& src, + HWND parent_window, + const webkit_glue::WebAccessibility& src, BrowserAccessibilityDelegate* delegate, - BrowserAccessibilityFactory* factory) - : BrowserAccessibilityManager(parent_view, src, delegate, factory) { + BrowserAccessibilityWinFactory* factory) + : BrowserAccessibilityManager(parent_window), + delegate_(delegate), + factory_(factory), + focus_(NULL) { HRESULT hr = ::CreateStdAccessibleObject( - parent_view, OBJID_WINDOW, IID_IAccessible, + parent_window, 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_; } -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; +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); } - NotifyWinEvent(event_id, GetParentView(), OBJID_CLIENT, node->child_id()); + return instance; } diff --git a/chrome/browser/accessibility/browser_accessibility_manager_win.h b/chrome/browser/accessibility/browser_accessibility_manager_win.h index 9ee396f..d216796 100644 --- a/chrome/browser/accessibility/browser_accessibility_manager_win.h +++ b/chrome/browser/accessibility/browser_accessibility_manager_win.h @@ -6,44 +6,140 @@ #define CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_WIN_H_ #pragma once +#include <atlbase.h> +#include <atlcom.h> #include <oleacc.h> -#include "base/scoped_comptr_win.h" +#include <hash_map> +#include <vector> + #include "chrome/browser/accessibility/browser_accessibility_manager.h" -#include "chrome/common/render_messages_params.h" +#include "base/hash_tables.h" +#include "base/scoped_comptr_win.h" +#include "base/scoped_ptr.h" #include "webkit/glue/webaccessibility.h" class BrowserAccessibilityWin; struct ViewHostMsg_AccessibilityNotification_Params; -using webkit_glue::WebAccessibility; +class BrowserAccessibilityWinFactory { + public: + virtual ~BrowserAccessibilityWinFactory() {} + + // Create an instance of BrowserAccessibilityWin and return a new + // reference to it. + virtual BrowserAccessibilityWin* Create(); +}; // 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(); - // BrowserAccessibilityManager methods - virtual void NotifyAccessibilityEvent( - ViewHostMsg_AccessibilityNotification_Params::NotificationType n, - BrowserAccessibility* node); + // 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); private: - BrowserAccessibilityManagerWin( - HWND parent_window, - const WebAccessibility& src, - BrowserAccessibilityDelegate* delegate, - BrowserAccessibilityFactory* factory); + // 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_; // A default IAccessible instance for the parent window. ScopedComPtr<IAccessible> window_iaccessible_; - // Give BrowserAccessibilityManager::Create access to our constructor. - friend class BrowserAccessibilityManager; + // 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_; DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManagerWin); }; diff --git a/chrome/browser/accessibility/browser_accessibility_win.cc b/chrome/browser/accessibility/browser_accessibility_win.cc index 432eb1a..f3520ee 100644 --- a/chrome/browser/accessibility/browser_accessibility_win.cc +++ b/chrome/browser/accessibility/browser_accessibility_win.cc @@ -12,24 +12,133 @@ using webkit_glue::WebAccessibility; -// static -BrowserAccessibility* BrowserAccessibility::Create() { - CComObject<BrowserAccessibilityWin>* instance; - HRESULT hr = CComObject<BrowserAccessibilityWin>::CreateInstance(&instance); - DCHECK(SUCCEEDED(hr)); - return instance->NewReference(); +BrowserAccessibilityWin::BrowserAccessibilityWin() + : manager_(NULL), + parent_(NULL), + child_id_(-1), + index_in_parent_(-1), + renderer_id_(-1), + instance_active_(false) { } -BrowserAccessibilityWin* BrowserAccessibility::toBrowserAccessibilityWin() { - return static_cast<BrowserAccessibilityWin*>(this); +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; } -BrowserAccessibilityWin::BrowserAccessibilityWin() - : instance_active_(false) { +void BrowserAccessibilityWin::AddChild(BrowserAccessibilityWin* child) { + children_.push_back(child); } -BrowserAccessibilityWin::~BrowserAccessibilityWin() { - ReleaseTree(); +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; +} + +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; +} + +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::NewReference() { + AddRef(); + return this; } // @@ -79,7 +188,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_->GetParentView(); + HWND parent_hwnd = manager_->GetParentWindow(); POINT top_left = {0, 0}; ::ClientToScreen(parent_hwnd, &top_left); @@ -103,7 +212,7 @@ STDMETHODIMP BrowserAccessibilityWin::accNavigate( return E_INVALIDARG; } - BrowserAccessibility* result = NULL; + BrowserAccessibilityWin* result = NULL; switch (nav_dir) { case NAVDIR_DOWN: case NAVDIR_UP: @@ -133,7 +242,7 @@ STDMETHODIMP BrowserAccessibilityWin::accNavigate( } end->vt = VT_DISPATCH; - end->pdispVal = result->toBrowserAccessibilityWin()->NewReference(); + end->pdispVal = result->NewReference(); return S_OK; } @@ -275,12 +384,11 @@ STDMETHODIMP BrowserAccessibilityWin::get_accParent(IDispatch** disp_parent) { if (!disp_parent) return E_INVALIDARG; - IAccessible* parent = parent_->toBrowserAccessibilityWin(); + IAccessible* parent = parent_; if (parent == NULL) { // This happens if we're the root of the tree; // return the IAccessible for the window. - parent = manager_->toBrowserAccessibilityManagerWin()-> - GetParentWindowIAccessible(); + parent = manager_->GetParentWindowIAccessible(); } parent->AddRef(); @@ -305,7 +413,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_accRole( role->bstrVal = SysAllocString(target->role_name_.c_str()); } else { role->vt = VT_I4; - role->lVal = target->ia_role_; + role->lVal = target->role_; } return S_OK; } @@ -323,7 +431,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_accState(VARIANT var_id, return E_INVALIDARG; state->vt = VT_I4; - state->lVal = target->ia_state_; + state->lVal = target->state_; if (manager_->GetFocus(NULL) == this) state->lVal |= STATE_SYSTEM_FOCUSED; @@ -445,7 +553,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_windowHandle(HWND* window_handle) { if (!window_handle) return E_INVALIDARG; - *window_handle = manager_->GetParentView(); + *window_handle = manager_->GetParentWindow(); return S_OK; } @@ -483,7 +591,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_imagePosition( return E_INVALIDARG; if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) { - HWND parent_hwnd = manager_->GetParentView(); + HWND parent_hwnd = manager_->GetParentWindow(); POINT top_left = {0, 0}; ::ClientToScreen(parent_hwnd, &top_left); *x = location_.x + top_left.x; @@ -492,8 +600,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; @@ -525,7 +633,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_nCharacters(LONG* n_characters) { if (!n_characters) return E_INVALIDARG; - if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { + if (src_role_ == WebAccessibility::ROLE_TEXT_FIELD) { *n_characters = value_.length(); } else { *n_characters = name_.length(); @@ -543,7 +651,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_text( return E_INVALIDARG; string16 text_str; - if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { + if (src_role_ == WebAccessibility::ROLE_TEXT_FIELD) { text_str = value_; } else { text_str = name_; @@ -580,7 +688,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) { if (!offset) return E_INVALIDARG; - if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { + if (src_role_ == WebAccessibility::ROLE_TEXT_FIELD) { int sel_start = 0; if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start)) { *offset = sel_start; @@ -601,7 +709,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_nSelections(LONG* n_selections) { if (!n_selections) return E_INVALIDARG; - if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { + if (src_role_ == WebAccessibility::ROLE_TEXT_FIELD) { int sel_start = 0; int sel_end = 0; if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start) && @@ -627,7 +735,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_selection(LONG selection_index, if (!start_offset || !end_offset || selection_index != 0) return E_INVALIDARG; - if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { + if (src_role_ == WebAccessibility::ROLE_TEXT_FIELD) { int sel_start = 0; int sel_end = 0; if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start) && @@ -720,9 +828,9 @@ STDMETHODIMP BrowserAccessibilityWin::get_nodeInfo( *num_children = children_.size(); *unique_id = child_id_; - if (ia_role_ == ROLE_SYSTEM_DOCUMENT) { + if (role_ == ROLE_SYSTEM_DOCUMENT) { *node_type = NODETYPE_DOCUMENT; - } else if (ia_role_ == ROLE_SYSTEM_TEXT && + } else if (role_ == ROLE_SYSTEM_TEXT && ((ia2_state_ & IA2_STATE_EDITABLE) == 0)) { *node_type = NODETYPE_TEXT; } else { @@ -853,7 +961,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_parentNode(ISimpleDOMNode** node) { if (!node) return E_INVALIDARG; - *node = parent_->toBrowserAccessibilityWin()->NewReference(); + *node = parent_->NewReference(); return S_OK; } @@ -865,7 +973,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_firstChild(ISimpleDOMNode** node) { return E_INVALIDARG; if (children_.size()) { - *node = children_[0]->toBrowserAccessibilityWin()->NewReference(); + *node = children_[0]->NewReference(); return S_OK; } else { *node = NULL; @@ -881,8 +989,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_lastChild(ISimpleDOMNode** node) { return E_INVALIDARG; if (children_.size()) { - *node = children_[children_.size() - 1]->toBrowserAccessibilityWin()-> - NewReference(); + *node = children_[children_.size() - 1]->NewReference(); return S_OK; } else { *node = NULL; @@ -899,8 +1006,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_previousSibling( return E_INVALIDARG; if (parent_ && index_in_parent_ > 0) { - *node = parent_->children()[index_in_parent_ - 1]-> - toBrowserAccessibilityWin()->NewReference(); + *node = parent_->children_[index_in_parent_ - 1]->NewReference(); return S_OK; } else { *node = NULL; @@ -917,9 +1023,8 @@ 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]-> - toBrowserAccessibilityWin()->NewReference(); + index_in_parent_ < static_cast<int>(parent_->children_.size()) - 1) { + *node = parent_->children_[index_in_parent_ + 1]->NewReference(); return S_OK; } else { *node = NULL; @@ -937,7 +1042,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_childAt( return E_INVALIDARG; if (child_index < children_.size()) { - *node = children_[child_index]->toBrowserAccessibilityWin()->NewReference(); + *node = children_[child_index]->NewReference(); return S_OK; } else { *node = NULL; @@ -997,17 +1102,17 @@ HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface( REFIID iid, void** object) { if (iid == IID_IAccessibleText) { - if (ia_role_ != ROLE_SYSTEM_LINK && ia_role_ != ROLE_SYSTEM_TEXT) { + if (role_ != ROLE_SYSTEM_LINK && role_ != ROLE_SYSTEM_TEXT) { *object = NULL; return E_NOINTERFACE; } } else if (iid == IID_IAccessibleImage) { - if (ia_role_ != ROLE_SYSTEM_GRAPHIC) { + if (role_ != ROLE_SYSTEM_GRAPHIC) { *object = NULL; return E_NOINTERFACE; } } else if (iid == IID_ISimpleDOMDocument) { - if (ia_role_ != ROLE_SYSTEM_DOCUMENT) { + if (role_ != ROLE_SYSTEM_DOCUMENT) { *object = NULL; return E_NOINTERFACE; } @@ -1021,50 +1126,6 @@ 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) @@ -1075,9 +1136,9 @@ BrowserAccessibilityWin* BrowserAccessibilityWin::GetTargetFromChildID( return this; if (child_id >= 1 && child_id <= static_cast<LONG>(children_.size())) - return children_[child_id - 1]->toBrowserAccessibilityWin(); + return children_[child_id - 1]; - return manager_->GetFromChildID(child_id)->toBrowserAccessibilityWin(); + return manager_->GetFromChildID(child_id); } bool BrowserAccessibilityWin::HasAttribute( @@ -1129,109 +1190,110 @@ string16 BrowserAccessibilityWin::Escape(string16 str) { return EscapeQueryParamValueUTF8(str, false); } -void BrowserAccessibilityWin::InitRoleAndState() { - ia_state_ = 0; +void BrowserAccessibilityWin::InitRoleAndState(LONG web_role, + LONG web_state) { + state_ = 0; ia2_state_ = IA2_STATE_OPAQUE; - 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; + 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; // TODO(ctguil): Support STATE_SYSTEM_EXTSELECTABLE/accSelect. - 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; + 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; ia2_role_ = 0; - switch (role_) { + switch (web_role) { case WebAccessibility::ROLE_ALERT: case WebAccessibility::ROLE_ALERT_DIALOG: - ia_role_ = ROLE_SYSTEM_ALERT; + role_ = ROLE_SYSTEM_ALERT; break; case WebAccessibility::ROLE_APPLICATION: - ia_role_ = ROLE_SYSTEM_APPLICATION; + role_ = ROLE_SYSTEM_APPLICATION; break; case WebAccessibility::ROLE_ARTICLE: - ia_role_ = ROLE_SYSTEM_GROUPING; + role_ = ROLE_SYSTEM_GROUPING; ia2_role_ = IA2_ROLE_SECTION; break; case WebAccessibility::ROLE_BUTTON: - ia_role_ = ROLE_SYSTEM_PUSHBUTTON; + role_ = ROLE_SYSTEM_PUSHBUTTON; break; case WebAccessibility::ROLE_CELL: - ia_role_ = ROLE_SYSTEM_CELL; + role_ = ROLE_SYSTEM_CELL; break; case WebAccessibility::ROLE_CHECKBOX: - ia_role_ = ROLE_SYSTEM_CHECKBUTTON; + role_ = ROLE_SYSTEM_CHECKBUTTON; break; case WebAccessibility::ROLE_COLOR_WELL: - ia_role_ = ROLE_SYSTEM_CLIENT; + role_ = ROLE_SYSTEM_CLIENT; ia2_role_ = IA2_ROLE_COLOR_CHOOSER; break; case WebAccessibility::ROLE_COLUMN: - ia_role_ = ROLE_SYSTEM_COLUMN; + role_ = ROLE_SYSTEM_COLUMN; break; case WebAccessibility::ROLE_COLUMN_HEADER: - ia_role_ = ROLE_SYSTEM_COLUMNHEADER; + role_ = ROLE_SYSTEM_COLUMNHEADER; break; case WebAccessibility::ROLE_COMBO_BOX: - ia_role_ = ROLE_SYSTEM_COMBOBOX; + 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: - ia_role_ = ROLE_SYSTEM_LISTITEM; + role_ = ROLE_SYSTEM_LISTITEM; break; case WebAccessibility::ROLE_DIALOG: - ia_role_ = ROLE_SYSTEM_DIALOG; + role_ = ROLE_SYSTEM_DIALOG; break; case WebAccessibility::ROLE_DOCUMENT: case WebAccessibility::ROLE_WEB_AREA: - ia_role_ = ROLE_SYSTEM_DOCUMENT; - ia_state_|= STATE_SYSTEM_READONLY; - ia_state_|= STATE_SYSTEM_FOCUSABLE; + role_ = ROLE_SYSTEM_DOCUMENT; + state_ |= STATE_SYSTEM_READONLY; + state_ |= STATE_SYSTEM_FOCUSABLE; break; case WebAccessibility::ROLE_EDITABLE_TEXT: - ia_role_ = ROLE_SYSTEM_TEXT; + role_ = ROLE_SYSTEM_TEXT; ia2_state_ |= IA2_STATE_SINGLE_LINE; ia2_state_ |= IA2_STATE_EDITABLE; break; case WebAccessibility::ROLE_GRID: - ia_role_ = ROLE_SYSTEM_TABLE; + role_ = ROLE_SYSTEM_TABLE; break; case WebAccessibility::ROLE_GROUP: GetAttribute(WebAccessibility::ATTR_HTML_TAG, &role_name_); @@ -1244,15 +1306,15 @@ void BrowserAccessibilityWin::InitRoleAndState() { ia2_role_ = IA2_ROLE_HEADING; break; case WebAccessibility::ROLE_IMAGE: - ia_role_ = ROLE_SYSTEM_GRAPHIC; + 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: - ia_role_ = ROLE_SYSTEM_LINK; - ia_state_|= STATE_SYSTEM_LINKED; + role_ = ROLE_SYSTEM_LINK; + state_ |= STATE_SYSTEM_LINKED; break; case WebAccessibility::ROLE_LANDMARK_APPLICATION: case WebAccessibility::ROLE_LANDMARK_BANNER: @@ -1261,136 +1323,136 @@ void BrowserAccessibilityWin::InitRoleAndState() { case WebAccessibility::ROLE_LANDMARK_MAIN: case WebAccessibility::ROLE_LANDMARK_NAVIGATION: case WebAccessibility::ROLE_LANDMARK_SEARCH: - ia_role_ = ROLE_SYSTEM_GROUPING; + role_ = ROLE_SYSTEM_GROUPING; ia2_role_ = IA2_ROLE_SECTION; break; case WebAccessibility::ROLE_LINK: case WebAccessibility::ROLE_WEBCORE_LINK: - ia_role_ = ROLE_SYSTEM_LINK; - ia_state_|= STATE_SYSTEM_LINKED; + role_ = ROLE_SYSTEM_LINK; + state_ |= STATE_SYSTEM_LINKED; break; case WebAccessibility::ROLE_LIST: - ia_role_ = ROLE_SYSTEM_LIST; + role_ = ROLE_SYSTEM_LIST; break; case WebAccessibility::ROLE_LISTBOX: - ia_role_ = ROLE_SYSTEM_LIST; + role_ = ROLE_SYSTEM_LIST; break; case WebAccessibility::ROLE_LISTBOX_OPTION: case WebAccessibility::ROLE_LIST_ITEM: case WebAccessibility::ROLE_LIST_MARKER: - ia_role_ = ROLE_SYSTEM_LISTITEM; + role_ = ROLE_SYSTEM_LISTITEM; break; case WebAccessibility::ROLE_MENU: case WebAccessibility::ROLE_MENU_BUTTON: - ia_role_ = ROLE_SYSTEM_MENUPOPUP; + role_ = ROLE_SYSTEM_MENUPOPUP; break; case WebAccessibility::ROLE_MENU_BAR: - ia_role_ = ROLE_SYSTEM_MENUBAR; + role_ = ROLE_SYSTEM_MENUBAR; break; case WebAccessibility::ROLE_MENU_ITEM: case WebAccessibility::ROLE_MENU_LIST_OPTION: - ia_role_ = ROLE_SYSTEM_MENUITEM; + role_ = ROLE_SYSTEM_MENUITEM; break; case WebAccessibility::ROLE_MENU_LIST_POPUP: - ia_role_ = ROLE_SYSTEM_MENUPOPUP; + role_ = ROLE_SYSTEM_MENUPOPUP; break; case WebAccessibility::ROLE_NOTE: - ia_role_ = ROLE_SYSTEM_GROUPING; + role_ = ROLE_SYSTEM_GROUPING; ia2_role_ = IA2_ROLE_NOTE; break; case WebAccessibility::ROLE_OUTLINE: - ia_role_ = ROLE_SYSTEM_OUTLINE; + role_ = ROLE_SYSTEM_OUTLINE; break; case WebAccessibility::ROLE_POPUP_BUTTON: - ia_role_ = ROLE_SYSTEM_COMBOBOX; + role_ = ROLE_SYSTEM_COMBOBOX; break; case WebAccessibility::ROLE_PROGRESS_INDICATOR: - ia_role_ = ROLE_SYSTEM_PROGRESSBAR; + role_ = ROLE_SYSTEM_PROGRESSBAR; break; case WebAccessibility::ROLE_RADIO_BUTTON: - ia_role_ = ROLE_SYSTEM_RADIOBUTTON; + role_ = ROLE_SYSTEM_RADIOBUTTON; break; case WebAccessibility::ROLE_RADIO_GROUP: - ia_role_ = ROLE_SYSTEM_GROUPING; + role_ = ROLE_SYSTEM_GROUPING; ia2_role_ = IA2_ROLE_SECTION; break; case WebAccessibility::ROLE_REGION: - ia_role_ = ROLE_SYSTEM_GROUPING; + role_ = ROLE_SYSTEM_GROUPING; ia2_role_ = IA2_ROLE_SECTION; break; case WebAccessibility::ROLE_ROW: - ia_role_ = ROLE_SYSTEM_ROW; + role_ = ROLE_SYSTEM_ROW; break; case WebAccessibility::ROLE_ROW_HEADER: - ia_role_ = ROLE_SYSTEM_ROWHEADER; + role_ = ROLE_SYSTEM_ROWHEADER; break; case WebAccessibility::ROLE_RULER: - ia_role_ = ROLE_SYSTEM_CLIENT; + role_ = ROLE_SYSTEM_CLIENT; ia2_role_ = IA2_ROLE_RULER; break; case WebAccessibility::ROLE_SCROLLAREA: - ia_role_ = ROLE_SYSTEM_CLIENT; + role_ = ROLE_SYSTEM_CLIENT; ia2_role_ = IA2_ROLE_SCROLL_PANE; break; case WebAccessibility::ROLE_SCROLLBAR: - ia_role_ = ROLE_SYSTEM_SCROLLBAR; + role_ = ROLE_SYSTEM_SCROLLBAR; break; case WebAccessibility::ROLE_SLIDER: - ia_role_ = ROLE_SYSTEM_SLIDER; + role_ = ROLE_SYSTEM_SLIDER; break; case WebAccessibility::ROLE_SPLIT_GROUP: - ia_role_ = ROLE_SYSTEM_CLIENT; + role_ = ROLE_SYSTEM_CLIENT; ia2_role_ = IA2_ROLE_SPLIT_PANE; break; case WebAccessibility::ROLE_ANNOTATION: case WebAccessibility::ROLE_STATIC_TEXT: - ia_role_ = ROLE_SYSTEM_TEXT; + role_ = ROLE_SYSTEM_TEXT; break; case WebAccessibility::ROLE_STATUS: - ia_role_ = ROLE_SYSTEM_STATUSBAR; + role_ = ROLE_SYSTEM_STATUSBAR; break; case WebAccessibility::ROLE_TAB: - ia_role_ = ROLE_SYSTEM_PAGETAB; + role_ = ROLE_SYSTEM_PAGETAB; break; case WebAccessibility::ROLE_TABLE: - ia_role_ = ROLE_SYSTEM_TABLE; + role_ = ROLE_SYSTEM_TABLE; break; case WebAccessibility::ROLE_TABLE_HEADER_CONTAINER: - ia_role_ = ROLE_SYSTEM_GROUPING; + 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: - ia_role_ = ROLE_SYSTEM_PAGETABLIST; + role_ = ROLE_SYSTEM_PAGETABLIST; break; case WebAccessibility::ROLE_TEXTAREA: - ia_role_ = ROLE_SYSTEM_TEXT; + role_ = ROLE_SYSTEM_TEXT; ia2_state_ |= IA2_STATE_MULTI_LINE; ia2_state_ |= IA2_STATE_EDITABLE; break; case WebAccessibility::ROLE_TEXT_FIELD: - ia_role_ = ROLE_SYSTEM_TEXT; + role_ = ROLE_SYSTEM_TEXT; ia2_state_ |= IA2_STATE_SINGLE_LINE; ia2_state_ |= IA2_STATE_EDITABLE; break; case WebAccessibility::ROLE_TOOLBAR: - ia_role_ = ROLE_SYSTEM_TOOLBAR; + role_ = ROLE_SYSTEM_TOOLBAR; break; case WebAccessibility::ROLE_TOOLTIP: - ia_role_ = ROLE_SYSTEM_TOOLTIP; + role_ = ROLE_SYSTEM_TOOLTIP; break; case WebAccessibility::ROLE_TREE: - ia_role_ = ROLE_SYSTEM_OUTLINE; + role_ = ROLE_SYSTEM_OUTLINE; break; case WebAccessibility::ROLE_TREE_GRID: - ia_role_ = ROLE_SYSTEM_OUTLINE; + role_ = ROLE_SYSTEM_OUTLINE; break; case WebAccessibility::ROLE_TREE_ITEM: - ia_role_ = ROLE_SYSTEM_OUTLINEITEM; + role_ = ROLE_SYSTEM_OUTLINEITEM; break; case WebAccessibility::ROLE_WINDOW: - ia_role_ = ROLE_SYSTEM_WINDOW; + role_ = ROLE_SYSTEM_WINDOW; break; // TODO(dmazzoni): figure out the proper MSAA role for all of these. @@ -1415,15 +1477,15 @@ void BrowserAccessibilityWin::InitRoleAndState() { case WebAccessibility::ROLE_TIMER: case WebAccessibility::ROLE_VALUE_INDICATOR: default: - ia_role_ = ROLE_SYSTEM_CLIENT; + role_ = ROLE_SYSTEM_CLIENT; break; } // The role should always be set. - DCHECK(!role_name_.empty() || ia_role_); + DCHECK(!role_name_.empty() || role_); // If we didn't explicitly set the IAccessible2 role, make it the same // as the MSAA role. if (!ia2_role_) - ia2_role_ = ia_role_; + ia2_role_ = role_; } diff --git a/chrome/browser/accessibility/browser_accessibility_win.h b/chrome/browser/accessibility/browser_accessibility_win.h index dbd014f..26522b1 100644 --- a/chrome/browser/accessibility/browser_accessibility_win.h +++ b/chrome/browser/accessibility/browser_accessibility_win.h @@ -60,12 +60,56 @@ class BrowserAccessibilityWin virtual ~BrowserAccessibilityWin(); - // - // BrowserAccessibility methods. - // - virtual void Initialize(); - virtual void ReleaseTree(); - virtual void ReleaseReference(); + // 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(); // // IAccessible methods. @@ -445,11 +489,6 @@ 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 @@ -459,7 +498,8 @@ class BrowserAccessibilityWin // Initialize the role and state metadata from the role enum and state // bitmasks defined in webkit/glue/webaccessibility.h. - void InitRoleAndState(); + void InitRoleAndState(LONG web_accessibility_role, + LONG web_accessibility_state); // Return true if this attribute is in the attributes map. bool HasAttribute(WebAccessibility::Attribute attribute); @@ -484,6 +524,36 @@ 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 @@ -491,17 +561,6 @@ 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 549700a..abcb388 100644 --- a/chrome/browser/accessibility/browser_accessibility_win_unittest.cc +++ b/chrome/browser/accessibility/browser_accessibility_win_unittest.cc @@ -4,35 +4,34 @@ #include "base/scoped_ptr.h" #include "base/scoped_comptr_win.h" -#include "chrome/browser/accessibility/browser_accessibility_manager.h" +#include "chrome/browser/accessibility/browser_accessibility_manager_win.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 BrowserAccessibilityWin that counts the number of instances. -class CountedBrowserAccessibility : public BrowserAccessibilityWin { +// Subclass of BrowserAccessibility that counts the number of instances. +class CountedBrowserAccessibilityWin : public BrowserAccessibilityWin { public: - CountedBrowserAccessibility() { global_obj_count_++; } - virtual ~CountedBrowserAccessibility() { global_obj_count_--; } + CountedBrowserAccessibilityWin() { global_obj_count_++; } + virtual ~CountedBrowserAccessibilityWin() { global_obj_count_--; } static int global_obj_count_; }; -int CountedBrowserAccessibility::global_obj_count_ = 0; +int CountedBrowserAccessibilityWin::global_obj_count_ = 0; -// Factory that creates a CountedBrowserAccessibility. -class CountedBrowserAccessibilityFactory - : public BrowserAccessibilityFactory { +// Factory that creates a CountedBrowserAccessibilityWin. +class CountedBrowserAccessibilityWinFactory + : public BrowserAccessibilityWinFactory { public: - virtual ~CountedBrowserAccessibilityFactory() {} - virtual BrowserAccessibility* Create() { - CComObject<CountedBrowserAccessibility>* instance; - HRESULT hr = CComObject<CountedBrowserAccessibility>::CreateInstance( + virtual ~CountedBrowserAccessibilityWinFactory() {} + virtual BrowserAccessibilityWin* Create() { + CComObject<CountedBrowserAccessibilityWin>* instance; + HRESULT hr = CComObject<CountedBrowserAccessibilityWin>::CreateInstance( &instance); DCHECK(SUCCEEDED(hr)); - instance->AddRef(); - return instance; + return instance->NewReference(); } }; @@ -91,30 +90,25 @@ 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. - CountedBrowserAccessibility::global_obj_count_ = 0; + CountedBrowserAccessibilityWin::global_obj_count_ = 0; + // TODO: Use BrowserAccessibilityManager::Create instead of new below. BrowserAccessibilityManager* manager = - BrowserAccessibilityManager::Create( - GetDesktopWindow(), - root, - NULL, - new CountedBrowserAccessibilityFactory()); - ASSERT_EQ(3, CountedBrowserAccessibility::global_obj_count_); + new BrowserAccessibilityManagerWin( + GetDesktopWindow(), root, NULL, + new CountedBrowserAccessibilityWinFactory()); + ASSERT_EQ(3, CountedBrowserAccessibilityWin::global_obj_count_); // Delete the manager and test that all 3 instances are deleted. delete manager; - ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_); + ASSERT_EQ(0, CountedBrowserAccessibilityWin::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 = - BrowserAccessibilityManager::Create( - GetDesktopWindow(), - root, - NULL, - new CountedBrowserAccessibilityFactory()); - ASSERT_EQ(3, CountedBrowserAccessibility::global_obj_count_); - IAccessible* root_accessible = - manager->GetRoot()->toBrowserAccessibilityWin(); + manager = new BrowserAccessibilityManagerWin( + GetDesktopWindow(), root, NULL, + new CountedBrowserAccessibilityWinFactory()); + ASSERT_EQ(3, CountedBrowserAccessibilityWin::global_obj_count_); + IAccessible* root_accessible = manager->GetRootAccessible(); IDispatch* root_iaccessible = NULL; IDispatch* child1_iaccessible = NULL; VARIANT var_child; @@ -129,14 +123,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, CountedBrowserAccessibility::global_obj_count_); + ASSERT_EQ(2, CountedBrowserAccessibilityWin::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, CountedBrowserAccessibility::global_obj_count_); + ASSERT_EQ(1, CountedBrowserAccessibilityWin::global_obj_count_); child1_iaccessible->Release(); - ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_); + ASSERT_EQ(0, CountedBrowserAccessibilityWin::global_obj_count_); } TEST_F(BrowserAccessibilityTest, TestChildrenChange) { @@ -158,18 +152,16 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChange) { // Construct a BrowserAccessibilityManager with this WebAccessibility tree // and a factory for an instance-counting BrowserAccessibility. - CountedBrowserAccessibility::global_obj_count_ = 0; + CountedBrowserAccessibilityWin::global_obj_count_ = 0; BrowserAccessibilityManager* manager = - BrowserAccessibilityManager::Create( - GetDesktopWindow(), - root, - NULL, - new CountedBrowserAccessibilityFactory()); + new BrowserAccessibilityManagerWin( + GetDesktopWindow(), root, NULL, + new CountedBrowserAccessibilityWinFactory()); // Query for the text IAccessible and verify that it returns "old text" as its // value. ScopedComPtr<IDispatch> text_dispatch; - HRESULT hr = manager->GetRoot()->toBrowserAccessibilityWin()->get_accChild( + HRESULT hr = manager->GetRootAccessible()->get_accChild( CreateI4Variant(1), text_dispatch.Receive()); ASSERT_EQ(S_OK, hr); @@ -198,7 +190,7 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChange) { // Query for the text IAccessible and verify that it now returns "new text" // as its value. - hr = manager->GetRoot()->toBrowserAccessibilityWin()->get_accChild( + hr = manager->GetRootAccessible()->get_accChild( CreateI4Variant(1), text_dispatch.Receive()); ASSERT_EQ(S_OK, hr); @@ -216,7 +208,7 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChange) { // Delete the manager and test that all BrowserAccessibility instances are // deleted. delete manager; - ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_); + ASSERT_EQ(0, CountedBrowserAccessibilityWin::global_obj_count_); } TEST_F(BrowserAccessibilityTest, TestChildrenChangeNoLeaks) { @@ -247,14 +239,12 @@ 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. - CountedBrowserAccessibility::global_obj_count_ = 0; + CountedBrowserAccessibilityWin::global_obj_count_ = 0; BrowserAccessibilityManager* manager = - BrowserAccessibilityManager::Create( - GetDesktopWindow(), - root, - NULL, - new CountedBrowserAccessibilityFactory()); - ASSERT_EQ(4, CountedBrowserAccessibility::global_obj_count_); + new BrowserAccessibilityManagerWin( + GetDesktopWindow(), root, NULL, + new CountedBrowserAccessibilityWinFactory()); + ASSERT_EQ(4, CountedBrowserAccessibilityWin::global_obj_count_); // Notify the BrowserAccessibilityManager that the div node and its children // were removed and ensure that only one BrowserAccessibility instance exists. @@ -267,10 +257,10 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChangeNoLeaks) { std::vector<ViewHostMsg_AccessibilityNotification_Params> notifications; notifications.push_back(param); manager->OnAccessibilityNotifications(notifications); - ASSERT_EQ(1, CountedBrowserAccessibility::global_obj_count_); + ASSERT_EQ(1, CountedBrowserAccessibilityWin::global_obj_count_); // Delete the manager and test that all BrowserAccessibility instances are // deleted. delete manager; - ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_); + ASSERT_EQ(0, CountedBrowserAccessibilityWin::global_obj_count_); } diff --git a/chrome/browser/renderer_host/render_widget_host_view.h b/chrome/browser/renderer_host/render_widget_host_view.h index fc57cb8..4258a86 100644 --- a/chrome/browser/renderer_host/render_widget_host_view.h +++ b/chrome/browser/renderer_host/render_widget_host_view.h @@ -14,7 +14,6 @@ #include <vector> #include "app/surface/transport_dib.h" -#include "chrome/browser/accessibility/browser_accessibility_manager.h" #include "gfx/native_widget_types.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/WebKit/WebKit/chromium/public/WebPopupType.h" @@ -48,7 +47,7 @@ struct WebPluginGeometry; // the surrounding environment and passing them to the RenderWidgetHost, and // for actually displaying the content of the RenderWidgetHost when it // changes. -class RenderWidgetHostView : public BrowserAccessibilityDelegate { +class RenderWidgetHostView { public: virtual ~RenderWidgetHostView() {} @@ -257,10 +256,6 @@ class RenderWidgetHostView : public BrowserAccessibilityDelegate { const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params) { } - // Implementation of BrowserAccessibilityDelegate: - virtual void SetAccessibilityFocus(int acc_obj_id) { } - virtual void AccessibilityDoDefaultAction(int acc_obj_id) { } - protected: // Interface class only, do not construct. RenderWidgetHostView() : popup_type_(WebKit::WebPopupTypeNone) {} diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.cc b/chrome/browser/renderer_host/render_widget_host_view_win.cc index e22033f..3c82568 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_win.cc +++ b/chrome/browser/renderer_host/render_widget_host_view_win.cc @@ -14,7 +14,7 @@ #include "base/scoped_comptr_win.h" #include "base/thread.h" #include "base/win_util.h" -#include "chrome/browser/accessibility/browser_accessibility_win.h" +#include "chrome/browser/accessibility/browser_accessibility.h" #include "chrome/browser/accessibility/browser_accessibility_manager.h" #include "chrome/browser/accessibility/browser_accessibility_state.h" #include "chrome/browser/browser_process.h" @@ -1576,7 +1576,7 @@ LRESULT RenderWidgetHostViewWin::OnGetObject(UINT message, WPARAM wparam, } ScopedComPtr<IAccessible> root( - browser_accessibility_manager_->GetRoot()->toBrowserAccessibilityWin()); + browser_accessibility_manager_->GetRootAccessible()); if (root.get()) return LresultFromObject(IID_IAccessible, wparam, root.Detach()); diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.h b/chrome/browser/renderer_host/render_widget_host_view_win.h index 95451c5..9fbaf11 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_win.h +++ b/chrome/browser/renderer_host/render_widget_host_view_win.h @@ -62,7 +62,8 @@ class RenderWidgetHostViewWin CWindow, RenderWidgetHostHWNDTraits>, public RenderWidgetHostView, - public NotificationObserver { + public NotificationObserver, + public BrowserAccessibilityDelegate { public: // The view will associate itself with the given widget. explicit RenderWidgetHostViewWin(RenderWidgetHost* widget); |