IndexedDBFactory now ForceCloses databases.
[chromium-blink-merge.git] / content / browser / accessibility / browser_accessibility.cc
blob452f01b2560f281dd6d092edc34665dc5cff161e
1 // Copyright (c) 2012 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.
5 #include "content/browser/accessibility/browser_accessibility.h"
7 #include "base/logging.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "content/browser/accessibility/browser_accessibility_manager.h"
12 #include "content/common/accessibility_messages.h"
14 namespace content {
16 #if !defined(OS_MACOSX) && \
17 !defined(OS_WIN) && \
18 !defined(TOOLKIT_GTK) && \
19 !defined(OS_ANDROID)
20 // We have subclassess of BrowserAccessibility on Mac, Linux/GTK,
21 // and Win. For any other platform, instantiate the base class.
22 // static
23 BrowserAccessibility* BrowserAccessibility::Create() {
24 return new BrowserAccessibility();
26 #endif
28 BrowserAccessibility::BrowserAccessibility()
29 : manager_(NULL),
30 parent_(NULL),
31 index_in_parent_(0),
32 renderer_id_(0),
33 role_(0),
34 state_(0),
35 instance_active_(false) {
38 BrowserAccessibility::~BrowserAccessibility() {
41 bool BrowserAccessibility::PlatformIsLeaf() const {
42 if (child_count() == 0)
43 return true;
45 // All of these roles may have children that we use as internal
46 // implementation details, but we want to expose them as leaves
47 // to platform accessibility APIs.
48 switch (role_) {
49 case ui::AX_ROLE_EDITABLE_TEXT:
50 case ui::AX_ROLE_SLIDER:
51 case ui::AX_ROLE_STATIC_TEXT:
52 case ui::AX_ROLE_TEXT_AREA:
53 case ui::AX_ROLE_TEXT_FIELD:
54 return true;
55 default:
56 return false;
60 uint32 BrowserAccessibility::PlatformChildCount() const {
61 return PlatformIsLeaf() ? 0 : children_.size();
64 void BrowserAccessibility::DetachTree(
65 std::vector<BrowserAccessibility*>* nodes) {
66 nodes->push_back(this);
67 for (size_t i = 0; i < children_.size(); ++i)
68 children_[i]->DetachTree(nodes);
69 children_.clear();
70 parent_ = NULL;
73 void BrowserAccessibility::InitializeTreeStructure(
74 BrowserAccessibilityManager* manager,
75 BrowserAccessibility* parent,
76 int32 renderer_id,
77 int32 index_in_parent) {
78 manager_ = manager;
79 parent_ = parent;
80 renderer_id_ = renderer_id;
81 index_in_parent_ = index_in_parent;
84 void BrowserAccessibility::InitializeData(const ui::AXNodeData& src) {
85 DCHECK_EQ(renderer_id_, src.id);
86 role_ = src.role;
87 state_ = src.state;
88 string_attributes_ = src.string_attributes;
89 int_attributes_ = src.int_attributes;
90 float_attributes_ = src.float_attributes;
91 bool_attributes_ = src.bool_attributes;
92 intlist_attributes_ = src.intlist_attributes;
93 html_attributes_ = src.html_attributes;
94 location_ = src.location;
95 instance_active_ = true;
97 GetStringAttribute(ui::AX_ATTR_NAME, &name_);
98 GetStringAttribute(ui::AX_ATTR_VALUE, &value_);
100 PreInitialize();
103 bool BrowserAccessibility::IsNative() const {
104 return false;
107 void BrowserAccessibility::SwapChildren(
108 std::vector<BrowserAccessibility*>& children) {
109 children.swap(children_);
112 void BrowserAccessibility::UpdateParent(BrowserAccessibility* parent,
113 int index_in_parent) {
114 parent_ = parent;
115 index_in_parent_ = index_in_parent;
118 void BrowserAccessibility::SetLocation(const gfx::Rect& new_location) {
119 location_ = new_location;
122 bool BrowserAccessibility::IsDescendantOf(
123 BrowserAccessibility* ancestor) {
124 if (this == ancestor) {
125 return true;
126 } else if (parent_) {
127 return parent_->IsDescendantOf(ancestor);
130 return false;
133 BrowserAccessibility* BrowserAccessibility::PlatformGetChild(
134 uint32 child_index) const {
135 DCHECK(child_index < children_.size());
136 return children_[child_index];
139 BrowserAccessibility* BrowserAccessibility::GetPreviousSibling() {
140 if (parent_ && index_in_parent_ > 0)
141 return parent_->children_[index_in_parent_ - 1];
143 return NULL;
146 BrowserAccessibility* BrowserAccessibility::GetNextSibling() {
147 if (parent_ &&
148 index_in_parent_ >= 0 &&
149 index_in_parent_ < static_cast<int>(parent_->children_.size() - 1)) {
150 return parent_->children_[index_in_parent_ + 1];
153 return NULL;
156 gfx::Rect BrowserAccessibility::GetLocalBoundsRect() const {
157 gfx::Rect bounds = location_;
159 // Walk up the parent chain. Every time we encounter a Web Area, offset
160 // based on the scroll bars and then offset based on the origin of that
161 // nested web area.
162 BrowserAccessibility* parent = parent_;
163 bool need_to_offset_web_area =
164 (role_ == ui::AX_ROLE_WEB_AREA ||
165 role_ == ui::AX_ROLE_ROOT_WEB_AREA);
166 while (parent) {
167 if (need_to_offset_web_area &&
168 parent->location().width() > 0 &&
169 parent->location().height() > 0) {
170 bounds.Offset(parent->location().x(), parent->location().y());
171 need_to_offset_web_area = false;
174 // On some platforms, we don't want to take the root scroll offsets
175 // into account.
176 if (parent->role() == ui::AX_ROLE_ROOT_WEB_AREA &&
177 !manager()->UseRootScrollOffsetsWhenComputingBounds()) {
178 break;
181 if (parent->role() == ui::AX_ROLE_WEB_AREA ||
182 parent->role() == ui::AX_ROLE_ROOT_WEB_AREA) {
183 int sx = 0;
184 int sy = 0;
185 if (parent->GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
186 parent->GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
187 bounds.Offset(-sx, -sy);
189 need_to_offset_web_area = true;
191 parent = parent->parent();
194 return bounds;
197 gfx::Rect BrowserAccessibility::GetGlobalBoundsRect() const {
198 gfx::Rect bounds = GetLocalBoundsRect();
200 // Adjust the bounds by the top left corner of the containing view's bounds
201 // in screen coordinates.
202 bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin());
204 return bounds;
207 gfx::Rect BrowserAccessibility::GetLocalBoundsForRange(int start, int len)
208 const {
209 if (role() != ui::AX_ROLE_STATIC_TEXT) {
210 // Apply recursively to all static text descendants. For example, if
211 // you call it on a div with two text node children, it just calls
212 // GetLocalBoundsForRange on each of the two children (adjusting
213 // |start| for each one) and unions the resulting rects.
214 gfx::Rect bounds;
215 for (size_t i = 0; i < children_.size(); ++i) {
216 BrowserAccessibility* child = children_[i];
217 int child_len = child->GetStaticTextLenRecursive();
218 if (start < child_len && start + len > 0) {
219 gfx::Rect child_rect = child->GetLocalBoundsForRange(start, len);
220 bounds.Union(child_rect);
222 start -= child_len;
224 return bounds;
227 int end = start + len;
228 int child_start = 0;
229 int child_end = 0;
231 gfx::Rect bounds;
232 for (size_t i = 0; i < children_.size() && child_end < start + len; ++i) {
233 BrowserAccessibility* child = children_[i];
234 DCHECK_EQ(child->role(), ui::AX_ROLE_INLINE_TEXT_BOX);
235 std::string child_text;
236 child->GetStringAttribute(ui::AX_ATTR_VALUE, &child_text);
237 int child_len = static_cast<int>(child_text.size());
238 child_start = child_end;
239 child_end += child_len;
241 if (child_end < start)
242 continue;
244 int overlap_start = std::max(start, child_start);
245 int overlap_end = std::min(end, child_end);
247 int local_start = overlap_start - child_start;
248 int local_end = overlap_end - child_start;
250 gfx::Rect child_rect = child->location();
251 int text_direction = child->GetIntAttribute(
252 ui::AX_ATTR_TEXT_DIRECTION);
253 const std::vector<int32>& character_offsets = child->GetIntListAttribute(
254 ui::AX_ATTR_CHARACTER_OFFSETS);
255 int start_pixel_offset =
256 local_start > 0 ? character_offsets[local_start - 1] : 0;
257 int end_pixel_offset =
258 local_end > 0 ? character_offsets[local_end - 1] : 0;
260 gfx::Rect child_overlap_rect;
261 switch (text_direction) {
262 case ui::AX_TEXT_DIRECTION_LR: {
263 int left = child_rect.x() + start_pixel_offset;
264 int right = child_rect.x() + end_pixel_offset;
265 child_overlap_rect = gfx::Rect(left, child_rect.y(),
266 right - left, child_rect.height());
267 break;
269 case ui::AX_TEXT_DIRECTION_RL: {
270 int right = child_rect.right() - start_pixel_offset;
271 int left = child_rect.right() - end_pixel_offset;
272 child_overlap_rect = gfx::Rect(left, child_rect.y(),
273 right - left, child_rect.height());
274 break;
276 case ui::AX_TEXT_DIRECTION_TB: {
277 int top = child_rect.y() + start_pixel_offset;
278 int bottom = child_rect.y() + end_pixel_offset;
279 child_overlap_rect = gfx::Rect(child_rect.x(), top,
280 child_rect.width(), bottom - top);
281 break;
283 case ui::AX_TEXT_DIRECTION_BT: {
284 int bottom = child_rect.bottom() - start_pixel_offset;
285 int top = child_rect.bottom() - end_pixel_offset;
286 child_overlap_rect = gfx::Rect(child_rect.x(), top,
287 child_rect.width(), bottom - top);
288 break;
290 default:
291 NOTREACHED();
294 if (bounds.width() == 0 && bounds.height() == 0)
295 bounds = child_overlap_rect;
296 else
297 bounds.Union(child_overlap_rect);
300 return bounds;
303 gfx::Rect BrowserAccessibility::GetGlobalBoundsForRange(int start, int len)
304 const {
305 gfx::Rect bounds = GetLocalBoundsForRange(start, len);
307 // Adjust the bounds by the top left corner of the containing view's bounds
308 // in screen coordinates.
309 bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin());
311 return bounds;
314 BrowserAccessibility* BrowserAccessibility::BrowserAccessibilityForPoint(
315 const gfx::Point& point) {
316 // Walk the children recursively looking for the BrowserAccessibility that
317 // most tightly encloses the specified point.
318 for (int i = static_cast<int>(PlatformChildCount()) - 1; i >= 0; --i) {
319 BrowserAccessibility* child = PlatformGetChild(i);
320 if (child->GetGlobalBoundsRect().Contains(point))
321 return child->BrowserAccessibilityForPoint(point);
323 return this;
326 void BrowserAccessibility::Destroy() {
327 for (std::vector<BrowserAccessibility*>::iterator iter = children_.begin();
328 iter != children_.end();
329 ++iter) {
330 (*iter)->Destroy();
332 children_.clear();
334 // Allow the object to fire a TextRemoved notification.
335 name_.clear();
336 value_.clear();
337 PostInitialize();
339 manager_->NotifyAccessibilityEvent(ui::AX_EVENT_HIDE, this);
341 instance_active_ = false;
342 manager_->RemoveNode(this);
343 NativeReleaseReference();
346 void BrowserAccessibility::NativeReleaseReference() {
347 delete this;
350 bool BrowserAccessibility::HasBoolAttribute(
351 ui::AXBoolAttribute attribute) const {
352 for (size_t i = 0; i < bool_attributes_.size(); ++i) {
353 if (bool_attributes_[i].first == attribute)
354 return true;
357 return false;
361 bool BrowserAccessibility::GetBoolAttribute(
362 ui::AXBoolAttribute attribute) const {
363 for (size_t i = 0; i < bool_attributes_.size(); ++i) {
364 if (bool_attributes_[i].first == attribute)
365 return bool_attributes_[i].second;
368 return false;
371 bool BrowserAccessibility::GetBoolAttribute(
372 ui::AXBoolAttribute attribute, bool* value) const {
373 for (size_t i = 0; i < bool_attributes_.size(); ++i) {
374 if (bool_attributes_[i].first == attribute) {
375 *value = bool_attributes_[i].second;
376 return true;
380 return false;
383 bool BrowserAccessibility::HasFloatAttribute(
384 ui::AXFloatAttribute attribute) const {
385 for (size_t i = 0; i < float_attributes_.size(); ++i) {
386 if (float_attributes_[i].first == attribute)
387 return true;
390 return false;
393 float BrowserAccessibility::GetFloatAttribute(
394 ui::AXFloatAttribute attribute) const {
395 for (size_t i = 0; i < float_attributes_.size(); ++i) {
396 if (float_attributes_[i].first == attribute)
397 return float_attributes_[i].second;
400 return 0.0;
403 bool BrowserAccessibility::GetFloatAttribute(
404 ui::AXFloatAttribute attribute, float* value) const {
405 for (size_t i = 0; i < float_attributes_.size(); ++i) {
406 if (float_attributes_[i].first == attribute) {
407 *value = float_attributes_[i].second;
408 return true;
412 return false;
415 bool BrowserAccessibility::HasIntAttribute(
416 ui::AXIntAttribute attribute) const {
417 for (size_t i = 0; i < int_attributes_.size(); ++i) {
418 if (int_attributes_[i].first == attribute)
419 return true;
422 return false;
425 int BrowserAccessibility::GetIntAttribute(ui::AXIntAttribute attribute) const {
426 for (size_t i = 0; i < int_attributes_.size(); ++i) {
427 if (int_attributes_[i].first == attribute)
428 return int_attributes_[i].second;
431 return 0;
434 bool BrowserAccessibility::GetIntAttribute(
435 ui::AXIntAttribute attribute, int* value) const {
436 for (size_t i = 0; i < int_attributes_.size(); ++i) {
437 if (int_attributes_[i].first == attribute) {
438 *value = int_attributes_[i].second;
439 return true;
443 return false;
446 bool BrowserAccessibility::HasStringAttribute(
447 ui::AXStringAttribute attribute) const {
448 for (size_t i = 0; i < string_attributes_.size(); ++i) {
449 if (string_attributes_[i].first == attribute)
450 return true;
453 return false;
456 const std::string& BrowserAccessibility::GetStringAttribute(
457 ui::AXStringAttribute attribute) const {
458 CR_DEFINE_STATIC_LOCAL(std::string, empty_string, ());
459 for (size_t i = 0; i < string_attributes_.size(); ++i) {
460 if (string_attributes_[i].first == attribute)
461 return string_attributes_[i].second;
464 return empty_string;
467 bool BrowserAccessibility::GetStringAttribute(
468 ui::AXStringAttribute attribute, std::string* value) const {
469 for (size_t i = 0; i < string_attributes_.size(); ++i) {
470 if (string_attributes_[i].first == attribute) {
471 *value = string_attributes_[i].second;
472 return true;
476 return false;
479 base::string16 BrowserAccessibility::GetString16Attribute(
480 ui::AXStringAttribute attribute) const {
481 std::string value_utf8;
482 if (!GetStringAttribute(attribute, &value_utf8))
483 return base::string16();
484 return base::UTF8ToUTF16(value_utf8);
487 bool BrowserAccessibility::GetString16Attribute(
488 ui::AXStringAttribute attribute,
489 base::string16* value) const {
490 std::string value_utf8;
491 if (!GetStringAttribute(attribute, &value_utf8))
492 return false;
493 *value = base::UTF8ToUTF16(value_utf8);
494 return true;
497 void BrowserAccessibility::SetStringAttribute(
498 ui::AXStringAttribute attribute, const std::string& value) {
499 for (size_t i = 0; i < string_attributes_.size(); ++i) {
500 if (string_attributes_[i].first == attribute) {
501 string_attributes_[i].second = value;
502 return;
505 if (!value.empty())
506 string_attributes_.push_back(std::make_pair(attribute, value));
509 bool BrowserAccessibility::HasIntListAttribute(
510 ui::AXIntListAttribute attribute) const {
511 for (size_t i = 0; i < intlist_attributes_.size(); ++i) {
512 if (intlist_attributes_[i].first == attribute)
513 return true;
516 return false;
519 const std::vector<int32>& BrowserAccessibility::GetIntListAttribute(
520 ui::AXIntListAttribute attribute) const {
521 CR_DEFINE_STATIC_LOCAL(std::vector<int32>, empty_vector, ());
522 for (size_t i = 0; i < intlist_attributes_.size(); ++i) {
523 if (intlist_attributes_[i].first == attribute)
524 return intlist_attributes_[i].second;
527 return empty_vector;
530 bool BrowserAccessibility::GetIntListAttribute(
531 ui::AXIntListAttribute attribute,
532 std::vector<int32>* value) const {
533 for (size_t i = 0; i < intlist_attributes_.size(); ++i) {
534 if (intlist_attributes_[i].first == attribute) {
535 *value = intlist_attributes_[i].second;
536 return true;
540 return false;
543 bool BrowserAccessibility::GetHtmlAttribute(
544 const char* html_attr, std::string* value) const {
545 for (size_t i = 0; i < html_attributes_.size(); ++i) {
546 const std::string& attr = html_attributes_[i].first;
547 if (LowerCaseEqualsASCII(attr, html_attr)) {
548 *value = html_attributes_[i].second;
549 return true;
553 return false;
556 bool BrowserAccessibility::GetHtmlAttribute(
557 const char* html_attr, base::string16* value) const {
558 std::string value_utf8;
559 if (!GetHtmlAttribute(html_attr, &value_utf8))
560 return false;
561 *value = base::UTF8ToUTF16(value_utf8);
562 return true;
565 bool BrowserAccessibility::GetAriaTristate(
566 const char* html_attr,
567 bool* is_defined,
568 bool* is_mixed) const {
569 *is_defined = false;
570 *is_mixed = false;
572 base::string16 value;
573 if (!GetHtmlAttribute(html_attr, &value) ||
574 value.empty() ||
575 EqualsASCII(value, "undefined")) {
576 return false; // Not set (and *is_defined is also false)
579 *is_defined = true;
581 if (EqualsASCII(value, "true"))
582 return true;
584 if (EqualsASCII(value, "mixed"))
585 *is_mixed = true;
587 return false; // Not set
590 bool BrowserAccessibility::HasState(ui::AXState state_enum) const {
591 return (state_ >> state_enum) & 1;
594 bool BrowserAccessibility::IsEditableText() const {
595 // These roles don't have readonly set, but they're not editable text.
596 if (role_ == ui::AX_ROLE_SCROLL_AREA ||
597 role_ == ui::AX_ROLE_COLUMN ||
598 role_ == ui::AX_ROLE_TABLE_HEADER_CONTAINER) {
599 return false;
602 // Note: WebAXStateReadonly being false means it's either a text control,
603 // or contenteditable. We also check for editable text roles to cover
604 // another element that has role=textbox set on it.
605 return (!HasState(ui::AX_STATE_READONLY) ||
606 role_ == ui::AX_ROLE_TEXT_FIELD ||
607 role_ == ui::AX_ROLE_TEXT_AREA);
610 std::string BrowserAccessibility::GetTextRecursive() const {
611 if (!name_.empty()) {
612 return name_;
615 std::string result;
616 for (uint32 i = 0; i < PlatformChildCount(); ++i)
617 result += PlatformGetChild(i)->GetTextRecursive();
618 return result;
621 int BrowserAccessibility::GetStaticTextLenRecursive() const {
622 if (role_ == blink::WebAXRoleStaticText)
623 return static_cast<int>(GetStringAttribute(ui::AX_ATTR_VALUE).size());
625 int len = 0;
626 for (size_t i = 0; i < children_.size(); ++i)
627 len += children_[i]->GetStaticTextLenRecursive();
628 return len;
631 } // namespace content