// 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;
}