| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/accessibility/browser_accessibility.h" |
| |
| #include "base/logging.h" |
| #include "base/string_number_conversions.h" |
| #include "chrome/browser/accessibility/browser_accessibility_manager.h" |
| |
| #if defined(OS_LINUX) |
| // There's no OS-specific implementation of BrowserAccessibilityManager |
| // on Linux, so just instantiate the base class. |
| // static |
| BrowserAccessibility* BrowserAccessibility::Create() { |
| return new BrowserAccessibility(); |
| } |
| #endif |
| |
| BrowserAccessibility::BrowserAccessibility() |
| : manager_(NULL), |
| parent_(NULL), |
| child_id_(0), |
| index_in_parent_(0), |
| renderer_id_(0), |
| ref_count_(1), |
| role_(0), |
| state_(0), |
| instance_active_(false) { |
| } |
| |
| BrowserAccessibility::~BrowserAccessibility() { |
| } |
| |
| void BrowserAccessibility::ReplaceChild( |
| BrowserAccessibility* old_acc, BrowserAccessibility* new_acc) { |
| DCHECK_EQ(children_[old_acc->index_in_parent_], old_acc); |
| |
| old_acc = children_[old_acc->index_in_parent_]; |
| children_[old_acc->index_in_parent_] = new_acc; |
| } |
| |
| void BrowserAccessibility::Initialize( |
| BrowserAccessibilityManager* manager, |
| BrowserAccessibility* parent, |
| int32 child_id, |
| int32 index_in_parent, |
| const webkit_glue::WebAccessibility& src) { |
| manager_ = manager; |
| parent_ = parent; |
| child_id_ = child_id; |
| index_in_parent_ = index_in_parent; |
| |
| renderer_id_ = src.id; |
| name_ = src.name; |
| value_ = src.value; |
| attributes_ = src.attributes; |
| html_attributes_ = src.html_attributes; |
| location_ = src.location; |
| role_ = src.role; |
| state_ = src.state; |
| indirect_child_ids_ = src.indirect_child_ids; |
| |
| Initialize(); |
| } |
| |
| void BrowserAccessibility::Initialize() { |
| instance_active_ = true; |
| } |
| |
| void BrowserAccessibility::AddChild(BrowserAccessibility* child) { |
| children_.push_back(child); |
| } |
| |
| void BrowserAccessibility::DetachTree( |
| std::vector<BrowserAccessibility*>* nodes) { |
| nodes->push_back(this); |
| for (size_t i = 0; i < children_.size(); i++) |
| children_[i]->DetachTree(nodes); |
| children_.clear(); |
| parent_ = NULL; |
| } |
| |
| void BrowserAccessibility::UpdateParent(BrowserAccessibility* parent, |
| int index_in_parent) { |
| parent_ = parent; |
| index_in_parent_ = index_in_parent; |
| } |
| |
| bool BrowserAccessibility::IsDescendantOf( |
| BrowserAccessibility* ancestor) { |
| if (this == ancestor) { |
| return true; |
| } else if (parent_) { |
| return parent_->IsDescendantOf(ancestor); |
| } |
| |
| return false; |
| } |
| |
| BrowserAccessibility* BrowserAccessibility::GetChild(uint32 child_index) { |
| DCHECK(child_index < children_.size()); |
| return children_[child_index]; |
| } |
| |
| BrowserAccessibility* BrowserAccessibility::GetPreviousSibling() { |
| if (parent_ && index_in_parent_ > 0) |
| return parent_->children_[index_in_parent_ - 1]; |
| |
| return NULL; |
| } |
| |
| BrowserAccessibility* BrowserAccessibility::GetNextSibling() { |
| if (parent_ && |
| index_in_parent_ >= 0 && |
| index_in_parent_ < static_cast<int>(parent_->children_.size() - 1)) { |
| return parent_->children_[index_in_parent_ + 1]; |
| } |
| |
| return NULL; |
| } |
| |
| gfx::Rect BrowserAccessibility::GetBoundsRect() { |
| gfx::Rect bounds = location_; |
| |
| // Adjust the bounds by the top left corner of the containing view's bounds |
| // in screen coordinates. |
| gfx::Point top_left = manager_->GetViewBounds().origin(); |
| bounds.Offset(top_left); |
| |
| // Adjust top left position by the root document's scroll offset. |
| BrowserAccessibility* root = manager_->GetRoot(); |
| int scroll_x = 0; |
| int scroll_y = 0; |
| root->GetAttributeAsInt( |
| WebAccessibility::ATTR_DOC_SCROLLX, &scroll_x); |
| root->GetAttributeAsInt( |
| WebAccessibility::ATTR_DOC_SCROLLY, &scroll_y); |
| bounds.Offset(-scroll_x, -scroll_y); |
| |
| return bounds; |
| } |
| |
| BrowserAccessibility* BrowserAccessibility::BrowserAccessibilityForPoint( |
| const gfx::Point& point) { |
| // Walk the children recursively looking for the BrowserAccessibility that |
| // most tightly encloses the specified point. |
| for (int i = children_.size() - 1; i >= 0; --i) { |
| BrowserAccessibility* child = children_[i]; |
| if (child->GetBoundsRect().Contains(point)) |
| return child->BrowserAccessibilityForPoint(point); |
| } |
| return this; |
| } |
| |
| void BrowserAccessibility::InternalAddReference() { |
| ref_count_++; |
| } |
| |
| void BrowserAccessibility::InternalReleaseReference(bool recursive) { |
| DCHECK_GT(ref_count_, 0); |
| |
| if (recursive || ref_count_ == 1) { |
| for (std::vector<BrowserAccessibility*>::iterator iter = children_.begin(); |
| iter != children_.end(); |
| ++iter) { |
| (*iter)->InternalReleaseReference(true); |
| } |
| } |
| |
| ref_count_--; |
| if (ref_count_ == 0) { |
| instance_active_ = false; |
| children_.clear(); |
| manager_->Remove(child_id_, renderer_id_); |
| NativeReleaseReference(); |
| } |
| } |
| |
| void BrowserAccessibility::NativeReleaseReference() { |
| delete this; |
| } |
| |
| bool BrowserAccessibility::HasAttribute( |
| WebAccessibility::Attribute attribute) { |
| return (attributes_.find(attribute) != attributes_.end()); |
| } |
| |
| bool BrowserAccessibility::GetAttribute( |
| WebAccessibility::Attribute attribute, string16* value) { |
| std::map<int32, string16>::iterator iter = attributes_.find(attribute); |
| if (iter != attributes_.end()) { |
| *value = iter->second; |
| return true; |
| } |
| |
| return false; |
| } |
| |
| bool BrowserAccessibility::GetAttributeAsInt( |
| WebAccessibility::Attribute attribute, int* value_int) { |
| string16 value_str; |
| |
| if (!GetAttribute(attribute, &value_str)) |
| return false; |
| |
| if (!base::StringToInt(value_str, value_int)) |
| return false; |
| |
| return true; |
| } |