1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/accessibility/browser_accessibility.h"
6
7#include "base/logging.h"
8#include "base/string_number_conversions.h"
9#include "chrome/browser/accessibility/browser_accessibility_manager.h"
10
11#if defined(OS_LINUX)
12// There's no OS-specific implementation of BrowserAccessibilityManager
13// on Linux, so just instantiate the base class.
14// static
15BrowserAccessibility* BrowserAccessibility::Create() {
16  return new BrowserAccessibility();
17}
18#endif
19
20BrowserAccessibility::BrowserAccessibility()
21    : manager_(NULL),
22      parent_(NULL),
23      child_id_(0),
24      index_in_parent_(0),
25      renderer_id_(0),
26      ref_count_(1),
27      role_(0),
28      state_(0),
29      instance_active_(false) {
30}
31
32BrowserAccessibility::~BrowserAccessibility() {
33}
34
35void BrowserAccessibility::ReplaceChild(
36    BrowserAccessibility* old_acc, BrowserAccessibility* new_acc) {
37  DCHECK_EQ(children_[old_acc->index_in_parent_], old_acc);
38
39  old_acc = children_[old_acc->index_in_parent_];
40  children_[old_acc->index_in_parent_] = new_acc;
41}
42
43void BrowserAccessibility::Initialize(
44    BrowserAccessibilityManager* manager,
45    BrowserAccessibility* parent,
46    int32 child_id,
47    int32 index_in_parent,
48    const webkit_glue::WebAccessibility& src) {
49  manager_ = manager;
50  parent_ = parent;
51  child_id_ = child_id;
52  index_in_parent_ = index_in_parent;
53
54  renderer_id_ = src.id;
55  name_ = src.name;
56  value_ = src.value;
57  attributes_ = src.attributes;
58  html_attributes_ = src.html_attributes;
59  location_ = src.location;
60  role_ = src.role;
61  state_ = src.state;
62  indirect_child_ids_ = src.indirect_child_ids;
63
64  Initialize();
65}
66
67void BrowserAccessibility::Initialize() {
68  instance_active_ = true;
69}
70
71void BrowserAccessibility::AddChild(BrowserAccessibility* child) {
72  children_.push_back(child);
73}
74
75void BrowserAccessibility::DetachTree(
76    std::vector<BrowserAccessibility*>* nodes) {
77  nodes->push_back(this);
78  for (size_t i = 0; i < children_.size(); i++)
79    children_[i]->DetachTree(nodes);
80  children_.clear();
81  parent_ = NULL;
82}
83
84void BrowserAccessibility::UpdateParent(BrowserAccessibility* parent,
85                                        int index_in_parent) {
86  parent_ = parent;
87  index_in_parent_ = index_in_parent;
88}
89
90bool BrowserAccessibility::IsDescendantOf(
91    BrowserAccessibility* ancestor) {
92  if (this == ancestor) {
93    return true;
94  } else if (parent_) {
95    return parent_->IsDescendantOf(ancestor);
96  }
97
98  return false;
99}
100
101BrowserAccessibility* BrowserAccessibility::GetChild(uint32 child_index) {
102  DCHECK(child_index < children_.size());
103  return children_[child_index];
104}
105
106BrowserAccessibility* BrowserAccessibility::GetPreviousSibling() {
107  if (parent_ && index_in_parent_ > 0)
108    return parent_->children_[index_in_parent_ - 1];
109
110  return NULL;
111}
112
113BrowserAccessibility* BrowserAccessibility::GetNextSibling() {
114  if (parent_ &&
115      index_in_parent_ >= 0 &&
116      index_in_parent_ < static_cast<int>(parent_->children_.size() - 1)) {
117    return parent_->children_[index_in_parent_ + 1];
118  }
119
120  return NULL;
121}
122
123gfx::Rect BrowserAccessibility::GetBoundsRect() {
124  gfx::Rect bounds = location_;
125
126  // Adjust the bounds by the top left corner of the containing view's bounds
127  // in screen coordinates.
128  gfx::Point top_left = manager_->GetViewBounds().origin();
129  bounds.Offset(top_left);
130
131  // Adjust top left position by the root document's scroll offset.
132  BrowserAccessibility* root = manager_->GetRoot();
133  int scroll_x = 0;
134  int scroll_y = 0;
135  root->GetAttributeAsInt(
136    WebAccessibility::ATTR_DOC_SCROLLX, &scroll_x);
137  root->GetAttributeAsInt(
138    WebAccessibility::ATTR_DOC_SCROLLY, &scroll_y);
139  bounds.Offset(-scroll_x, -scroll_y);
140
141  return bounds;
142}
143
144BrowserAccessibility* BrowserAccessibility::BrowserAccessibilityForPoint(
145    const gfx::Point& point) {
146  // Walk the children recursively looking for the BrowserAccessibility that
147  // most tightly encloses the specified point.
148  for (int i = children_.size() - 1; i >= 0; --i) {
149    BrowserAccessibility* child = children_[i];
150    if (child->GetBoundsRect().Contains(point))
151      return child->BrowserAccessibilityForPoint(point);
152  }
153  return this;
154}
155
156void BrowserAccessibility::InternalAddReference() {
157  ref_count_++;
158}
159
160void BrowserAccessibility::InternalReleaseReference(bool recursive) {
161  DCHECK_GT(ref_count_, 0);
162
163  if (recursive || ref_count_ == 1) {
164    for (std::vector<BrowserAccessibility*>::iterator iter = children_.begin();
165         iter != children_.end();
166         ++iter) {
167      (*iter)->InternalReleaseReference(true);
168    }
169  }
170
171  ref_count_--;
172  if (ref_count_ == 0) {
173    instance_active_ = false;
174    children_.clear();
175    manager_->Remove(child_id_, renderer_id_);
176    NativeReleaseReference();
177  }
178}
179
180void BrowserAccessibility::NativeReleaseReference() {
181  delete this;
182}
183
184bool BrowserAccessibility::HasAttribute(
185    WebAccessibility::Attribute attribute) {
186  return (attributes_.find(attribute) != attributes_.end());
187}
188
189bool BrowserAccessibility::GetAttribute(
190    WebAccessibility::Attribute attribute, string16* value) {
191  std::map<int32, string16>::iterator iter = attributes_.find(attribute);
192  if (iter != attributes_.end()) {
193    *value = iter->second;
194    return true;
195  }
196
197  return false;
198}
199
200bool BrowserAccessibility::GetAttributeAsInt(
201    WebAccessibility::Attribute attribute, int* value_int) {
202  string16 value_str;
203
204  if (!GetAttribute(attribute, &value_str))
205    return false;
206
207  if (!base::StringToInt(value_str, value_int))
208    return false;
209
210  return true;
211}
212