From d96f384cf58a669efd1637416ed96633a71f4fa5 Mon Sep 17 00:00:00 2001 From: "dmazzoni@chromium.org" Date: Mon, 21 Apr 2014 18:07:29 +0000 Subject: [PATCH] Make BrowserAccessibilityManager use AXTree (re-land). This is the final step of migrating content/*/accessibility to make full use of the new infrastructure in ui/accessibility. Previously, BrowserAccessibilityManager owned the tree of BrowserAccessibility objects and handled making changes to the tree in response to messages from the renderer. Now, AXTree handles the updates from the renderer and notifies BrowserAccessibilityManager (via AXTreeDelegate) when it should create or destroy BrowserAccessibility objects, and when it should notify a BrowserAccessibility object that it's been modified. This makes the serialization/unserialization logic fully tested now, and greatly clarifies the semantics of when in the update cycle various notifications are called (e.g., PreInitialize and PostInitialize are now OnDataChanged and OnUpdateFinished). BUG=316726 NOTRY=true Review URL: https://codereview.chromium.org/234723003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@265021 0039d316-1c4b-4281-b951-d872f2087c98 --- .../browser/accessibility/browser_accessibility.cc | 237 ++++++++------ .../browser/accessibility/browser_accessibility.h | 110 +++---- .../accessibility/browser_accessibility_android.cc | 4 +- .../accessibility/browser_accessibility_android.h | 2 +- .../accessibility/browser_accessibility_cocoa.mm | 18 +- .../accessibility/browser_accessibility_mac.h | 9 +- .../accessibility/browser_accessibility_mac.mm | 20 +- .../browser_accessibility_mac_unittest.mm | 6 +- .../accessibility/browser_accessibility_manager.cc | 350 +++++++-------------- .../accessibility/browser_accessibility_manager.h | 73 +++-- .../browser_accessibility_manager_android.cc | 45 +-- .../browser_accessibility_manager_android.h | 7 +- .../browser_accessibility_manager_mac.h | 4 +- .../browser_accessibility_manager_mac.mm | 15 +- .../browser_accessibility_manager_unittest.cc | 62 ++-- .../browser_accessibility_manager_win.cc | 56 ++-- .../browser_accessibility_manager_win.h | 16 +- .../accessibility/browser_accessibility_win.cc | 48 ++- .../accessibility/browser_accessibility_win.h | 11 +- .../browser_accessibility_win_unittest.cc | 37 ++- .../renderer_host/render_widget_host_view_mac.mm | 2 +- ui/accessibility/ax_node.cc | 13 + ui/accessibility/ax_node.h | 15 +- ui/accessibility/ax_tree.cc | 40 +-- ui/accessibility/ax_tree.h | 37 ++- ui/accessibility/ax_tree_unittest.cc | 17 + 26 files changed, 598 insertions(+), 656 deletions(-) diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc index 5e1f94e153fe..fe71fef965aa 100644 --- a/content/browser/accessibility/browser_accessibility.cc +++ b/content/browser/accessibility/browser_accessibility.cc @@ -26,17 +26,23 @@ BrowserAccessibility* BrowserAccessibility::Create() { BrowserAccessibility::BrowserAccessibility() : manager_(NULL), - deprecated_parent_(NULL), - deprecated_index_in_parent_(0), - instance_active_(false) { - data_.id = 0; - data_.role = ui::AX_ROLE_UNKNOWN; - data_.state = 0; + node_(NULL) { } BrowserAccessibility::~BrowserAccessibility() { } +void BrowserAccessibility::Init(BrowserAccessibilityManager* manager, + ui::AXNode* node) { + manager_ = manager; + node_ = node; +} + +void BrowserAccessibility::OnDataChanged() { + GetStringAttribute(ui::AX_ATTR_NAME, &name_); + GetStringAttribute(ui::AX_ATTR_VALUE, &value_); +} + bool BrowserAccessibility::PlatformIsLeaf() const { if (InternalChildCount() == 0) return true; @@ -60,56 +66,10 @@ uint32 BrowserAccessibility::PlatformChildCount() const { return PlatformIsLeaf() ? 0 : InternalChildCount(); } -void BrowserAccessibility::DetachTree( - std::vector* nodes) { - nodes->push_back(this); - for (size_t i = 0; i < InternalChildCount(); ++i) - InternalGetChild(i)->DetachTree(nodes); - deprecated_children_.clear(); - deprecated_parent_ = NULL; -} - -void BrowserAccessibility::InitializeTreeStructure( - BrowserAccessibilityManager* manager, - BrowserAccessibility* parent, - int32 id, - int32 index_in_parent) { - manager_ = manager; - deprecated_parent_ = parent; - data_.id = id; - deprecated_index_in_parent_ = index_in_parent; -} - -void BrowserAccessibility::InitializeData(const ui::AXNodeData& src) { - DCHECK_EQ(data_.id, src.id); - data_ = src; - instance_active_ = true; - - GetStringAttribute(ui::AX_ATTR_NAME, &name_); - GetStringAttribute(ui::AX_ATTR_VALUE, &value_); - - PreInitialize(); -} - bool BrowserAccessibility::IsNative() const { return false; } -void BrowserAccessibility::SwapChildren( - std::vector& children) { - children.swap(deprecated_children_); -} - -void BrowserAccessibility::UpdateParent(BrowserAccessibility* parent, - int index_in_parent) { - deprecated_parent_ = parent; - deprecated_index_in_parent_ = index_in_parent; -} - -void BrowserAccessibility::SetLocation(const gfx::Rect& new_location) { - data_.location = new_location; -} - bool BrowserAccessibility::IsDescendantOf( BrowserAccessibility* ancestor) { if (this == ancestor) { @@ -145,6 +105,59 @@ BrowserAccessibility* BrowserAccessibility::GetNextSibling() { return NULL; } +uint32 BrowserAccessibility::InternalChildCount() const { + if (!node_ || !manager_) + return 0; + return static_cast(node_->child_count()); +} + +BrowserAccessibility* BrowserAccessibility::InternalGetChild( + uint32 child_index) const { + if (!node_ || !manager_) + return NULL; + return manager_->GetFromAXNode(node_->children()[child_index]); +} + +BrowserAccessibility* BrowserAccessibility::GetParent() const { + if (!node_ || !manager_) + return NULL; + ui::AXNode* parent = node_->parent(); + return parent ? manager_->GetFromAXNode(parent) : NULL; +} + +int32 BrowserAccessibility::GetIndexInParent() const { + return node_ ? node_->index_in_parent() : -1; +} + +int32 BrowserAccessibility::GetId() const { + return node_ ? node_->id() : -1; +} + +const ui::AXNodeData& BrowserAccessibility::GetData() const { + CR_DEFINE_STATIC_LOCAL(ui::AXNodeData, empty_data, ()); + if (node_) + return node_->data(); + else + return empty_data; +} + +gfx::Rect BrowserAccessibility::GetLocation() const { + return GetData().location; +} + +int32 BrowserAccessibility::GetRole() const { + return GetData().role; +} + +int32 BrowserAccessibility::GetState() const { + return GetData().state; +} + +const std::vector >& +BrowserAccessibility::GetHtmlAttributes() const { + return GetData().html_attributes; +} + gfx::Rect BrowserAccessibility::GetLocalBoundsRect() const { gfx::Rect bounds = GetLocation(); @@ -350,19 +363,14 @@ BrowserAccessibility* BrowserAccessibility::BrowserAccessibilityForPoint( } void BrowserAccessibility::Destroy() { - for (uint32 i = 0; i < InternalChildCount(); i++) - InternalGetChild(i)->Destroy(); - deprecated_children_.clear(); - // Allow the object to fire a TextRemoved notification. name_.clear(); value_.clear(); - PostInitialize(); manager_->NotifyAccessibilityEvent(ui::AX_EVENT_HIDE, this); + node_ = NULL; + manager_ = NULL; - instance_active_ = false; - manager_->RemoveNode(this); NativeReleaseReference(); } @@ -372,8 +380,9 @@ void BrowserAccessibility::NativeReleaseReference() { bool BrowserAccessibility::HasBoolAttribute( ui::AXBoolAttribute attribute) const { - for (size_t i = 0; i < data_.bool_attributes.size(); ++i) { - if (data_.bool_attributes[i].first == attribute) + const ui::AXNodeData& data = GetData(); + for (size_t i = 0; i < data.bool_attributes.size(); ++i) { + if (data.bool_attributes[i].first == attribute) return true; } @@ -383,9 +392,10 @@ bool BrowserAccessibility::HasBoolAttribute( bool BrowserAccessibility::GetBoolAttribute( ui::AXBoolAttribute attribute) const { - for (size_t i = 0; i < data_.bool_attributes.size(); ++i) { - if (data_.bool_attributes[i].first == attribute) - return data_.bool_attributes[i].second; + const ui::AXNodeData& data = GetData(); + for (size_t i = 0; i < data.bool_attributes.size(); ++i) { + if (data.bool_attributes[i].first == attribute) + return data.bool_attributes[i].second; } return false; @@ -393,9 +403,10 @@ bool BrowserAccessibility::GetBoolAttribute( bool BrowserAccessibility::GetBoolAttribute( ui::AXBoolAttribute attribute, bool* value) const { - for (size_t i = 0; i < data_.bool_attributes.size(); ++i) { - if (data_.bool_attributes[i].first == attribute) { - *value = data_.bool_attributes[i].second; + const ui::AXNodeData& data = GetData(); + for (size_t i = 0; i < data.bool_attributes.size(); ++i) { + if (data.bool_attributes[i].first == attribute) { + *value = data.bool_attributes[i].second; return true; } } @@ -405,8 +416,9 @@ bool BrowserAccessibility::GetBoolAttribute( bool BrowserAccessibility::HasFloatAttribute( ui::AXFloatAttribute attribute) const { - for (size_t i = 0; i < data_.float_attributes.size(); ++i) { - if (data_.float_attributes[i].first == attribute) + const ui::AXNodeData& data = GetData(); + for (size_t i = 0; i < data.float_attributes.size(); ++i) { + if (data.float_attributes[i].first == attribute) return true; } @@ -415,9 +427,10 @@ bool BrowserAccessibility::HasFloatAttribute( float BrowserAccessibility::GetFloatAttribute( ui::AXFloatAttribute attribute) const { - for (size_t i = 0; i < data_.float_attributes.size(); ++i) { - if (data_.float_attributes[i].first == attribute) - return data_.float_attributes[i].second; + const ui::AXNodeData& data = GetData(); + for (size_t i = 0; i < data.float_attributes.size(); ++i) { + if (data.float_attributes[i].first == attribute) + return data.float_attributes[i].second; } return 0.0; @@ -425,9 +438,10 @@ float BrowserAccessibility::GetFloatAttribute( bool BrowserAccessibility::GetFloatAttribute( ui::AXFloatAttribute attribute, float* value) const { - for (size_t i = 0; i < data_.float_attributes.size(); ++i) { - if (data_.float_attributes[i].first == attribute) { - *value = data_.float_attributes[i].second; + const ui::AXNodeData& data = GetData(); + for (size_t i = 0; i < data.float_attributes.size(); ++i) { + if (data.float_attributes[i].first == attribute) { + *value = data.float_attributes[i].second; return true; } } @@ -437,8 +451,9 @@ bool BrowserAccessibility::GetFloatAttribute( bool BrowserAccessibility::HasIntAttribute( ui::AXIntAttribute attribute) const { - for (size_t i = 0; i < data_.int_attributes.size(); ++i) { - if (data_.int_attributes[i].first == attribute) + const ui::AXNodeData& data = GetData(); + for (size_t i = 0; i < data.int_attributes.size(); ++i) { + if (data.int_attributes[i].first == attribute) return true; } @@ -446,9 +461,10 @@ bool BrowserAccessibility::HasIntAttribute( } int BrowserAccessibility::GetIntAttribute(ui::AXIntAttribute attribute) const { - for (size_t i = 0; i < data_.int_attributes.size(); ++i) { - if (data_.int_attributes[i].first == attribute) - return data_.int_attributes[i].second; + const ui::AXNodeData& data = GetData(); + for (size_t i = 0; i < data.int_attributes.size(); ++i) { + if (data.int_attributes[i].first == attribute) + return data.int_attributes[i].second; } return 0; @@ -456,9 +472,10 @@ int BrowserAccessibility::GetIntAttribute(ui::AXIntAttribute attribute) const { bool BrowserAccessibility::GetIntAttribute( ui::AXIntAttribute attribute, int* value) const { - for (size_t i = 0; i < data_.int_attributes.size(); ++i) { - if (data_.int_attributes[i].first == attribute) { - *value = data_.int_attributes[i].second; + const ui::AXNodeData& data = GetData(); + for (size_t i = 0; i < data.int_attributes.size(); ++i) { + if (data.int_attributes[i].first == attribute) { + *value = data.int_attributes[i].second; return true; } } @@ -468,8 +485,9 @@ bool BrowserAccessibility::GetIntAttribute( bool BrowserAccessibility::HasStringAttribute( ui::AXStringAttribute attribute) const { - for (size_t i = 0; i < data_.string_attributes.size(); ++i) { - if (data_.string_attributes[i].first == attribute) + const ui::AXNodeData& data = GetData(); + for (size_t i = 0; i < data.string_attributes.size(); ++i) { + if (data.string_attributes[i].first == attribute) return true; } @@ -478,10 +496,11 @@ bool BrowserAccessibility::HasStringAttribute( const std::string& BrowserAccessibility::GetStringAttribute( ui::AXStringAttribute attribute) const { + const ui::AXNodeData& data = GetData(); CR_DEFINE_STATIC_LOCAL(std::string, empty_string, ()); - for (size_t i = 0; i < data_.string_attributes.size(); ++i) { - if (data_.string_attributes[i].first == attribute) - return data_.string_attributes[i].second; + for (size_t i = 0; i < data.string_attributes.size(); ++i) { + if (data.string_attributes[i].first == attribute) + return data.string_attributes[i].second; } return empty_string; @@ -489,9 +508,10 @@ const std::string& BrowserAccessibility::GetStringAttribute( bool BrowserAccessibility::GetStringAttribute( ui::AXStringAttribute attribute, std::string* value) const { - for (size_t i = 0; i < data_.string_attributes.size(); ++i) { - if (data_.string_attributes[i].first == attribute) { - *value = data_.string_attributes[i].second; + const ui::AXNodeData& data = GetData(); + for (size_t i = 0; i < data.string_attributes.size(); ++i) { + if (data.string_attributes[i].first == attribute) { + *value = data.string_attributes[i].second; return true; } } @@ -519,20 +539,27 @@ bool BrowserAccessibility::GetString16Attribute( void BrowserAccessibility::SetStringAttribute( ui::AXStringAttribute attribute, const std::string& value) { - for (size_t i = 0; i < data_.string_attributes.size(); ++i) { - if (data_.string_attributes[i].first == attribute) { - data_.string_attributes[i].second = value; + if (!node_) + return; + ui::AXNodeData data = GetData(); + for (size_t i = 0; i < data.string_attributes.size(); ++i) { + if (data.string_attributes[i].first == attribute) { + data.string_attributes[i].second = value; + node_->SetData(data); return; } } - if (!value.empty()) - data_.string_attributes.push_back(std::make_pair(attribute, value)); + if (!value.empty()) { + data.string_attributes.push_back(std::make_pair(attribute, value)); + node_->SetData(data); + } } bool BrowserAccessibility::HasIntListAttribute( ui::AXIntListAttribute attribute) const { - for (size_t i = 0; i < data_.intlist_attributes.size(); ++i) { - if (data_.intlist_attributes[i].first == attribute) + const ui::AXNodeData& data = GetData(); + for (size_t i = 0; i < data.intlist_attributes.size(); ++i) { + if (data.intlist_attributes[i].first == attribute) return true; } @@ -541,10 +568,11 @@ bool BrowserAccessibility::HasIntListAttribute( const std::vector& BrowserAccessibility::GetIntListAttribute( ui::AXIntListAttribute attribute) const { + const ui::AXNodeData& data = GetData(); CR_DEFINE_STATIC_LOCAL(std::vector, empty_vector, ()); - for (size_t i = 0; i < data_.intlist_attributes.size(); ++i) { - if (data_.intlist_attributes[i].first == attribute) - return data_.intlist_attributes[i].second; + for (size_t i = 0; i < data.intlist_attributes.size(); ++i) { + if (data.intlist_attributes[i].first == attribute) + return data.intlist_attributes[i].second; } return empty_vector; @@ -553,9 +581,10 @@ const std::vector& BrowserAccessibility::GetIntListAttribute( bool BrowserAccessibility::GetIntListAttribute( ui::AXIntListAttribute attribute, std::vector* value) const { - for (size_t i = 0; i < data_.intlist_attributes.size(); ++i) { - if (data_.intlist_attributes[i].first == attribute) { - *value = data_.intlist_attributes[i].second; + const ui::AXNodeData& data = GetData(); + for (size_t i = 0; i < data.intlist_attributes.size(); ++i) { + if (data.intlist_attributes[i].first == attribute) { + *value = data.intlist_attributes[i].second; return true; } } diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h index 5ea37485166e..17f70caf675f 100644 --- a/content/browser/accessibility/browser_accessibility.h +++ b/content/browser/accessibility/browser_accessibility.h @@ -14,6 +14,7 @@ #include "build/build_config.h" #include "content/common/content_export.h" #include "third_party/WebKit/public/web/WebAXEnums.h" +#include "ui/accessibility/ax_node.h" #include "ui/accessibility/ax_node_data.h" #if defined(OS_MACOSX) && __OBJC__ @@ -46,37 +47,25 @@ class CONTENT_EXPORT BrowserAccessibility { virtual ~BrowserAccessibility(); - // Detach all descendants of this subtree and push all of the node pointers, - // including this node, onto the end of |nodes|. - virtual void DetachTree(std::vector* nodes); + // Called only once, immediately after construction. The constructor doesn't + // take any arguments because in the Windows subclass we use a special + // function to construct a COM object. + virtual void Init(BrowserAccessibilityManager* manager, ui::AXNode* node); - // 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. - // Child dependent initialization can be done here. - virtual void PostInitialize() {} + // Called after the object is first initialized and again every time + // its data changes. + virtual void OnDataChanged(); + + // Called after an atomic update to the tree finished and this object + // was created or changed in this update. + virtual void OnUpdateFinished() {} // Returns true if this is a native platform-specific object, vs a // cross-platform generic object. virtual bool IsNative() const; - // Initialize the tree structure of this object. - void InitializeTreeStructure( - BrowserAccessibilityManager* manager, - BrowserAccessibility* parent, - int32 id, - int32 index_in_parent); - - // Initialize this object's data. - void InitializeData(const ui::AXNodeData& src); - - virtual void SwapChildren(std::vector& children); - - // Update the parent and index in parent if this node has been moved. - void UpdateParent(BrowserAccessibility* parent, int index_in_parent); - - // Update this node's location, leaving everything else the same. - virtual void SetLocation(const gfx::Rect& new_location); + // Called when the location changed. + virtual void OnLocationChanged() const {} // Return true if this object is equal to or a descendant of |ancestor|. bool IsDescendantOf(BrowserAccessibility* ancestor); @@ -126,14 +115,14 @@ class CONTENT_EXPORT BrowserAccessibility { BrowserAccessibility* BrowserAccessibilityForPoint(const gfx::Point& point); // Marks this object for deletion, releases our reference to it, and - // recursively calls Destroy() on its children. May not delete - // immediately due to reference counting. + // nulls out the pointer to the underlying AXNode. May not delete + // the object immediately due to reference counting. // // Reference counting is used on some platforms because the // operating system may hold onto a reference to a BrowserAccessibility // object even after we're through with it. When a BrowserAccessibility // has had Destroy() called but its reference count is not yet zero, - // queries on this object return failure + // instance_active() returns false and queries on this object return failure. virtual void Destroy(); // Subclasses should override this to support platform reference counting. @@ -147,36 +136,31 @@ class CONTENT_EXPORT BrowserAccessibility { // BrowserAccessibilityManager* manager() const { return manager_; } - bool instance_active() const { return instance_active_; } + bool instance_active() const { return node_ != NULL; } + ui::AXNode* node() const { return node_; } const std::string& name() const { return name_; } const std::string& value() const { return value_; } void set_name(const std::string& name) { name_ = name; } void set_value(const std::string& value) { value_ = value; } - std::vector& deprecated_children() { - return deprecated_children_; - } - // These access the internal accessibility tree, which doesn't necessarily // reflect the accessibility tree that should be exposed on each platform. // Use PlatformChildCount and PlatformGetChild to implement platform // accessibility APIs. - uint32 InternalChildCount() const { return deprecated_children_.size(); } - BrowserAccessibility* InternalGetChild(uint32 child_index) const { - return deprecated_children_[child_index]; - } - - BrowserAccessibility* GetParent() const { return deprecated_parent_; } - int32 GetIndexInParent() const { return deprecated_index_in_parent_; } - - int32 GetId() const { return data_.id; } - gfx::Rect GetLocation() const { return data_.location; } - int32 GetRole() const { return data_.role; } - int32 GetState() const { return data_.state; } - const std::vector >& GetHtmlAttributes() - const { - return data_.html_attributes; - } + uint32 InternalChildCount() const; + BrowserAccessibility* InternalGetChild(uint32 child_index) const; + + BrowserAccessibility* GetParent() const; + int32 GetIndexInParent() const; + + int32 GetId() const; + const ui::AXNodeData& GetData() const; + gfx::Rect GetLocation() const; + int32 GetRole() const; + int32 GetState() const; + + typedef std::vector > HtmlAttributes; + const HtmlAttributes& GetHtmlAttributes() const; #if defined(OS_MACOSX) && __OBJC__ BrowserAccessibilityCocoa* ToBrowserAccessibilityCocoa(); @@ -262,43 +246,21 @@ class CONTENT_EXPORT BrowserAccessibility { std::string GetTextRecursive() const; protected: - // 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. - // Perform child independent initialization in this method. - virtual void PreInitialize() {} - BrowserAccessibility(); - // The manager of this tree of accessibility objects; needed for - // global operations like focus tracking. + // The manager of this tree of accessibility objects. BrowserAccessibilityManager* manager_; - // The parent of this object, may be NULL if we're the root object. - BrowserAccessibility* deprecated_parent_; + // The underlying node. + ui::AXNode* node_; private: // Return the sum of the lengths of all static text descendants, // including this object if it's static text. int GetStaticTextLenRecursive() const; - // The index of this within its parent object. - int32 deprecated_index_in_parent_; - - // The children of this object. - std::vector deprecated_children_; - - // Accessibility metadata from the renderer std::string name_; std::string value_; - ui::AXNodeData data_; - - // BrowserAccessibility objects are reference-counted on some platforms. - // 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 so that calls to any of this object's methods - // immediately return failure. - bool instance_active_; private: DISALLOW_COPY_AND_ASSIGN(BrowserAccessibility); diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc index 725896f27c0f..cec0a664cdab 100644 --- a/content/browser/accessibility/browser_accessibility_android.cc +++ b/content/browser/accessibility/browser_accessibility_android.cc @@ -585,8 +585,8 @@ bool BrowserAccessibilityAndroid::IsIframe() const { return html_tag == base::ASCIIToUTF16("iframe"); } -void BrowserAccessibilityAndroid::PostInitialize() { - BrowserAccessibility::PostInitialize(); +void BrowserAccessibilityAndroid::OnDataChanged() { + BrowserAccessibility::OnDataChanged(); if (IsEditableText()) { if (base::UTF8ToUTF16(value()) != new_value_) { diff --git a/content/browser/accessibility/browser_accessibility_android.h b/content/browser/accessibility/browser_accessibility_android.h index a01b35ecdf8d..d0eb478ad103 100644 --- a/content/browser/accessibility/browser_accessibility_android.h +++ b/content/browser/accessibility/browser_accessibility_android.h @@ -13,7 +13,7 @@ namespace content { class BrowserAccessibilityAndroid : public BrowserAccessibility { public: // Overrides from BrowserAccessibility. - virtual void PostInitialize() OVERRIDE; + virtual void OnDataChanged() OVERRIDE; virtual bool IsNative() const OVERRIDE; virtual bool PlatformIsLeaf() const OVERRIDE; diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm index f16db1a03f62..3b9cb92993e1 100644 --- a/content/browser/accessibility/browser_accessibility_cocoa.mm +++ b/content/browser/accessibility/browser_accessibility_cocoa.mm @@ -373,7 +373,7 @@ NSDictionary* attributeToMethodNameMap = nil; for (uint32 i = 0; i < indirectChildIds.size(); ++i) { int32 child_id = indirectChildIds[i]; BrowserAccessibility* child = - browserAccessibility_->manager()->GetFromRendererID(child_id); + browserAccessibility_->manager()->GetFromID(child_id); // This only became necessary as a result of crbug.com/93095. It should be // a DCHECK in the future. @@ -409,7 +409,7 @@ NSDictionary* attributeToMethodNameMap = nil; for (size_t i = 0; i < uniqueCellIds.size(); ++i) { int id = uniqueCellIds[i]; BrowserAccessibility* cell = - browserAccessibility_->manager()->GetFromRendererID(id); + browserAccessibility_->manager()->GetFromID(id); if (cell && cell->GetRole() == ui::AX_ROLE_COLUMN_HEADER) [ret addObject:cell->ToBrowserAccessibilityCocoa()]; } @@ -537,7 +537,7 @@ NSDictionary* attributeToMethodNameMap = nil; if (headerElementId > 0) { BrowserAccessibility* headerObject = - browserAccessibility_->manager()->GetFromRendererID(headerElementId); + browserAccessibility_->manager()->GetFromID(headerElementId); if (headerObject) return headerObject->ToBrowserAccessibilityCocoa(); } @@ -587,7 +587,7 @@ NSDictionary* attributeToMethodNameMap = nil; browserAccessibility_->GetIntListAttribute(attribute); for (size_t i = 0; i < attributeValues.size(); ++i) { BrowserAccessibility* element = - browserAccessibility_->manager()->GetFromRendererID(attributeValues[i]); + browserAccessibility_->manager()->GetFromID(attributeValues[i]); if (element) [outArray addObject:element->ToBrowserAccessibilityCocoa()]; } @@ -770,7 +770,7 @@ NSDictionary* attributeToMethodNameMap = nil; for (size_t i = 0; i < uniqueCellIds.size(); ++i) { int id = uniqueCellIds[i]; BrowserAccessibility* cell = - browserAccessibility_->manager()->GetFromRendererID(id); + browserAccessibility_->manager()->GetFromID(id); if (cell && cell->GetRole() == ui::AX_ROLE_ROW_HEADER) [ret addObject:cell->ToBrowserAccessibilityCocoa()]; } @@ -808,7 +808,7 @@ NSDictionary* attributeToMethodNameMap = nil; for (uint32 i = 0; i < indirectChildIds.size(); ++i) { int id = indirectChildIds[i]; BrowserAccessibility* rowElement = - browserAccessibility_->manager()->GetFromRendererID(id); + browserAccessibility_->manager()->GetFromID(id); if (rowElement) [ret addObject:rowElement->ToBrowserAccessibilityCocoa()]; } @@ -872,7 +872,7 @@ NSDictionary* attributeToMethodNameMap = nil; if (browserAccessibility_->GetIntAttribute( ui::AX_ATTR_TITLE_UI_ELEMENT, &titleElementId)) { BrowserAccessibility* titleElement = - browserAccessibility_->manager()->GetFromRendererID(titleElementId); + browserAccessibility_->manager()->GetFromID(titleElementId); if (titleElement) return titleElement->ToBrowserAccessibilityCocoa(); } @@ -880,7 +880,7 @@ NSDictionary* attributeToMethodNameMap = nil; browserAccessibility_->GetIntListAttribute(ui::AX_ATTR_LABELLEDBY_IDS); if (labelledby_ids.size() == 1) { BrowserAccessibility* titleElement = - browserAccessibility_->manager()->GetFromRendererID(labelledby_ids[0]); + browserAccessibility_->manager()->GetFromID(labelledby_ids[0]); if (titleElement) return titleElement->ToBrowserAccessibilityCocoa(); } @@ -984,7 +984,7 @@ NSDictionary* attributeToMethodNameMap = nil; for (size_t i = 0; i < uniqueCellIds.size(); ++i) { int id = uniqueCellIds[i]; BrowserAccessibility* cell = - browserAccessibility_->manager()->GetFromRendererID(id); + browserAccessibility_->manager()->GetFromID(id); if (cell) [ret addObject:cell->ToBrowserAccessibilityCocoa()]; } diff --git a/content/browser/accessibility/browser_accessibility_mac.h b/content/browser/accessibility/browser_accessibility_mac.h index 63a9d007d3ef..dc04484b67e9 100644 --- a/content/browser/accessibility/browser_accessibility_mac.h +++ b/content/browser/accessibility/browser_accessibility_mac.h @@ -17,15 +17,10 @@ namespace content { class BrowserAccessibilityMac : public BrowserAccessibility { public: - // Implementation of BrowserAccessibility. - virtual void PreInitialize() OVERRIDE; + // BrowserAccessibility overrides. virtual void NativeReleaseReference() OVERRIDE; virtual bool IsNative() const OVERRIDE; - - // Overrides from BrowserAccessibility. - virtual void DetachTree(std::vector* nodes) OVERRIDE; - virtual void SwapChildren(std::vector& children) - OVERRIDE; + virtual void OnDataChanged() OVERRIDE; // The BrowserAccessibilityCocoa associated with us. BrowserAccessibilityCocoa* native_view() const { diff --git a/content/browser/accessibility/browser_accessibility_mac.mm b/content/browser/accessibility/browser_accessibility_mac.mm index 11595a10e28b..33b36ce04a1d 100644 --- a/content/browser/accessibility/browser_accessibility_mac.mm +++ b/content/browser/accessibility/browser_accessibility_mac.mm @@ -21,11 +21,13 @@ BrowserAccessibilityMac::BrowserAccessibilityMac() : browser_accessibility_cocoa_(NULL) { } -void BrowserAccessibilityMac::PreInitialize() { - BrowserAccessibility::PreInitialize(); +void BrowserAccessibilityMac::OnDataChanged() { + BrowserAccessibility::OnDataChanged(); - if (browser_accessibility_cocoa_) + if (browser_accessibility_cocoa_) { + [browser_accessibility_cocoa_ childrenChanged]; return; + } // We take ownership of the cocoa obj here. BrowserAccessibilityManagerMac* manager = @@ -51,18 +53,6 @@ bool BrowserAccessibilityMac::IsNative() const { return true; } -void BrowserAccessibilityMac::DetachTree( - std::vector* nodes) { - [browser_accessibility_cocoa_ childrenChanged]; - BrowserAccessibility::DetachTree(nodes); -} - -void BrowserAccessibilityMac::SwapChildren( - std::vector& children) { - [browser_accessibility_cocoa_ childrenChanged]; - BrowserAccessibility::SwapChildren(children); -} - BrowserAccessibilityCocoa* BrowserAccessibility::ToBrowserAccessibilityCocoa() { return static_cast(this)-> native_view(); diff --git a/content/browser/accessibility/browser_accessibility_mac_unittest.mm b/content/browser/accessibility/browser_accessibility_mac_unittest.mm index c28ad6a8ec35..4dd8e30bfd55 100644 --- a/content/browser/accessibility/browser_accessibility_mac_unittest.mm +++ b/content/browser/accessibility/browser_accessibility_mac_unittest.mm @@ -89,8 +89,10 @@ class BrowserAccessibilityTest : public ui::CocoaTest { delegate_.reset([[MockAccessibilityDelegate alloc] init]); manager_.reset( - new BrowserAccessibilityManagerMac(delegate_, root, NULL)); - manager_->UpdateNodesForTesting(child1, child2); + new BrowserAccessibilityManagerMac( + delegate_, + MakeAXTreeUpdate(root, child1, child2), + NULL)); accessibility_.reset([manager_->GetRoot()->ToBrowserAccessibilityCocoa() retain]); } diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc index b91f3c1be3fb..abc5884119b9 100644 --- a/content/browser/accessibility/browser_accessibility_manager.cc +++ b/content/browser/accessibility/browser_accessibility_manager.cc @@ -10,6 +10,40 @@ namespace content { +ui::AXTreeUpdate MakeAXTreeUpdate( + const ui::AXNodeData& node1, + const ui::AXNodeData& node2 /* = ui::AXNodeData() */, + const ui::AXNodeData& node3 /* = ui::AXNodeData() */, + const ui::AXNodeData& node4 /* = ui::AXNodeData() */, + const ui::AXNodeData& node5 /* = ui::AXNodeData() */, + const ui::AXNodeData& node6 /* = ui::AXNodeData() */, + const ui::AXNodeData& node7 /* = ui::AXNodeData() */, + const ui::AXNodeData& node8 /* = ui::AXNodeData() */, + const ui::AXNodeData& node9 /* = ui::AXNodeData() */) { + CR_DEFINE_STATIC_LOCAL(ui::AXNodeData, empty_data, ()); + int32 no_id = empty_data.id; + + ui::AXTreeUpdate update; + update.nodes.push_back(node1); + if (node2.id != no_id) + update.nodes.push_back(node2); + if (node3.id != no_id) + update.nodes.push_back(node3); + if (node4.id != no_id) + update.nodes.push_back(node4); + if (node5.id != no_id) + update.nodes.push_back(node5); + if (node6.id != no_id) + update.nodes.push_back(node6); + if (node7.id != no_id) + update.nodes.push_back(node7); + if (node8.id != no_id) + update.nodes.push_back(node8); + if (node9.id != no_id) + update.nodes.push_back(node9); + return update; +} + BrowserAccessibility* BrowserAccessibilityFactory::Create() { return BrowserAccessibility::Create(); } @@ -21,10 +55,10 @@ BrowserAccessibility* BrowserAccessibilityFactory::Create() { // other platform, instantiate the base class. // static BrowserAccessibilityManager* BrowserAccessibilityManager::Create( - const ui::AXNodeData& src, + const ui::AXTreeUpdate& initial_tree, BrowserAccessibilityDelegate* delegate, BrowserAccessibilityFactory* factory) { - return new BrowserAccessibilityManager(src, delegate, factory); + return new BrowserAccessibilityManager(initial_tree, delegate, factory); } #endif @@ -33,71 +67,84 @@ BrowserAccessibilityManager::BrowserAccessibilityManager( BrowserAccessibilityFactory* factory) : delegate_(delegate), factory_(factory), - root_(NULL), + tree_(new ui::AXTree()), focus_(NULL), osk_state_(OSK_ALLOWED) { + tree_->SetDelegate(this); } BrowserAccessibilityManager::BrowserAccessibilityManager( - const ui::AXNodeData& src, + const ui::AXTreeUpdate& initial_tree, BrowserAccessibilityDelegate* delegate, BrowserAccessibilityFactory* factory) : delegate_(delegate), factory_(factory), - root_(NULL), + tree_(new ui::AXTree()), focus_(NULL), osk_state_(OSK_ALLOWED) { - Initialize(src); + tree_->SetDelegate(this); + Initialize(initial_tree); } BrowserAccessibilityManager::~BrowserAccessibilityManager() { - if (root_) - root_->Destroy(); + tree_.reset(NULL); } -void BrowserAccessibilityManager::Initialize(const ui::AXNodeData src) { - std::vector nodes; - nodes.push_back(src); - if (!UpdateNodes(nodes)) - return; +void BrowserAccessibilityManager::Initialize( + const ui::AXTreeUpdate& initial_tree) { + if (!tree_->Unserialize(initial_tree)) { + if (delegate_) { + LOG(ERROR) << tree_->error(); + delegate_->FatalAccessibilityTreeError(); + } else { + LOG(FATAL) << tree_->error(); + } + } + if (!focus_) - SetFocus(root_, false); + SetFocus(tree_->GetRoot(), false); } // static -ui::AXNodeData BrowserAccessibilityManager::GetEmptyDocument() { +ui::AXTreeUpdate BrowserAccessibilityManager::GetEmptyDocument() { ui::AXNodeData empty_document; empty_document.id = 0; empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA; - return empty_document; + ui::AXTreeUpdate update; + update.nodes.push_back(empty_document); + return update; } BrowserAccessibility* BrowserAccessibilityManager::GetRoot() { - return root_; + return GetFromAXNode(tree_->GetRoot()); } -BrowserAccessibility* BrowserAccessibilityManager::GetFromRendererID( - int32 renderer_id) { +BrowserAccessibility* BrowserAccessibilityManager::GetFromAXNode( + ui::AXNode* node) { + return GetFromID(node->id()); +} + +BrowserAccessibility* BrowserAccessibilityManager::GetFromID(int32 id) { base::hash_map::iterator iter = - renderer_id_map_.find(renderer_id); - if (iter != renderer_id_map_.end()) + id_wrapper_map_.find(id); + if (iter != id_wrapper_map_.end()) return iter->second; return NULL; } void BrowserAccessibilityManager::OnWindowFocused() { if (focus_) - NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, focus_); + NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_)); } void BrowserAccessibilityManager::OnWindowBlurred() { if (focus_) - NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, focus_); + NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, GetFromAXNode(focus_)); } void BrowserAccessibilityManager::GotMouseDown() { osk_state_ = OSK_ALLOWED_WITHIN_FOCUSED_OBJECT; - NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, focus_); + NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_)); } bool BrowserAccessibilityManager::IsOSKAllowed(const gfx::Rect& bounds) { @@ -112,13 +159,6 @@ bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() { return true; } -void BrowserAccessibilityManager::RemoveNode(BrowserAccessibility* node) { - if (node == focus_) - SetFocus(root_, false); - int renderer_id = node->GetId(); - renderer_id_map_.erase(renderer_id); -} - void BrowserAccessibilityManager::OnAccessibilityEvents( const std::vector& params) { bool should_send_initial_focus = false; @@ -126,22 +166,26 @@ void BrowserAccessibilityManager::OnAccessibilityEvents( // Process all changes to the accessibility tree first. for (uint32 index = 0; index < params.size(); index++) { const AccessibilityHostMsg_EventParams& param = params[index]; - if (!UpdateNodes(param.update.nodes)) + if (!tree_->Unserialize(param.update)) { + if (delegate_) { + LOG(ERROR) << tree_->error(); + delegate_->FatalAccessibilityTreeError(); + } else { + CHECK(false) << tree_->error(); + } return; + } - // Set initial focus when a page is loaded. - ui::AXEvent event_type = param.event_type; - if (event_type == ui::AX_EVENT_LOAD_COMPLETE) { - if (!focus_) { - SetFocus(root_, false); - should_send_initial_focus = true; - } + // Set focus to the root if it's not anywhere else. + if (!focus_) { + SetFocus(tree_->GetRoot(), false); + should_send_initial_focus = true; } } if (should_send_initial_focus && (!delegate_ || delegate_->HasFocus())) { - NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, focus_); + NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_)); } // Now iterate over the events again and fire the events. @@ -150,7 +194,7 @@ void BrowserAccessibilityManager::OnAccessibilityEvents( // Find the node corresponding to the id that's the target of the // event (which may not be the root of the update tree). - BrowserAccessibility* node = GetFromRendererID(param.id); + ui::AXNode* node = tree_->GetFromId(param.id); if (!node) continue; @@ -170,39 +214,42 @@ void BrowserAccessibilityManager::OnAccessibilityEvents( } // Send the event event to the operating system. - NotifyAccessibilityEvent(event_type, node); + NotifyAccessibilityEvent(event_type, GetFromAXNode(node)); } } void BrowserAccessibilityManager::OnLocationChanges( const std::vector& params) { for (size_t i = 0; i < params.size(); ++i) { - BrowserAccessibility* node = GetFromRendererID(params[i].id); - if (node) - node->SetLocation(params[i].new_location); + BrowserAccessibility* obj = GetFromID(params[i].id); + if (!obj) + continue; + ui::AXNode* node = obj->node(); + node->SetLocation(params[i].new_location); + obj->OnLocationChanged(); } } BrowserAccessibility* BrowserAccessibilityManager::GetFocus( BrowserAccessibility* root) { - if (focus_ && (!root || focus_->IsDescendantOf(root))) - return focus_; + if (focus_ && (!root || focus_->IsDescendantOf(root->node()))) + return GetFromAXNode(focus_); return NULL; } -void BrowserAccessibilityManager::SetFocus( - BrowserAccessibility* node, bool notify) { +void BrowserAccessibilityManager::SetFocus(ui::AXNode* node, bool notify) { if (focus_ != node) focus_ = node; if (notify && node && delegate_) - delegate_->SetAccessibilityFocus(node->GetId()); + delegate_->SetAccessibilityFocus(node->id()); } -void BrowserAccessibilityManager::SetRoot(BrowserAccessibility* node) { - root_ = node; - OnRootChanged(); +void BrowserAccessibilityManager::SetFocus( + BrowserAccessibility* obj, bool notify) { + if (obj->node()) + SetFocus(obj->node(), notify); } void BrowserAccessibilityManager::DoDefaultAction( @@ -273,191 +320,36 @@ BrowserAccessibility* BrowserAccessibilityManager::PreviousInTreeOrder( return node->GetParent(); } -void BrowserAccessibilityManager::UpdateNodesForTesting( - const ui::AXNodeData& node1, - const ui::AXNodeData& node2 /* = ui::AXNodeData() */, - const ui::AXNodeData& node3 /* = ui::AXNodeData() */, - const ui::AXNodeData& node4 /* = ui::AXNodeData() */, - const ui::AXNodeData& node5 /* = ui::AXNodeData() */, - const ui::AXNodeData& node6 /* = ui::AXNodeData() */, - const ui::AXNodeData& node7 /* = ui::AXNodeData() */) { - std::vector nodes; - nodes.push_back(node1); - if (node2.id != ui::AXNodeData().id) - nodes.push_back(node2); - if (node3.id != ui::AXNodeData().id) - nodes.push_back(node3); - if (node4.id != ui::AXNodeData().id) - nodes.push_back(node4); - if (node5.id != ui::AXNodeData().id) - nodes.push_back(node5); - if (node6.id != ui::AXNodeData().id) - nodes.push_back(node6); - if (node7.id != ui::AXNodeData().id) - nodes.push_back(node7); - UpdateNodes(nodes); -} - -bool BrowserAccessibilityManager::UpdateNodes( - const std::vector& nodes) { - bool success = true; - - // First, update all of the nodes in the tree. - for (size_t i = 0; i < nodes.size() && success; i++) { - if (!UpdateNode(nodes[i])) - success = false; - } - - // In a second pass, call PostInitialize on each one - this must - // be called after all of each node's children are initialized too. - for (size_t i = 0; i < nodes.size() && success; i++) { - // Note: it's not a bug for nodes[i].id to not be found in the tree. - // Consider this example: - // Before: - // A - // B - // C - // D - // E - // F - // After: - // A - // B - // C - // F - // D - // In this example, F is being reparented. The renderer scans the tree - // in order. If can't update "C" to add "F" as a child, when "F" is still - // a child of "E". So it first updates "E", to remove "F" as a child. - // Later, it ends up deleting "E". So when we get here, "E" was updated as - // part of this sequence but it no longer exists in the final tree, so - // there's nothing to postinitialize. - BrowserAccessibility* instance = GetFromRendererID(nodes[i].id); - if (instance) - instance->PostInitialize(); - } - - if (!success) { - // A bad accessibility tree could lead to memory corruption. - // Ask the delegate to crash the renderer, or if not available, - // crash the browser. - if (delegate_) - delegate_->FatalAccessibilityTreeError(); +void BrowserAccessibilityManager::OnNodeWillBeDeleted(ui::AXNode* node) { + if (node == focus_ && tree_) { + if (node != tree_->GetRoot()) + SetFocus(tree_->GetRoot(), false); else - CHECK(false); + focus_ = NULL; } - - return success; + if (id_wrapper_map_.find(node->id()) == id_wrapper_map_.end()) + return; + GetFromAXNode(node)->Destroy(); + id_wrapper_map_.erase(node->id()); } -BrowserAccessibility* BrowserAccessibilityManager::CreateNode( - BrowserAccessibility* parent, - int32 renderer_id, - int32 index_in_parent) { - BrowserAccessibility* node = factory_->Create(); - node->InitializeTreeStructure( - this, parent, renderer_id, index_in_parent); - AddNodeToMap(node); - return node; +void BrowserAccessibilityManager::OnNodeCreated(ui::AXNode* node) { + BrowserAccessibility* wrapper = factory_->Create(); + wrapper->Init(this, node); + id_wrapper_map_[node->id()] = wrapper; + wrapper->OnDataChanged(); } -void BrowserAccessibilityManager::AddNodeToMap(BrowserAccessibility* node) { - renderer_id_map_[node->GetId()] = node; +void BrowserAccessibilityManager::OnNodeChanged(ui::AXNode* node) { + GetFromAXNode(node)->OnDataChanged(); } -bool BrowserAccessibilityManager::UpdateNode(const ui::AXNodeData& src) { - // This method updates one node in the tree based on serialized data - // received from the renderer. - - // Create a set of child ids in |src| for fast lookup. If a duplicate id is - // found, exit now with a fatal error before changing anything else. - std::set new_child_ids; - for (size_t i = 0; i < src.child_ids.size(); ++i) { - if (new_child_ids.find(src.child_ids[i]) != new_child_ids.end()) - return false; - new_child_ids.insert(src.child_ids[i]); - } - - // Look up the node by id. If it's not found, then either the root - // of the tree is being swapped, or we're out of sync with the renderer - // and this is a serious error. - BrowserAccessibility* instance = GetFromRendererID(src.id); - if (!instance) { - if (src.role != ui::AX_ROLE_ROOT_WEB_AREA) - return false; - instance = CreateNode(NULL, src.id, 0); - } - - // Update all of the node-specific data, like its role, state, name, etc. - instance->InitializeData(src); - - // - // Update the children in three steps: - // - // 1. Iterate over the old children and delete nodes that are no longer - // in the tree. - // 2. Build up a vector of new children, reusing children that haven't - // changed (but may have been reordered) and adding new empty - // objects for new children. - // 3. Swap in the new children vector for the old one. - - // Delete any previous children of this instance that are no longer - // children first. We make a deletion-only pass first to prevent a - // node that's being reparented from being the child of both its old - // parent and new parent, which could lead to a double-free. - // If a node is reparented, the renderer will always send us a fresh - // copy of the node. - const std::vector& old_children = - instance->deprecated_children(); - for (size_t i = 0; i < old_children.size(); ++i) { - int old_id = old_children[i]->GetId(); - if (new_child_ids.find(old_id) == new_child_ids.end()) - old_children[i]->Destroy(); - } - - // Now build a vector of new children, reusing objects that were already - // children of this node before. - std::vector new_children; - bool success = true; - for (size_t i = 0; i < src.child_ids.size(); i++) { - int32 child_renderer_id = src.child_ids[i]; - int32 index_in_parent = static_cast(i); - BrowserAccessibility* child = GetFromRendererID(child_renderer_id); - if (child) { - if (child->GetParent() != instance) { - // This is a serious error - nodes should never be reparented. - // If this case occurs, continue so this node isn't left in an - // inconsistent state, but return failure at the end. - success = false; - continue; - } - child->UpdateParent(instance, index_in_parent); - } else { - child = CreateNode(instance, child_renderer_id, index_in_parent); - } - new_children.push_back(child); - } - - // Finally, swap in the new children vector for the old. - instance->SwapChildren(new_children); - - // Handle the case where this node is the new root of the tree. - if (src.role == ui::AX_ROLE_ROOT_WEB_AREA && - (!root_ || root_->GetId() != src.id)) { - if (root_) - root_->Destroy(); - if (focus_ == root_) - SetFocus(instance, false); - SetRoot(instance); - } +void BrowserAccessibilityManager::OnNodeCreationFinished(ui::AXNode* node) { + GetFromAXNode(node)->OnUpdateFinished(); +} - // Keep track of what node is focused. - if (src.role != ui::AX_ROLE_ROOT_WEB_AREA && - src.role != ui::AX_ROLE_WEB_AREA && - (src.state >> ui::AX_STATE_FOCUSED & 1)) { - SetFocus(instance, false); - } - return success; +void BrowserAccessibilityManager::OnNodeChangeFinished(ui::AXNode* node) { + GetFromAXNode(node)->OnUpdateFinished(); } } // namespace content diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h index 3dafaabdadfd..a5926c7b70f5 100644 --- a/content/browser/accessibility/browser_accessibility_manager.h +++ b/content/browser/accessibility/browser_accessibility_manager.h @@ -13,6 +13,8 @@ #include "content/common/content_export.h" #include "third_party/WebKit/public/web/WebAXEnums.h" #include "ui/accessibility/ax_node_data.h" +#include "ui/accessibility/ax_tree.h" +#include "ui/accessibility/ax_tree_update.h" #include "ui/gfx/native_widget_types.h" struct AccessibilityHostMsg_EventParams; @@ -27,6 +29,18 @@ class BrowserAccessibilityManagerAndroid; class BrowserAccessibilityManagerWin; #endif +// For testing. +CONTENT_EXPORT ui::AXTreeUpdate MakeAXTreeUpdate( + const ui::AXNodeData& node, + const ui::AXNodeData& node2 = ui::AXNodeData(), + const ui::AXNodeData& node3 = ui::AXNodeData(), + const ui::AXNodeData& node4 = ui::AXNodeData(), + const ui::AXNodeData& node5 = ui::AXNodeData(), + const ui::AXNodeData& node6 = ui::AXNodeData(), + const ui::AXNodeData& node7 = ui::AXNodeData(), + const ui::AXNodeData& node8 = ui::AXNodeData(), + const ui::AXNodeData& node9 = ui::AXNodeData()); + // Class that can perform actions on behalf of the BrowserAccessibilityManager. class CONTENT_EXPORT BrowserAccessibilityDelegate { public: @@ -55,20 +69,20 @@ class CONTENT_EXPORT BrowserAccessibilityFactory { }; // Manages a tree of BrowserAccessibility objects. -class CONTENT_EXPORT BrowserAccessibilityManager { +class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate { public: // Creates the platform-specific BrowserAccessibilityManager, but // with no parent window pointer. Only useful for unit tests. static BrowserAccessibilityManager* Create( - const ui::AXNodeData& src, + const ui::AXTreeUpdate& initial_tree, BrowserAccessibilityDelegate* delegate, BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory()); virtual ~BrowserAccessibilityManager(); - void Initialize(const ui::AXNodeData src); + void Initialize(const ui::AXTreeUpdate& initial_tree); - static ui::AXNodeData GetEmptyDocument(); + static ui::AXTreeUpdate GetEmptyDocument(); virtual void NotifyAccessibilityEvent( ui::AXEvent event_type, BrowserAccessibility* node) { } @@ -76,12 +90,12 @@ class CONTENT_EXPORT BrowserAccessibilityManager { // Return a pointer to the root of the tree, does not make a new reference. BrowserAccessibility* GetRoot(); - // Removes a node from the manager. - virtual void RemoveNode(BrowserAccessibility* node); + // Returns a pointer to the BrowserAccessibility object for a given AXNode. + BrowserAccessibility* GetFromAXNode(ui::AXNode* node); - // Return a pointer to the object corresponding to the given renderer_id, + // Return a pointer to the object corresponding to the given id, // does not make a new reference. - BrowserAccessibility* GetFromRendererID(int32 renderer_id); + BrowserAccessibility* GetFromID(int32 id); // Called to notify the accessibility manager that its associated native // view got focused. @@ -98,6 +112,7 @@ class CONTENT_EXPORT BrowserAccessibilityManager { // Update the focused node to |node|, which may be null. // If |notify| is true, send a message to the renderer to set focus // to this node. + void SetFocus(ui::AXNode* node, bool notify); void SetFocus(BrowserAccessibility* node, bool notify); // Tell the renderer to do the default action for this node. @@ -155,18 +170,13 @@ class CONTENT_EXPORT BrowserAccessibilityManager { BrowserAccessibility* NextInTreeOrder(BrowserAccessibility* node); BrowserAccessibility* PreviousInTreeOrder(BrowserAccessibility* node); - // For testing only: update the given nodes as if they were - // received from the renderer process in OnAccessibilityEvents. - // Takes up to 7 nodes at once so tests don't need to create a vector - // each time. - void UpdateNodesForTesting( - const ui::AXNodeData& node, - const ui::AXNodeData& node2 = ui::AXNodeData(), - const ui::AXNodeData& node3 = ui::AXNodeData(), - const ui::AXNodeData& node4 = ui::AXNodeData(), - const ui::AXNodeData& node5 = ui::AXNodeData(), - const ui::AXNodeData& node6 = ui::AXNodeData(), - const ui::AXNodeData& node7 = ui::AXNodeData()); + // AXTreeDelegate implementation. + virtual void OnNodeWillBeDeleted(ui::AXNode* node) OVERRIDE; + virtual void OnNodeCreated(ui::AXNode* node) OVERRIDE; + virtual void OnNodeChanged(ui::AXNode* node) OVERRIDE; + virtual void OnNodeCreationFinished(ui::AXNode* node) OVERRIDE; + virtual void OnNodeChangeFinished(ui::AXNode* node) OVERRIDE; + virtual void OnRootChanged(ui::AXNode* new_root) OVERRIDE {} protected: BrowserAccessibilityManager( @@ -174,14 +184,10 @@ class CONTENT_EXPORT BrowserAccessibilityManager { BrowserAccessibilityFactory* factory); BrowserAccessibilityManager( - const ui::AXNodeData& src, + const ui::AXTreeUpdate& initial_tree, BrowserAccessibilityDelegate* delegate, BrowserAccessibilityFactory* factory); - virtual void AddNodeToMap(BrowserAccessibility* node); - - virtual void OnRootChanged() {} - private: // The following states keep track of whether or not the // on-screen keyboard is allowed to be shown. @@ -217,7 +223,7 @@ class CONTENT_EXPORT BrowserAccessibilityManager { BrowserAccessibility* CreateNode( BrowserAccessibility* parent, - int32 renderer_id, + int32 id, int32 index_in_parent); protected: @@ -227,17 +233,18 @@ class CONTENT_EXPORT BrowserAccessibilityManager { // Factory to create BrowserAccessibility objects (for dependency injection). scoped_ptr factory_; - // The root of the tree of accessible objects and the element that - // currently has focus, if any. - BrowserAccessibility* root_; - BrowserAccessibility* focus_; + // The underlying tree of accessibility objects. + scoped_ptr tree_; + + // The node that currently has focus. + ui::AXNode* focus_; + + // A mapping from a node id to its wrapper of type BrowserAccessibility. + base::hash_map id_wrapper_map_; // The on-screen keyboard state. OnScreenKeyboardState osk_state_; - // A mapping from renderer IDs to BrowserAccessibility objects. - base::hash_map renderer_id_map_; - DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManager); }; diff --git a/content/browser/accessibility/browser_accessibility_manager_android.cc b/content/browser/accessibility/browser_accessibility_manager_android.cc index 3d349e4b39c3..21c29c0aab53 100644 --- a/content/browser/accessibility/browser_accessibility_manager_android.cc +++ b/content/browser/accessibility/browser_accessibility_manager_android.cc @@ -62,11 +62,11 @@ namespace aria_strings { // static BrowserAccessibilityManager* BrowserAccessibilityManager::Create( - const ui::AXNodeData& src, + const ui::AXTreeUpdate& initial_tree, BrowserAccessibilityDelegate* delegate, BrowserAccessibilityFactory* factory) { - return new BrowserAccessibilityManagerAndroid(ScopedJavaLocalRef(), - src, delegate, factory); + return new BrowserAccessibilityManagerAndroid( + ScopedJavaLocalRef(), initial_tree, delegate, factory); } BrowserAccessibilityManagerAndroid* @@ -76,10 +76,10 @@ BrowserAccessibilityManager::ToBrowserAccessibilityManagerAndroid() { BrowserAccessibilityManagerAndroid::BrowserAccessibilityManagerAndroid( ScopedJavaLocalRef content_view_core, - const ui::AXNodeData& src, + const ui::AXTreeUpdate& initial_tree, BrowserAccessibilityDelegate* delegate, BrowserAccessibilityFactory* factory) - : BrowserAccessibilityManager(src, delegate, factory) { + : BrowserAccessibilityManager(initial_tree, delegate, factory) { SetContentViewCore(content_view_core); } @@ -93,12 +93,15 @@ BrowserAccessibilityManagerAndroid::~BrowserAccessibilityManagerAndroid() { } // static -ui::AXNodeData BrowserAccessibilityManagerAndroid::GetEmptyDocument() { +ui::AXTreeUpdate BrowserAccessibilityManagerAndroid::GetEmptyDocument() { ui::AXNodeData empty_document; empty_document.id = 0; empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA; empty_document.state = 1 << ui::AX_STATE_READ_ONLY; - return empty_document; + + ui::AXTreeUpdate update; + update.nodes.push_back(empty_document); + return update; } void BrowserAccessibilityManagerAndroid::SetContentViewCore( @@ -133,7 +136,7 @@ void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent( switch (event_type) { case ui::AX_EVENT_LOAD_COMPLETE: Java_BrowserAccessibilityManager_handlePageLoaded( - env, obj.obj(), focus_->GetId()); + env, obj.obj(), focus_->id()); break; case ui::AX_EVENT_FOCUS: Java_BrowserAccessibilityManager_handleFocusChanged( @@ -185,22 +188,22 @@ void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent( } jint BrowserAccessibilityManagerAndroid::GetRootId(JNIEnv* env, jobject obj) { - return static_cast(root_->GetId()); + return static_cast(GetRoot()->GetId()); } jboolean BrowserAccessibilityManagerAndroid::IsNodeValid( JNIEnv* env, jobject obj, jint id) { - return GetFromRendererID(id) != NULL; + return GetFromID(id) != NULL; } jint BrowserAccessibilityManagerAndroid::HitTest( JNIEnv* env, jobject obj, jint x, jint y) { BrowserAccessibilityAndroid* result = static_cast( - root_->BrowserAccessibilityForPoint(gfx::Point(x, y))); + GetRoot()->BrowserAccessibilityForPoint(gfx::Point(x, y))); if (!result) - return root_->GetId(); + return GetRoot()->GetId(); if (result->IsFocusable()) return result->GetId(); @@ -211,13 +214,13 @@ jint BrowserAccessibilityManagerAndroid::HitTest( if (nearest_node) return nearest_node->GetId(); - return root_->GetId(); + return GetRoot()->GetId(); } jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo( JNIEnv* env, jobject obj, jobject info, jint id) { BrowserAccessibilityAndroid* node = static_cast( - GetFromRendererID(id)); + GetFromID(id)); if (!node) return false; @@ -304,7 +307,7 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo( jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityEvent( JNIEnv* env, jobject obj, jobject event, jint id, jint event_type) { BrowserAccessibilityAndroid* node = static_cast( - GetFromRendererID(id)); + GetFromID(id)); if (!node) return false; @@ -390,25 +393,25 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityEvent( void BrowserAccessibilityManagerAndroid::Click( JNIEnv* env, jobject obj, jint id) { - BrowserAccessibility* node = GetFromRendererID(id); + BrowserAccessibility* node = GetFromID(id); if (node) DoDefaultAction(*node); } void BrowserAccessibilityManagerAndroid::Focus( JNIEnv* env, jobject obj, jint id) { - BrowserAccessibility* node = GetFromRendererID(id); + BrowserAccessibility* node = GetFromID(id); if (node) SetFocus(node, true); } void BrowserAccessibilityManagerAndroid::Blur(JNIEnv* env, jobject obj) { - SetFocus(root_, true); + SetFocus(GetRoot(), true); } void BrowserAccessibilityManagerAndroid::ScrollToMakeNodeVisible( JNIEnv* env, jobject obj, jint id) { - BrowserAccessibility* node = GetFromRendererID(id); + BrowserAccessibility* node = GetFromID(id); if (node) ScrollToMakeVisible(*node, gfx::Rect(node->GetLocation().size())); } @@ -467,7 +470,7 @@ int BrowserAccessibilityManagerAndroid::CalculateDistanceSquared( jint BrowserAccessibilityManagerAndroid::FindElementType( JNIEnv* env, jobject obj, jint start_id, jstring element_type_str, jboolean forwards) { - BrowserAccessibility* node = GetFromRendererID(start_id); + BrowserAccessibility* node = GetFromID(start_id); if (!node) return 0; @@ -521,7 +524,7 @@ jint BrowserAccessibilityManagerAndroid::FindElementType( return 0; } -void BrowserAccessibilityManagerAndroid::OnRootChanged() { +void BrowserAccessibilityManagerAndroid::OnRootChanged(ui::AXNode* new_root) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (obj.is_null()) diff --git a/content/browser/accessibility/browser_accessibility_manager_android.h b/content/browser/accessibility/browser_accessibility_manager_android.h index 146567a90793..cc2757cf45b3 100644 --- a/content/browser/accessibility/browser_accessibility_manager_android.h +++ b/content/browser/accessibility/browser_accessibility_manager_android.h @@ -21,13 +21,13 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAndroid public: BrowserAccessibilityManagerAndroid( base::android::ScopedJavaLocalRef content_view_core, - const ui::AXNodeData& src, + const ui::AXTreeUpdate& initial_tree, BrowserAccessibilityDelegate* delegate, BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory()); virtual ~BrowserAccessibilityManagerAndroid(); - static ui::AXNodeData GetEmptyDocument(); + static ui::AXTreeUpdate GetEmptyDocument(); void SetContentViewCore( base::android::ScopedJavaLocalRef content_view_core); @@ -66,7 +66,8 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAndroid jstring element_type, jboolean forwards); protected: - virtual void OnRootChanged() OVERRIDE; + // AXTreeDelegate overrides. + virtual void OnRootChanged(ui::AXNode* new_root) OVERRIDE; virtual bool UseRootScrollOffsetsWhenComputingBounds() OVERRIDE; diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.h b/content/browser/accessibility/browser_accessibility_manager_mac.h index 2b501d6d210b..c0576190ae6f 100644 --- a/content/browser/accessibility/browser_accessibility_manager_mac.h +++ b/content/browser/accessibility/browser_accessibility_manager_mac.h @@ -16,11 +16,11 @@ class CONTENT_EXPORT BrowserAccessibilityManagerMac public: BrowserAccessibilityManagerMac( NSView* parent_view, - const ui::AXNodeData& src, + const ui::AXTreeUpdate& initial_tree, BrowserAccessibilityDelegate* delegate, BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory()); - static ui::AXNodeData GetEmptyDocument(); + static ui::AXTreeUpdate GetEmptyDocument(); // Implementation of BrowserAccessibilityManager. virtual void NotifyAccessibilityEvent( diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.mm b/content/browser/accessibility/browser_accessibility_manager_mac.mm index 2a2f331479e4..266f8fb90c85 100644 --- a/content/browser/accessibility/browser_accessibility_manager_mac.mm +++ b/content/browser/accessibility/browser_accessibility_manager_mac.mm @@ -12,29 +12,32 @@ namespace content { // static BrowserAccessibilityManager* BrowserAccessibilityManager::Create( - const ui::AXNodeData& src, + const ui::AXTreeUpdate& initial_tree, BrowserAccessibilityDelegate* delegate, BrowserAccessibilityFactory* factory) { - return new BrowserAccessibilityManagerMac(NULL, src, delegate, factory); + return new BrowserAccessibilityManagerMac( + NULL, initial_tree, delegate, factory); } BrowserAccessibilityManagerMac::BrowserAccessibilityManagerMac( NSView* parent_view, - const ui::AXNodeData& src, + const ui::AXTreeUpdate& initial_tree, BrowserAccessibilityDelegate* delegate, BrowserAccessibilityFactory* factory) - : BrowserAccessibilityManager(src, delegate, factory), + : BrowserAccessibilityManager(initial_tree, delegate, factory), parent_view_(parent_view) { } // static -ui::AXNodeData BrowserAccessibilityManagerMac::GetEmptyDocument() { +ui::AXTreeUpdate BrowserAccessibilityManagerMac::GetEmptyDocument() { ui::AXNodeData empty_document; empty_document.id = 0; empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA; empty_document.state = 1 << ui::AX_STATE_READ_ONLY; - return empty_document; + ui::AXTreeUpdate update; + update.nodes.push_back(empty_document); + return update; } void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent( diff --git a/content/browser/accessibility/browser_accessibility_manager_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_unittest.cc index 3cfeb5549022..dd0b6157f857 100644 --- a/content/browser/accessibility/browser_accessibility_manager_unittest.cc +++ b/content/browser/accessibility/browser_accessibility_manager_unittest.cc @@ -128,10 +128,9 @@ TEST(BrowserAccessibilityManagerTest, TestNoLeaks) { CountedBrowserAccessibility::global_obj_count_ = 0; BrowserAccessibilityManager* manager = BrowserAccessibilityManager::Create( - root, + MakeAXTreeUpdate(root, button, checkbox), NULL, new CountedBrowserAccessibilityFactory()); - manager->UpdateNodesForTesting(button, checkbox); ASSERT_EQ(3, CountedBrowserAccessibility::global_obj_count_); @@ -143,10 +142,9 @@ TEST(BrowserAccessibilityManagerTest, TestNoLeaks) { // the three nodes in the tree. manager = BrowserAccessibilityManager::Create( - root, + MakeAXTreeUpdate(root, button, checkbox), NULL, new CountedBrowserAccessibilityFactory()); - manager->UpdateNodesForTesting(button, checkbox); ASSERT_EQ(3, CountedBrowserAccessibility::global_obj_count_); CountedBrowserAccessibility* root_accessible = @@ -234,10 +232,10 @@ TEST(BrowserAccessibilityManagerTest, TestReuseBrowserAccessibilityObjects) { CountedBrowserAccessibility::global_obj_count_ = 0; BrowserAccessibilityManager* manager = BrowserAccessibilityManager::Create( - tree1_root, + MakeAXTreeUpdate(tree1_root, + tree1_child1, tree1_child2, tree1_child3), NULL, new CountedBrowserAccessibilityFactory()); - manager->UpdateNodesForTesting(tree1_child1, tree1_child2, tree1_child3); ASSERT_EQ(4, CountedBrowserAccessibility::global_obj_count_); // Save references to all of the objects. @@ -408,13 +406,12 @@ TEST(BrowserAccessibilityManagerTest, TestReuseBrowserAccessibilityObjects2) { CountedBrowserAccessibility::global_obj_count_ = 0; BrowserAccessibilityManager* manager = BrowserAccessibilityManager::Create( - tree1_root, + MakeAXTreeUpdate(tree1_root, tree1_container, + tree1_child1, tree1_grandchild1, + tree1_child2, tree1_grandchild2, + tree1_child3, tree1_grandchild3), NULL, new CountedBrowserAccessibilityFactory()); - manager->UpdateNodesForTesting(tree1_container, - tree1_child1, tree1_grandchild1, - tree1_child2, tree1_grandchild2, - tree1_child3, tree1_grandchild3); ASSERT_EQ(8, CountedBrowserAccessibility::global_obj_count_); // Save references to some objects. @@ -540,10 +537,9 @@ TEST(BrowserAccessibilityManagerTest, TestMoveChildUp) { CountedBrowserAccessibility::global_obj_count_ = 0; BrowserAccessibilityManager* manager = BrowserAccessibilityManager::Create( - tree1_1, + MakeAXTreeUpdate(tree1_1, tree1_2, tree1_3, tree1_4), NULL, new CountedBrowserAccessibilityFactory()); - manager->UpdateNodesForTesting(tree1_2, tree1_3, tree1_4); ASSERT_EQ(4, CountedBrowserAccessibility::global_obj_count_); // Process a notification containing the changed subtree. @@ -566,13 +562,7 @@ TEST(BrowserAccessibilityManagerTest, TestMoveChildUp) { ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_); } -// Crashes on Windows. http://crbug.com/304130 -#if defined(OS_WIN) -#define MAYBE_TestFatalError DISABLED_TestFatalError -#else -#define MAYBE_TestFatalError TestFatalError -#endif -TEST(BrowserAccessibilityManagerTest, MAYBE_TestFatalError) { +TEST(BrowserAccessibilityManagerTest, TestFatalError) { // Test that BrowserAccessibilityManager raises a fatal error // (which will crash the renderer) if the same id is used in // two places in the tree. @@ -590,7 +580,7 @@ TEST(BrowserAccessibilityManagerTest, MAYBE_TestFatalError) { scoped_ptr manager; ASSERT_FALSE(delegate->got_fatal_error()); manager.reset(BrowserAccessibilityManager::Create( - root, + MakeAXTreeUpdate(root), delegate.get(), factory)); ASSERT_TRUE(delegate->got_fatal_error()); @@ -611,14 +601,22 @@ TEST(BrowserAccessibilityManagerTest, MAYBE_TestFatalError) { child2.child_ids.push_back(6); child2.child_ids.push_back(5); // Duplicate + ui::AXNodeData grandchild4; + grandchild4.id = 4; + + ui::AXNodeData grandchild5; + grandchild5.id = 5; + + ui::AXNodeData grandchild6; + grandchild6.id = 6; + delegate->reset_got_fatal_error(); factory = new CountedBrowserAccessibilityFactory(); manager.reset(BrowserAccessibilityManager::Create( - root2, + MakeAXTreeUpdate(root2, child1, child2, + grandchild4, grandchild5, grandchild6), delegate.get(), factory)); - ASSERT_FALSE(delegate->got_fatal_error()); - manager->UpdateNodesForTesting(child1, child2); ASSERT_TRUE(delegate->got_fatal_error()); } @@ -673,10 +671,9 @@ TEST(BrowserAccessibilityManagerTest, BoundsForRange) { scoped_ptr manager( BrowserAccessibilityManager::Create( - root, + MakeAXTreeUpdate(root, static_text, inline_text1, inline_text2), NULL, new CountedBrowserAccessibilityFactory())); - manager->UpdateNodesForTesting(static_text, inline_text1, inline_text2); BrowserAccessibility* root_accessible = manager->GetRoot(); BrowserAccessibility* static_text_accessible = @@ -762,10 +759,9 @@ TEST(BrowserAccessibilityManagerTest, BoundsForRangeBiDi) { scoped_ptr manager( BrowserAccessibilityManager::Create( - root, + MakeAXTreeUpdate(root, static_text, inline_text1, inline_text2), NULL, new CountedBrowserAccessibilityFactory())); - manager->UpdateNodesForTesting(static_text, inline_text1, inline_text2); BrowserAccessibility* root_accessible = manager->GetRoot(); BrowserAccessibility* static_text_accessible = @@ -859,12 +855,11 @@ TEST(BrowserAccessibilityManagerTest, MAYBE_BoundsForRangeOnParentElement) { scoped_ptr manager( BrowserAccessibilityManager::Create( - root, + MakeAXTreeUpdate( + root, div, static_text1, img, + static_text2, inline_text1, inline_text2), NULL, new CountedBrowserAccessibilityFactory())); - manager->UpdateNodesForTesting( - div, static_text1, img, static_text2, inline_text1, inline_text2); - BrowserAccessibility* root_accessible = manager->GetRoot(); EXPECT_EQ(gfx::Rect(100, 100, 20, 20).ToString(), @@ -909,10 +904,9 @@ TEST(BrowserAccessibilityManagerTest, NextPreviousInTreeOrder) { scoped_ptr manager( BrowserAccessibilityManager::Create( - root, + MakeAXTreeUpdate(root, node2, node3, node4, node5), NULL, new CountedBrowserAccessibilityFactory())); - manager->UpdateNodesForTesting(node2, node3, node4, node5); BrowserAccessibility* root_accessible = manager->GetRoot(); BrowserAccessibility* node2_accessible = root_accessible->PlatformGetChild(0); diff --git a/content/browser/accessibility/browser_accessibility_manager_win.cc b/content/browser/accessibility/browser_accessibility_manager_win.cc index 7205d14ababe..31f9d8a637d7 100644 --- a/content/browser/accessibility/browser_accessibility_manager_win.cc +++ b/content/browser/accessibility/browser_accessibility_manager_win.cc @@ -16,12 +16,12 @@ namespace content { // static BrowserAccessibilityManager* BrowserAccessibilityManager::Create( - const ui::AXNodeData& src, + const ui::AXTreeUpdate& initial_tree, BrowserAccessibilityDelegate* delegate, BrowserAccessibilityFactory* factory) { return new BrowserAccessibilityManagerWin( content::LegacyRenderWidgetHostHWND::Create(GetDesktopWindow()).get(), - NULL, src, delegate, factory); + NULL, initial_tree, delegate, factory); } BrowserAccessibilityManagerWin* @@ -32,10 +32,10 @@ BrowserAccessibilityManager::ToBrowserAccessibilityManagerWin() { BrowserAccessibilityManagerWin::BrowserAccessibilityManagerWin( LegacyRenderWidgetHostHWND* accessible_hwnd, IAccessible* parent_iaccessible, - const ui::AXNodeData& src, + const ui::AXTreeUpdate& initial_tree, BrowserAccessibilityDelegate* delegate, BrowserAccessibilityFactory* factory) - : BrowserAccessibilityManager(src, delegate, factory), + : BrowserAccessibilityManager(initial_tree, delegate, factory), parent_hwnd_(accessible_hwnd->GetParent()), parent_iaccessible_(parent_iaccessible), tracked_scroll_object_(NULL), @@ -53,7 +53,7 @@ BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() { } // static -ui::AXNodeData BrowserAccessibilityManagerWin::GetEmptyDocument() { +ui::AXTreeUpdate BrowserAccessibilityManagerWin::GetEmptyDocument() { ui::AXNodeData empty_document; empty_document.id = 0; empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA; @@ -61,7 +61,10 @@ ui::AXNodeData BrowserAccessibilityManagerWin::GetEmptyDocument() { (1 << ui::AX_STATE_ENABLED) | (1 << ui::AX_STATE_READ_ONLY) | (1 << ui::AX_STATE_BUSY); - return empty_document; + + ui::AXTreeUpdate update; + update.nodes.push_back(empty_document); + return update; } void BrowserAccessibilityManagerWin::MaybeCallNotifyWinEvent(DWORD event, @@ -81,17 +84,22 @@ void BrowserAccessibilityManagerWin::MaybeCallNotifyWinEvent(DWORD event, ::NotifyWinEvent(event, parent_hwnd(), OBJID_CLIENT, child_id); } -void BrowserAccessibilityManagerWin::AddNodeToMap(BrowserAccessibility* node) { - BrowserAccessibilityManager::AddNodeToMap(node); - LONG unique_id_win = node->ToBrowserAccessibilityWin()->unique_id_win(); - unique_id_to_renderer_id_map_[unique_id_win] = node->GetId(); + +void BrowserAccessibilityManagerWin::OnNodeCreated(ui::AXNode* node) { + BrowserAccessibilityManager::OnNodeCreated(node); + BrowserAccessibility* obj = GetFromAXNode(node); + LONG unique_id_win = obj->ToBrowserAccessibilityWin()->unique_id_win(); + unique_id_to_ax_id_map_[unique_id_win] = obj->GetId(); } -void BrowserAccessibilityManagerWin::RemoveNode(BrowserAccessibility* node) { - unique_id_to_renderer_id_map_.erase( - node->ToBrowserAccessibilityWin()->unique_id_win()); - BrowserAccessibilityManager::RemoveNode(node); - if (node == tracked_scroll_object_) { +void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXNode* node) { + BrowserAccessibilityManager::OnNodeWillBeDeleted(node); + BrowserAccessibility* obj = GetFromAXNode(node); + if (!obj) + return; + unique_id_to_ax_id_map_.erase( + obj->ToBrowserAccessibilityWin()->unique_id_win()); + if (obj == tracked_scroll_object_) { tracked_scroll_object_->Release(); tracked_scroll_object_ = NULL; } @@ -99,16 +107,16 @@ void BrowserAccessibilityManagerWin::RemoveNode(BrowserAccessibility* node) { void BrowserAccessibilityManagerWin::OnWindowFocused() { // Fire a focus event on the root first and then the focused node. - if (focus_ != root_) - NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, root_); + if (focus_ != tree_->GetRoot()) + NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetRoot()); BrowserAccessibilityManager::OnWindowFocused(); } void BrowserAccessibilityManagerWin::OnWindowBlurred() { // Fire a blur event on the focused node first and then the root. BrowserAccessibilityManager::OnWindowBlurred(); - if (focus_ != root_) - NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, root_); + if (focus_ != tree_->GetRoot()) + NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, GetRoot()); } void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent( @@ -221,9 +229,9 @@ void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent( } } -void BrowserAccessibilityManagerWin::OnRootChanged() { +void BrowserAccessibilityManagerWin::OnRootChanged(ui::AXNode* new_root) { if (delegate_ && delegate_->HasFocus()) - NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, root_); + NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetRoot()); } void BrowserAccessibilityManagerWin::TrackScrollingObject( @@ -237,9 +245,9 @@ void BrowserAccessibilityManagerWin::TrackScrollingObject( BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFromUniqueIdWin( LONG unique_id_win) { base::hash_map::iterator iter = - unique_id_to_renderer_id_map_.find(unique_id_win); - if (iter != unique_id_to_renderer_id_map_.end()) { - BrowserAccessibility* result = GetFromRendererID(iter->second); + unique_id_to_ax_id_map_.find(unique_id_win); + if (iter != unique_id_to_ax_id_map_.end()) { + BrowserAccessibility* result = GetFromID(iter->second); if (result) return result->ToBrowserAccessibilityWin(); } diff --git a/content/browser/accessibility/browser_accessibility_manager_win.h b/content/browser/accessibility/browser_accessibility_manager_win.h index 3fbbd3fe2b61..18260e4f70d1 100644 --- a/content/browser/accessibility/browser_accessibility_manager_win.h +++ b/content/browser/accessibility/browser_accessibility_manager_win.h @@ -23,13 +23,13 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin BrowserAccessibilityManagerWin( content::LegacyRenderWidgetHostHWND* accessible_hwnd, IAccessible* parent_iaccessible, - const ui::AXNodeData& src, + const ui::AXTreeUpdate& initial_tree, BrowserAccessibilityDelegate* delegate, BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory()); virtual ~BrowserAccessibilityManagerWin(); - static ui::AXNodeData GetEmptyDocument(); + static ui::AXTreeUpdate GetEmptyDocument(); // Get the closest containing HWND. HWND parent_hwnd() { return parent_hwnd_; } @@ -43,9 +43,11 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin // Calls NotifyWinEvent if the parent window's IAccessible pointer is known. void MaybeCallNotifyWinEvent(DWORD event, LONG child_id); + // AXTree methods + virtual void OnNodeWillBeDeleted(ui::AXNode* node) OVERRIDE; + virtual void OnNodeCreated(ui::AXNode* node) OVERRIDE; + // BrowserAccessibilityManager methods - virtual void AddNodeToMap(BrowserAccessibility* node); - virtual void RemoveNode(BrowserAccessibility* node) OVERRIDE; virtual void OnWindowFocused() OVERRIDE; virtual void OnWindowBlurred() OVERRIDE; virtual void NotifyAccessibilityEvent( @@ -65,7 +67,7 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin protected: // BrowserAccessibilityManager methods - virtual void OnRootChanged() OVERRIDE; + virtual void OnRootChanged(ui::AXNode* new_root) OVERRIDE; private: // The closest ancestor HWND. @@ -83,8 +85,8 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin BrowserAccessibilityWin* tracked_scroll_object_; // A mapping from the Windows-specific unique IDs (unique within the - // browser process) to renderer ids within this page. - base::hash_map unique_id_to_renderer_id_map_; + // browser process) to accessibility ids within this page. + base::hash_map unique_id_to_ax_id_map_; // Owned by its parent; OnAccessibleHwndDeleted gets called upon deletion. LegacyRenderWidgetHostHWND* accessible_hwnd_; diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc index c96c785717b5..ac2af33903d2 100644 --- a/content/browser/accessibility/browser_accessibility_win.cc +++ b/content/browser/accessibility/browser_accessibility_win.cc @@ -114,7 +114,7 @@ STDMETHODIMP BrowserAccessibilityRelation::get_nTargets(long* n_targets) { BrowserAccessibilityManager* manager = owner_->manager(); for (long i = *n_targets - 1; i >= 0; --i) { - BrowserAccessibility* result = manager->GetFromRendererID(target_ids_[i]); + BrowserAccessibility* result = manager->GetFromID(target_ids_[i]); if (!result || !result->instance_active()) { *n_targets = 0; break; @@ -138,7 +138,7 @@ STDMETHODIMP BrowserAccessibilityRelation::get_target(long target_index, BrowserAccessibilityManager* manager = owner_->manager(); BrowserAccessibility* result = - manager->GetFromRendererID(target_ids_[target_index]); + manager->GetFromID(target_ids_[target_index]); if (!result || !result->instance_active()) return E_FAIL; @@ -471,7 +471,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_accName(VARIANT var_id, BSTR* name) { if (target->GetIntAttribute(ui::AX_ATTR_TITLE_UI_ELEMENT, &title_elem_id)) { BrowserAccessibility* title_elem = - manager()->GetFromRendererID(title_elem_id); + manager()->GetFromID(title_elem_id); if (title_elem) name_str = title_elem->GetTextRecursive(); } @@ -1055,7 +1055,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_accessibleAt( DCHECK_EQ(columns * rows, static_cast(cell_ids.size())); int cell_id = cell_ids[row * columns + column]; - BrowserAccessibilityWin* cell = GetFromRendererID(cell_id); + BrowserAccessibilityWin* cell = GetFromID(cell_id); if (cell) { *accessible = static_cast(cell->NewReference()); return S_OK; @@ -1141,7 +1141,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_columnDescription(long column, for (int i = 0; i < rows; ++i) { int cell_id = cell_ids[i * columns + column]; BrowserAccessibilityWin* cell = static_cast( - manager()->GetFromRendererID(cell_id)); + manager()->GetFromID(cell_id)); if (cell && cell->GetRole() == ui::AX_ROLE_COLUMN_HEADER) { base::string16 cell_name = cell->GetString16Attribute( ui::AX_ATTR_NAME); @@ -1185,7 +1185,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_columnExtentAt( ui::AX_ATTR_CELL_IDS); int cell_id = cell_ids[row * columns + column]; BrowserAccessibilityWin* cell = static_cast( - manager()->GetFromRendererID(cell_id)); + manager()->GetFromID(cell_id)); int colspan; if (cell && cell->GetIntAttribute( @@ -1223,7 +1223,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_columnIndex(long cell_index, int cell_id = unique_cell_ids[cell_index]; BrowserAccessibilityWin* cell = - manager()->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin(); + manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin(); int col_index; if (cell && cell->GetIntAttribute( @@ -1328,7 +1328,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowDescription(long row, for (int i = 0; i < columns; ++i) { int cell_id = cell_ids[row * columns + i]; BrowserAccessibilityWin* cell = - manager()->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin(); + manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin(); if (cell && cell->GetRole() == ui::AX_ROLE_ROW_HEADER) { base::string16 cell_name = cell->GetString16Attribute( ui::AX_ATTR_NAME); @@ -1371,7 +1371,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowExtentAt(long row, ui::AX_ATTR_CELL_IDS); int cell_id = cell_ids[row * columns + column]; BrowserAccessibilityWin* cell = - manager()->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin(); + manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin(); int rowspan; if (cell && cell->GetIntAttribute( @@ -1409,7 +1409,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowIndex(long cell_index, int cell_id = unique_cell_ids[cell_index]; BrowserAccessibilityWin* cell = - manager()->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin(); + manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin(); int cell_row_index; if (cell && cell->GetIntAttribute( @@ -1538,7 +1538,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowColumnExtentsAtIndex( int cell_id = unique_cell_ids[index]; BrowserAccessibilityWin* cell = - manager()->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin(); + manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin(); int rowspan; int colspan; if (cell && @@ -1676,7 +1676,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_columnHeaderCells( for (int i = 0; i < rows; ++i) { int cell_id = cell_ids[i * columns + column]; BrowserAccessibilityWin* cell = - manager()->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin(); + manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin(); if (cell && cell->GetRole() == ui::AX_ROLE_COLUMN_HEADER) (*n_column_header_cells)++; } @@ -1686,7 +1686,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_columnHeaderCells( int index = 0; for (int i = 0; i < rows; ++i) { int cell_id = cell_ids[i * columns + column]; - BrowserAccessibility* cell = manager()->GetFromRendererID(cell_id); + BrowserAccessibility* cell = manager()->GetFromID(cell_id); if (cell && cell->GetRole() == ui::AX_ROLE_COLUMN_HEADER) { (*cell_accessibles)[index] = static_cast( cell->ToBrowserAccessibilityWin()->NewReference()); @@ -1773,7 +1773,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowHeaderCells( for (int i = 0; i < columns; ++i) { int cell_id = cell_ids[row * columns + i]; - BrowserAccessibility* cell = manager()->GetFromRendererID(cell_id); + BrowserAccessibility* cell = manager()->GetFromID(cell_id); if (cell && cell->GetRole() == ui::AX_ROLE_ROW_HEADER) (*n_row_header_cells)++; } @@ -1783,7 +1783,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowHeaderCells( int index = 0; for (int i = 0; i < columns; ++i) { int cell_id = cell_ids[row * columns + i]; - BrowserAccessibility* cell = manager()->GetFromRendererID(cell_id); + BrowserAccessibility* cell = manager()->GetFromID(cell_id); if (cell && cell->GetRole() == ui::AX_ROLE_ROW_HEADER) { (*cell_accessibles)[index] = static_cast( cell->ToBrowserAccessibilityWin()->NewReference()); @@ -2897,9 +2897,9 @@ HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface( // Private methods. // -// Initialize this object and mark it as active. -void BrowserAccessibilityWin::PreInitialize() { - BrowserAccessibility::PreInitialize(); +// Called every time this node's data changes. +void BrowserAccessibilityWin::OnDataChanged() { + BrowserAccessibility::OnDataChanged(); InitRoleAndState(); @@ -3078,9 +3078,7 @@ void BrowserAccessibilityWin::PreInitialize() { } } -void BrowserAccessibilityWin::PostInitialize() { - BrowserAccessibility::PostInitialize(); - +void BrowserAccessibilityWin::OnUpdateFinished() { // Construct the hypertext for this node. hyperlink_offset_to_index_.clear(); hyperlinks_.clear(); @@ -3174,8 +3172,7 @@ bool BrowserAccessibilityWin::IsNative() const { return true; } -void BrowserAccessibilityWin::SetLocation(const gfx::Rect& new_location) { - BrowserAccessibility::SetLocation(new_location); +void BrowserAccessibilityWin::OnLocationChanged() const { manager()->ToBrowserAccessibilityManagerWin()->MaybeCallNotifyWinEvent( EVENT_OBJECT_LOCATIONCHANGE, unique_id_win()); } @@ -3301,9 +3298,8 @@ LONG BrowserAccessibilityWin::FindBoundary( text, line_breaks, boundary, start_offset, direction); } -BrowserAccessibilityWin* BrowserAccessibilityWin::GetFromRendererID( - int32 renderer_id) { - return manager()->GetFromRendererID(renderer_id)->ToBrowserAccessibilityWin(); +BrowserAccessibilityWin* BrowserAccessibilityWin::GetFromID(int32 id) { + return manager()->GetFromID(id)->ToBrowserAccessibilityWin(); } void BrowserAccessibilityWin::InitRoleAndState() { diff --git a/content/browser/accessibility/browser_accessibility_win.h b/content/browser/accessibility/browser_accessibility_win.h index 137f8b962b6d..914d5c81d886 100644 --- a/content/browser/accessibility/browser_accessibility_win.h +++ b/content/browser/accessibility/browser_accessibility_win.h @@ -100,13 +100,12 @@ BrowserAccessibilityWin // // BrowserAccessibility methods. // - CONTENT_EXPORT virtual void PreInitialize() OVERRIDE; - CONTENT_EXPORT virtual void PostInitialize() OVERRIDE; + CONTENT_EXPORT virtual void OnDataChanged() OVERRIDE; + CONTENT_EXPORT virtual void OnUpdateFinished() OVERRIDE; CONTENT_EXPORT virtual void NativeAddReference() OVERRIDE; CONTENT_EXPORT virtual void NativeReleaseReference() OVERRIDE; CONTENT_EXPORT virtual bool IsNative() const OVERRIDE; - CONTENT_EXPORT virtual void SetLocation(const gfx::Rect& new_location) - OVERRIDE; + CONTENT_EXPORT virtual void OnLocationChanged() const OVERRIDE; // // IAccessible methods. @@ -834,9 +833,9 @@ BrowserAccessibilityWin LONG start_offset, ui::TextBoundaryDirection direction); - // Return a pointer to the object corresponding to the given renderer_id, + // Return a pointer to the object corresponding to the given id, // does not make a new reference. - BrowserAccessibilityWin* GetFromRendererID(int32 renderer_id); + BrowserAccessibilityWin* GetFromID(int32 id); // Windows-specific unique ID (unique within the browser process), // used for get_accChild, NotifyWinEvent, and as the unique ID for diff --git a/content/browser/accessibility/browser_accessibility_win_unittest.cc b/content/browser/accessibility/browser_accessibility_win_unittest.cc index 09704ea6543f..eca0d911711b 100644 --- a/content/browser/accessibility/browser_accessibility_win_unittest.cc +++ b/content/browser/accessibility/browser_accessibility_win_unittest.cc @@ -141,8 +141,8 @@ TEST_F(BrowserAccessibilityTest, TestNoLeaks) { CountedBrowserAccessibility::reset(); scoped_ptr manager( BrowserAccessibilityManager::Create( - root, NULL, new CountedBrowserAccessibilityFactory())); - manager->UpdateNodesForTesting(button, checkbox); + MakeAXTreeUpdate(root, button, checkbox), + NULL, new CountedBrowserAccessibilityFactory())); ASSERT_EQ(3, CountedBrowserAccessibility::num_instances()); // Delete the manager and test that all 3 instances are deleted. @@ -152,8 +152,8 @@ TEST_F(BrowserAccessibilityTest, TestNoLeaks) { // 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.reset(BrowserAccessibilityManager::Create( - root, NULL, new CountedBrowserAccessibilityFactory())); - manager->UpdateNodesForTesting(button, checkbox); + MakeAXTreeUpdate(root, button, checkbox), + NULL, new CountedBrowserAccessibilityFactory())); ASSERT_EQ(3, CountedBrowserAccessibility::num_instances()); IAccessible* root_accessible = manager->GetRoot()->ToBrowserAccessibilityWin(); @@ -202,8 +202,8 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChange) { CountedBrowserAccessibility::reset(); scoped_ptr manager( BrowserAccessibilityManager::Create( - root, NULL, new CountedBrowserAccessibilityFactory())); - manager->UpdateNodesForTesting(text); + MakeAXTreeUpdate(root, text), + NULL, new CountedBrowserAccessibilityFactory())); // Query for the text IAccessible and verify that it returns "old text" as its // value. @@ -298,8 +298,8 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChangeNoLeaks) { CountedBrowserAccessibility::reset(); scoped_ptr manager( BrowserAccessibilityManager::Create( - root, NULL, new CountedBrowserAccessibilityFactory())); - manager->UpdateNodesForTesting(div, text3, text4); + MakeAXTreeUpdate(root, div, text3, text4), + NULL, new CountedBrowserAccessibilityFactory())); ASSERT_EQ(4, CountedBrowserAccessibility::num_instances()); // Notify the BrowserAccessibilityManager that the div node and its children @@ -342,8 +342,8 @@ TEST_F(BrowserAccessibilityTest, TestTextBoundaries) { CountedBrowserAccessibility::reset(); scoped_ptr manager( BrowserAccessibilityManager::Create( - root, NULL, new CountedBrowserAccessibilityFactory())); - manager->UpdateNodesForTesting(text1); + MakeAXTreeUpdate(root, text1), + NULL, new CountedBrowserAccessibilityFactory())); ASSERT_EQ(2, CountedBrowserAccessibility::num_instances()); BrowserAccessibilityWin* root_obj = @@ -442,8 +442,8 @@ TEST_F(BrowserAccessibilityTest, TestSimpleHypertext) { CountedBrowserAccessibility::reset(); scoped_ptr manager( BrowserAccessibilityManager::Create( - root, NULL, new CountedBrowserAccessibilityFactory())); - manager->UpdateNodesForTesting(root, text1, text2); + MakeAXTreeUpdate(root, root, text1, text2), + NULL, new CountedBrowserAccessibilityFactory())); ASSERT_EQ(3, CountedBrowserAccessibility::num_instances()); BrowserAccessibilityWin* root_obj = @@ -532,11 +532,10 @@ TEST_F(BrowserAccessibilityTest, TestComplexHypertext) { CountedBrowserAccessibility::reset(); scoped_ptr manager( BrowserAccessibilityManager::Create( - root, NULL, new CountedBrowserAccessibilityFactory())); - manager->UpdateNodesForTesting(root, - text1, button1, button1_text, - text2, link1, link1_text); - + MakeAXTreeUpdate(root, + text1, button1, button1_text, + text2, link1, link1_text), + NULL, new CountedBrowserAccessibilityFactory())); ASSERT_EQ(7, CountedBrowserAccessibility::num_instances()); BrowserAccessibilityWin* root_obj = @@ -643,7 +642,7 @@ TEST_F(BrowserAccessibilityTest, TestCreateEmptyDocument) { manager->OnAccessibilityEvents(params); // Save for later comparison. - BrowserAccessibility* acc1_2 = manager->GetFromRendererID(2); + BrowserAccessibility* acc1_2 = manager->GetFromID(2); // Verify the root has changed. EXPECT_NE(root, manager->GetRoot()); @@ -670,7 +669,7 @@ TEST_F(BrowserAccessibilityTest, TestCreateEmptyDocument) { // Fire another load complete. manager->OnAccessibilityEvents(params); - BrowserAccessibility* acc2_2 = manager->GetFromRendererID(3); + BrowserAccessibility* acc2_2 = manager->GetFromID(3); // Verify the root has changed. EXPECT_NE(root, manager->GetRoot()); diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm index 3864c2a6c34d..fa4b79845af3 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm @@ -3467,7 +3467,7 @@ SkBitmap::Config RenderWidgetHostViewMac::PreferredReadbackFormat() { // method returns. BrowserAccessibilityManager* manager = renderWidgetHostView_->GetBrowserAccessibilityManager(); - manager->SetFocus(manager->GetFromRendererID(accessibilityObjectId), false); + manager->SetFocus(manager->GetFromID(accessibilityObjectId), false); } } diff --git a/ui/accessibility/ax_node.cc b/ui/accessibility/ax_node.cc index 8adb9409051f..587f7375d749 100644 --- a/ui/accessibility/ax_node.cc +++ b/ui/accessibility/ax_node.cc @@ -19,6 +19,10 @@ void AXNode::SetData(const AXNodeData& src) { data_ = src; } +void AXNode::SetLocation(const gfx::Rect& new_location) { + data_.location = new_location; +} + void AXNode::SetIndexInParent(int index_in_parent) { index_in_parent_ = index_in_parent; } @@ -31,4 +35,13 @@ void AXNode::Destroy() { delete this; } +bool AXNode::IsDescendantOf(AXNode* ancestor) { + if (this == ancestor) + return true; + else if (parent()) + return parent()->IsDescendantOf(ancestor); + + return false; +} + } // namespace ui diff --git a/ui/accessibility/ax_node.h b/ui/accessibility/ax_node.h index b7e31257b968..5da73401c535 100644 --- a/ui/accessibility/ax_node.h +++ b/ui/accessibility/ax_node.h @@ -24,27 +24,36 @@ class AX_EXPORT AXNode { int child_count() const { return static_cast(children_.size()); } const AXNodeData& data() const { return data_; } const std::vector& children() const { return children_; } + int index_in_parent() const { return index_in_parent_; } // Get the child at the given index. AXNode* ChildAtIndex(int index) const { return children_[index]; } // Set the node's accessibility data. This may be done during initial // initialization or later when the node data changes. - virtual void SetData(const AXNodeData& src); + void SetData(const AXNodeData& src); + + // Update this node's location. This is separate from SetData just because + // changing only the location is common and should be more efficient than + // re-copying all of the data. + void SetLocation(const gfx::Rect& new_location); // Set the index in parent, for example if siblings were inserted or deleted. void SetIndexInParent(int index_in_parent); // Swap the internal children vector with |children|. This instance // now owns all of the passed children. - virtual void SwapChildren(std::vector& children); + void SwapChildren(std::vector& children); // This is called when the AXTree no longer includes this node in the // tree. Reference counting is used on some platforms because the // operating system may hold onto a reference to an AXNode // object even after we're through with it, so this may decrement the // reference count and clear out the object's data. - virtual void Destroy(); + void Destroy(); + + // Return true if this object is equal to or a descendant of |ancestor|. + bool IsDescendantOf(AXNode* ancestor); private: int index_in_parent_; diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc index f2ccdcba3777..c0ec9ac8c49f 100644 --- a/ui/accessibility/ax_tree.cc +++ b/ui/accessibility/ax_tree.cc @@ -45,7 +45,7 @@ AXTreeDelegate::~AXTreeDelegate() { AXTree::AXTree() : delegate_(NULL), root_(NULL) { AXNodeData root; - root.id = 0; + root.id = -1; root.role = AX_ROLE_ROOT_WEB_AREA; AXTreeUpdate initial_state; @@ -117,10 +117,10 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) { for (size_t i = 0; i < update.nodes.size(); ++i) { AXNode* node = GetFromId(update.nodes[i].id); if (update_state.new_nodes.find(node) != update_state.new_nodes.end()) { - delegate_->OnNodeCreated(node); + delegate_->OnNodeCreationFinished(node); update_state.new_nodes.erase(node); } else { - delegate_->OnNodeChanged(node); + delegate_->OnNodeChangeFinished(node); } } if (root_->id() != old_root_id) @@ -134,8 +134,13 @@ std::string AXTree::ToString() const { return TreeToStringHelper(root_, 0); } -AXNode* AXTree::CreateNode(AXNode* parent, int32 id, int32 index_in_parent) { - return new AXNode(parent, id, index_in_parent); +AXNode* AXTree::CreateNode( + AXNode* parent, int32 id, int32 index_in_parent) { + AXNode* new_node = new AXNode(parent, id, index_in_parent); + id_map_[new_node->id()] = new_node; + if (delegate_) + delegate_->OnNodeCreated(new_node); + return new_node; } bool AXTree::UpdateNode( @@ -148,25 +153,31 @@ bool AXTree::UpdateNode( // of the tree is being swapped, or we're out of sync with the source // and this is a serious error. AXNode* node = GetFromId(src.id); + AXNode* new_node = NULL; if (node) { update_state->pending_nodes.erase(node); + node->SetData(src); + if (delegate_) + delegate_->OnNodeChanged(node); } else { if (src.role != AX_ROLE_ROOT_WEB_AREA) { error_ = base::StringPrintf( "%d is not in the tree and not the new root", src.id); return false; } - node = CreateAndInitializeNode(NULL, src.id, 0); + new_node = CreateNode(NULL, src.id, 0); + node = new_node; update_state->new_nodes.insert(node); + node->SetData(src); } - // Set the node's data. - node->SetData(src); - // First, delete nodes that used to be children of this node but aren't // anymore. - if (!DeleteOldChildren(node, src.child_ids)) + if (!DeleteOldChildren(node, src.child_ids)) { + if (new_node) + DestroyNodeAndSubtree(new_node); return false; + } // Now build a new children vector, reusing nodes when possible, // and swap it in. @@ -186,13 +197,6 @@ bool AXTree::UpdateNode( return success; } -AXNode* AXTree::CreateAndInitializeNode( - AXNode* parent, int32 id, int32 index_in_parent) { - AXNode* node = CreateNode(parent, id, index_in_parent); - id_map_[node->id()] = node; - return node; -} - void AXTree::DestroyNodeAndSubtree(AXNode* node) { id_map_.erase(node->id()); for (int i = 0; i < node->child_count(); ++i) @@ -251,7 +255,7 @@ bool AXTree::CreateNewChildVector(AXNode* node, } child->SetIndexInParent(index_in_parent); } else { - child = CreateAndInitializeNode(node, child_id, index_in_parent); + child = CreateNode(node, child_id, index_in_parent); update_state->pending_nodes.insert(child); update_state->new_nodes.insert(child); } diff --git a/ui/accessibility/ax_tree.h b/ui/accessibility/ax_tree.h index 6a4134cb2aa2..b4baac460ccf 100644 --- a/ui/accessibility/ax_tree.h +++ b/ui/accessibility/ax_tree.h @@ -17,6 +17,20 @@ class AXNode; struct AXTreeUpdateState; // Used when you want to be notified when changes happen to the tree. +// +// Some of the notifications are called in the middle of an update operation. +// Be careful, as the tree may be in an inconsistent state at this time; +// don't walk the parents and children at this time: +// OnNodeWillBeDeleted +// OnNodeCreated +// OnNodeChanged +// +// Other notifications are called at the end of an atomic update operation. +// From these, it's safe to walk the tree and do any initialization that +// assumes the tree is in a consistent state. +// OnNodeCreationFinished +// OnNodeChangeFinished +// OnRootChanged class AX_EXPORT AXTreeDelegate { public: AXTreeDelegate(); @@ -27,16 +41,23 @@ class AX_EXPORT AXTreeDelegate { // in the middle of an update, the tree may be in an invalid state! virtual void OnNodeWillBeDeleted(AXNode* node) = 0; - // Called after a new node is created. It's guaranteed to be called - // after it's been fully initialized, so you can rely on its data and - // links to parents and children being valid. This will be called on - // parents before it's called on their children. + // Called immediately after a new node is created. The tree may be in + // the middle of an update, don't walk the parents and children now. virtual void OnNodeCreated(AXNode* node) = 0; - // Called when a node changes its data or children. + // Called when a node changes its data or children. The tree may be in + // the middle of an update, don't walk the parents and children now. virtual void OnNodeChanged(AXNode* node) = 0; - // Called when the root node changes. + // Called for each new node at the end of an update operation, + // when the tree is in a consistent state. + virtual void OnNodeCreationFinished(AXNode* node) = 0; + + // Called for each existing node that changed at the end of an update + // operation, when the tree is in a consistent state. + virtual void OnNodeChangeFinished(AXNode* node) = 0; + + // Called at the end of an update operation when the root node changes. virtual void OnRootChanged(AXNode* new_root) = 0; }; @@ -76,10 +97,6 @@ class AX_EXPORT AXTree { void OnRootChanged(); - // Convenience function to create a node and call Initialize on it. - AXNode* CreateAndInitializeNode( - AXNode* parent, int32 id, int32 index_in_parent); - // Call Destroy() on |node|, and delete it from the id map, and then // call recursively on all nodes in its subtree. void DestroyNodeAndSubtree(AXNode* node); diff --git a/ui/accessibility/ax_tree_unittest.cc b/ui/accessibility/ax_tree_unittest.cc index 0001474577d1..9d734f883fcc 100644 --- a/ui/accessibility/ax_tree_unittest.cc +++ b/ui/accessibility/ax_tree_unittest.cc @@ -28,18 +28,31 @@ class FakeAXTreeDelegate : public AXTreeDelegate { changed_ids_.push_back(node->id()); } + virtual void OnNodeCreationFinished(AXNode* node) OVERRIDE { + creation_finished_ids_.push_back(node->id()); + } + + virtual void OnNodeChangeFinished(AXNode* node) OVERRIDE { + change_finished_ids_.push_back(node->id()); + } + virtual void OnRootChanged(AXNode* new_root) OVERRIDE { new_root_ids_.push_back(new_root->id()); } const std::vector& deleted_ids() { return deleted_ids_; } const std::vector& created_ids() { return created_ids_; } + const std::vector& creation_finished_ids() { + return creation_finished_ids_; + } const std::vector& new_root_ids() { return new_root_ids_; } private: std::vector deleted_ids_; std::vector created_ids_; + std::vector creation_finished_ids_; std::vector changed_ids_; + std::vector change_finished_ids_; std::vector new_root_ids_; }; @@ -272,6 +285,10 @@ TEST(AXTreeTest, TreeDelegateIsCalled) { EXPECT_EQ(2, fake_delegate.created_ids()[0]); EXPECT_EQ(3, fake_delegate.created_ids()[1]); + ASSERT_EQ(2U, fake_delegate.creation_finished_ids().size()); + EXPECT_EQ(2, fake_delegate.creation_finished_ids()[0]); + EXPECT_EQ(3, fake_delegate.creation_finished_ids()[1]); + ASSERT_EQ(1U, fake_delegate.new_root_ids().size()); EXPECT_EQ(2, fake_delegate.new_root_ids()[0]); -- 2.11.4.GIT