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.
4
5 #include "content/browser/accessibility/browser_accessibility.h"
6
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"
13
14 namespace content {
15
16 #if !defined(OS_MACOSX) && \
17 !defined(OS_WIN) && \
18 !defined(OS_ANDROID)
19 // We have subclassess of BrowserAccessibility on Mac and Win. For any other
20 // platform, instantiate the base class.
21 // static
Create()22 BrowserAccessibility* BrowserAccessibility::Create() {
23 return new BrowserAccessibility();
24 }
25 #endif
26
BrowserAccessibility()27 BrowserAccessibility::BrowserAccessibility()
28 : manager_(NULL),
29 node_(NULL) {
30 }
31
~BrowserAccessibility()32 BrowserAccessibility::~BrowserAccessibility() {
33 }
34
Init(BrowserAccessibilityManager * manager,ui::AXNode * node)35 void BrowserAccessibility::Init(BrowserAccessibilityManager* manager,
36 ui::AXNode* node) {
37 manager_ = manager;
38 node_ = node;
39 }
40
OnDataChanged()41 void BrowserAccessibility::OnDataChanged() {
42 GetStringAttribute(ui::AX_ATTR_NAME, &name_);
43 GetStringAttribute(ui::AX_ATTR_VALUE, &value_);
44 }
45
PlatformIsLeaf() const46 bool BrowserAccessibility::PlatformIsLeaf() const {
47 if (InternalChildCount() == 0)
48 return true;
49
50 // All of these roles may have children that we use as internal
51 // implementation details, but we want to expose them as leaves
52 // to platform accessibility APIs.
53 switch (GetRole()) {
54 case ui::AX_ROLE_EDITABLE_TEXT:
55 case ui::AX_ROLE_SLIDER:
56 case ui::AX_ROLE_STATIC_TEXT:
57 case ui::AX_ROLE_TEXT_AREA:
58 case ui::AX_ROLE_TEXT_FIELD:
59 return true;
60 default:
61 return false;
62 }
63 }
64
PlatformChildCount() const65 uint32 BrowserAccessibility::PlatformChildCount() const {
66 return PlatformIsLeaf() ? 0 : InternalChildCount();
67 }
68
IsNative() const69 bool BrowserAccessibility::IsNative() const {
70 return false;
71 }
72
IsDescendantOf(BrowserAccessibility * ancestor)73 bool BrowserAccessibility::IsDescendantOf(
74 BrowserAccessibility* ancestor) {
75 if (this == ancestor) {
76 return true;
77 } else if (GetParent()) {
78 return GetParent()->IsDescendantOf(ancestor);
79 }
80
81 return false;
82 }
83
PlatformGetChild(uint32 child_index) const84 BrowserAccessibility* BrowserAccessibility::PlatformGetChild(
85 uint32 child_index) const {
86 DCHECK(child_index < InternalChildCount());
87 BrowserAccessibility* result = InternalGetChild(child_index);
88
89 if (result->HasBoolAttribute(ui::AX_ATTR_IS_AX_TREE_HOST)) {
90 BrowserAccessibilityManager* child_manager =
91 manager_->delegate()->AccessibilityGetChildFrame(result->GetId());
92 if (child_manager)
93 result = child_manager->GetRoot();
94 }
95
96 return result;
97 }
98
GetPreviousSibling()99 BrowserAccessibility* BrowserAccessibility::GetPreviousSibling() {
100 if (GetParent() && GetIndexInParent() > 0)
101 return GetParent()->InternalGetChild(GetIndexInParent() - 1);
102
103 return NULL;
104 }
105
GetNextSibling()106 BrowserAccessibility* BrowserAccessibility::GetNextSibling() {
107 if (GetParent() &&
108 GetIndexInParent() >= 0 &&
109 GetIndexInParent() < static_cast<int>(
110 GetParent()->InternalChildCount() - 1)) {
111 return GetParent()->InternalGetChild(GetIndexInParent() + 1);
112 }
113
114 return NULL;
115 }
116
InternalChildCount() const117 uint32 BrowserAccessibility::InternalChildCount() const {
118 if (!node_ || !manager_)
119 return 0;
120 return static_cast<uint32>(node_->child_count());
121 }
122
InternalGetChild(uint32 child_index) const123 BrowserAccessibility* BrowserAccessibility::InternalGetChild(
124 uint32 child_index) const {
125 if (!node_ || !manager_)
126 return NULL;
127 return manager_->GetFromAXNode(node_->children()[child_index]);
128 }
129
GetParent() const130 BrowserAccessibility* BrowserAccessibility::GetParent() const {
131 if (!node_ || !manager_)
132 return NULL;
133 ui::AXNode* parent = node_->parent();
134 if (parent)
135 return manager_->GetFromAXNode(parent);
136
137 if (!manager_->delegate())
138 return NULL;
139
140 BrowserAccessibility* host_node =
141 manager_->delegate()->AccessibilityGetParentFrame();
142 if (!host_node)
143 return NULL;
144
145 return host_node->GetParent();
146 }
147
GetIndexInParent() const148 int32 BrowserAccessibility::GetIndexInParent() const {
149 return node_ ? node_->index_in_parent() : -1;
150 }
151
GetId() const152 int32 BrowserAccessibility::GetId() const {
153 return node_ ? node_->id() : -1;
154 }
155
GetData() const156 const ui::AXNodeData& BrowserAccessibility::GetData() const {
157 CR_DEFINE_STATIC_LOCAL(ui::AXNodeData, empty_data, ());
158 if (node_)
159 return node_->data();
160 else
161 return empty_data;
162 }
163
GetLocation() const164 gfx::Rect BrowserAccessibility::GetLocation() const {
165 return GetData().location;
166 }
167
GetRole() const168 int32 BrowserAccessibility::GetRole() const {
169 return GetData().role;
170 }
171
GetState() const172 int32 BrowserAccessibility::GetState() const {
173 return GetData().state;
174 }
175
176 const BrowserAccessibility::HtmlAttributes&
GetHtmlAttributes() const177 BrowserAccessibility::GetHtmlAttributes() const {
178 return GetData().html_attributes;
179 }
180
GetLocalBoundsRect() const181 gfx::Rect BrowserAccessibility::GetLocalBoundsRect() const {
182 gfx::Rect bounds = GetLocation();
183
184 // Walk up the parent chain. Every time we encounter a Web Area, offset
185 // based on the scroll bars and then offset based on the origin of that
186 // nested web area.
187 BrowserAccessibility* parent = GetParent();
188 bool need_to_offset_web_area =
189 (GetRole() == ui::AX_ROLE_WEB_AREA ||
190 GetRole() == ui::AX_ROLE_ROOT_WEB_AREA);
191 while (parent) {
192 if (need_to_offset_web_area &&
193 parent->GetLocation().width() > 0 &&
194 parent->GetLocation().height() > 0) {
195 bounds.Offset(parent->GetLocation().x(), parent->GetLocation().y());
196 need_to_offset_web_area = false;
197 }
198
199 // On some platforms, we don't want to take the root scroll offsets
200 // into account.
201 if (parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA &&
202 !manager()->UseRootScrollOffsetsWhenComputingBounds()) {
203 break;
204 }
205
206 if (parent->GetRole() == ui::AX_ROLE_WEB_AREA ||
207 parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA) {
208 int sx = 0;
209 int sy = 0;
210 if (parent->GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
211 parent->GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
212 bounds.Offset(-sx, -sy);
213 }
214 need_to_offset_web_area = true;
215 }
216 parent = parent->GetParent();
217 }
218
219 return bounds;
220 }
221
GetGlobalBoundsRect() const222 gfx::Rect BrowserAccessibility::GetGlobalBoundsRect() const {
223 gfx::Rect bounds = GetLocalBoundsRect();
224
225 // Adjust the bounds by the top left corner of the containing view's bounds
226 // in screen coordinates.
227 bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin());
228
229 return bounds;
230 }
231
GetLocalBoundsForRange(int start,int len) const232 gfx::Rect BrowserAccessibility::GetLocalBoundsForRange(int start, int len)
233 const {
234 if (GetRole() != ui::AX_ROLE_STATIC_TEXT) {
235 // Apply recursively to all static text descendants. For example, if
236 // you call it on a div with two text node children, it just calls
237 // GetLocalBoundsForRange on each of the two children (adjusting
238 // |start| for each one) and unions the resulting rects.
239 gfx::Rect bounds;
240 for (size_t i = 0; i < InternalChildCount(); ++i) {
241 BrowserAccessibility* child = InternalGetChild(i);
242 int child_len = child->GetStaticTextLenRecursive();
243 if (start < child_len && start + len > 0) {
244 gfx::Rect child_rect = child->GetLocalBoundsForRange(start, len);
245 bounds.Union(child_rect);
246 }
247 start -= child_len;
248 }
249 return bounds;
250 }
251
252 int end = start + len;
253 int child_start = 0;
254 int child_end = 0;
255
256 gfx::Rect bounds;
257 for (size_t i = 0; i < InternalChildCount() && child_end < start + len; ++i) {
258 BrowserAccessibility* child = InternalGetChild(i);
259 DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX);
260 std::string child_text;
261 child->GetStringAttribute(ui::AX_ATTR_VALUE, &child_text);
262 int child_len = static_cast<int>(child_text.size());
263 child_start = child_end;
264 child_end += child_len;
265
266 if (child_end < start)
267 continue;
268
269 int overlap_start = std::max(start, child_start);
270 int overlap_end = std::min(end, child_end);
271
272 int local_start = overlap_start - child_start;
273 int local_end = overlap_end - child_start;
274
275 gfx::Rect child_rect = child->GetLocation();
276 int text_direction = child->GetIntAttribute(
277 ui::AX_ATTR_TEXT_DIRECTION);
278 const std::vector<int32>& character_offsets = child->GetIntListAttribute(
279 ui::AX_ATTR_CHARACTER_OFFSETS);
280 int start_pixel_offset =
281 local_start > 0 ? character_offsets[local_start - 1] : 0;
282 int end_pixel_offset =
283 local_end > 0 ? character_offsets[local_end - 1] : 0;
284
285 gfx::Rect child_overlap_rect;
286 switch (text_direction) {
287 case ui::AX_TEXT_DIRECTION_NONE:
288 case ui::AX_TEXT_DIRECTION_LR: {
289 int left = child_rect.x() + start_pixel_offset;
290 int right = child_rect.x() + end_pixel_offset;
291 child_overlap_rect = gfx::Rect(left, child_rect.y(),
292 right - left, child_rect.height());
293 break;
294 }
295 case ui::AX_TEXT_DIRECTION_RL: {
296 int right = child_rect.right() - start_pixel_offset;
297 int left = child_rect.right() - end_pixel_offset;
298 child_overlap_rect = gfx::Rect(left, child_rect.y(),
299 right - left, child_rect.height());
300 break;
301 }
302 case ui::AX_TEXT_DIRECTION_TB: {
303 int top = child_rect.y() + start_pixel_offset;
304 int bottom = child_rect.y() + end_pixel_offset;
305 child_overlap_rect = gfx::Rect(child_rect.x(), top,
306 child_rect.width(), bottom - top);
307 break;
308 }
309 case ui::AX_TEXT_DIRECTION_BT: {
310 int bottom = child_rect.bottom() - start_pixel_offset;
311 int top = child_rect.bottom() - end_pixel_offset;
312 child_overlap_rect = gfx::Rect(child_rect.x(), top,
313 child_rect.width(), bottom - top);
314 break;
315 }
316 default:
317 NOTREACHED();
318 }
319
320 if (bounds.width() == 0 && bounds.height() == 0)
321 bounds = child_overlap_rect;
322 else
323 bounds.Union(child_overlap_rect);
324 }
325
326 return bounds;
327 }
328
GetGlobalBoundsForRange(int start,int len) const329 gfx::Rect BrowserAccessibility::GetGlobalBoundsForRange(int start, int len)
330 const {
331 gfx::Rect bounds = GetLocalBoundsForRange(start, len);
332
333 // Adjust the bounds by the top left corner of the containing view's bounds
334 // in screen coordinates.
335 bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin());
336
337 return bounds;
338 }
339
BrowserAccessibilityForPoint(const gfx::Point & point)340 BrowserAccessibility* BrowserAccessibility::BrowserAccessibilityForPoint(
341 const gfx::Point& point) {
342 // The best result found that's a child of this object.
343 BrowserAccessibility* child_result = NULL;
344 // The best result that's an indirect descendant like grandchild, etc.
345 BrowserAccessibility* descendant_result = NULL;
346
347 // Walk the children recursively looking for the BrowserAccessibility that
348 // most tightly encloses the specified point. Walk backwards so that in
349 // the absence of any other information, we assume the object that occurs
350 // later in the tree is on top of one that comes before it.
351 for (int i = static_cast<int>(PlatformChildCount()) - 1; i >= 0; --i) {
352 BrowserAccessibility* child = PlatformGetChild(i);
353
354 // Skip table columns because cells are only contained in rows,
355 // not columns.
356 if (child->GetRole() == ui::AX_ROLE_COLUMN)
357 continue;
358
359 if (child->GetGlobalBoundsRect().Contains(point)) {
360 BrowserAccessibility* result = child->BrowserAccessibilityForPoint(point);
361 if (result == child && !child_result)
362 child_result = result;
363 if (result != child && !descendant_result)
364 descendant_result = result;
365 }
366
367 if (child_result && descendant_result)
368 break;
369 }
370
371 // Explanation of logic: it's possible that this point overlaps more than
372 // one child of this object. If so, as a heuristic we prefer if the point
373 // overlaps a descendant of one of the two children and not the other.
374 // As an example, suppose you have two rows of buttons - the buttons don't
375 // overlap, but the rows do. Without this heuristic, we'd greedily only
376 // consider one of the containers.
377 if (descendant_result)
378 return descendant_result;
379 if (child_result)
380 return child_result;
381
382 return this;
383 }
384
Destroy()385 void BrowserAccessibility::Destroy() {
386 // Allow the object to fire a TextRemoved notification.
387 name_.clear();
388 value_.clear();
389
390 manager_->NotifyAccessibilityEvent(ui::AX_EVENT_HIDE, this);
391 node_ = NULL;
392 manager_ = NULL;
393
394 NativeReleaseReference();
395 }
396
NativeReleaseReference()397 void BrowserAccessibility::NativeReleaseReference() {
398 delete this;
399 }
400
HasBoolAttribute(ui::AXBoolAttribute attribute) const401 bool BrowserAccessibility::HasBoolAttribute(
402 ui::AXBoolAttribute attribute) const {
403 const ui::AXNodeData& data = GetData();
404 for (size_t i = 0; i < data.bool_attributes.size(); ++i) {
405 if (data.bool_attributes[i].first == attribute)
406 return true;
407 }
408
409 return false;
410 }
411
412
GetBoolAttribute(ui::AXBoolAttribute attribute) const413 bool BrowserAccessibility::GetBoolAttribute(
414 ui::AXBoolAttribute attribute) const {
415 const ui::AXNodeData& data = GetData();
416 for (size_t i = 0; i < data.bool_attributes.size(); ++i) {
417 if (data.bool_attributes[i].first == attribute)
418 return data.bool_attributes[i].second;
419 }
420
421 return false;
422 }
423
GetBoolAttribute(ui::AXBoolAttribute attribute,bool * value) const424 bool BrowserAccessibility::GetBoolAttribute(
425 ui::AXBoolAttribute attribute, bool* value) const {
426 const ui::AXNodeData& data = GetData();
427 for (size_t i = 0; i < data.bool_attributes.size(); ++i) {
428 if (data.bool_attributes[i].first == attribute) {
429 *value = data.bool_attributes[i].second;
430 return true;
431 }
432 }
433
434 return false;
435 }
436
HasFloatAttribute(ui::AXFloatAttribute attribute) const437 bool BrowserAccessibility::HasFloatAttribute(
438 ui::AXFloatAttribute attribute) const {
439 const ui::AXNodeData& data = GetData();
440 for (size_t i = 0; i < data.float_attributes.size(); ++i) {
441 if (data.float_attributes[i].first == attribute)
442 return true;
443 }
444
445 return false;
446 }
447
GetFloatAttribute(ui::AXFloatAttribute attribute) const448 float BrowserAccessibility::GetFloatAttribute(
449 ui::AXFloatAttribute attribute) const {
450 const ui::AXNodeData& data = GetData();
451 for (size_t i = 0; i < data.float_attributes.size(); ++i) {
452 if (data.float_attributes[i].first == attribute)
453 return data.float_attributes[i].second;
454 }
455
456 return 0.0;
457 }
458
GetFloatAttribute(ui::AXFloatAttribute attribute,float * value) const459 bool BrowserAccessibility::GetFloatAttribute(
460 ui::AXFloatAttribute attribute, float* value) const {
461 const ui::AXNodeData& data = GetData();
462 for (size_t i = 0; i < data.float_attributes.size(); ++i) {
463 if (data.float_attributes[i].first == attribute) {
464 *value = data.float_attributes[i].second;
465 return true;
466 }
467 }
468
469 return false;
470 }
471
HasIntAttribute(ui::AXIntAttribute attribute) const472 bool BrowserAccessibility::HasIntAttribute(
473 ui::AXIntAttribute attribute) const {
474 const ui::AXNodeData& data = GetData();
475 for (size_t i = 0; i < data.int_attributes.size(); ++i) {
476 if (data.int_attributes[i].first == attribute)
477 return true;
478 }
479
480 return false;
481 }
482
GetIntAttribute(ui::AXIntAttribute attribute) const483 int BrowserAccessibility::GetIntAttribute(ui::AXIntAttribute attribute) const {
484 const ui::AXNodeData& data = GetData();
485 for (size_t i = 0; i < data.int_attributes.size(); ++i) {
486 if (data.int_attributes[i].first == attribute)
487 return data.int_attributes[i].second;
488 }
489
490 return 0;
491 }
492
GetIntAttribute(ui::AXIntAttribute attribute,int * value) const493 bool BrowserAccessibility::GetIntAttribute(
494 ui::AXIntAttribute attribute, int* value) const {
495 const ui::AXNodeData& data = GetData();
496 for (size_t i = 0; i < data.int_attributes.size(); ++i) {
497 if (data.int_attributes[i].first == attribute) {
498 *value = data.int_attributes[i].second;
499 return true;
500 }
501 }
502
503 return false;
504 }
505
HasStringAttribute(ui::AXStringAttribute attribute) const506 bool BrowserAccessibility::HasStringAttribute(
507 ui::AXStringAttribute attribute) const {
508 const ui::AXNodeData& data = GetData();
509 for (size_t i = 0; i < data.string_attributes.size(); ++i) {
510 if (data.string_attributes[i].first == attribute)
511 return true;
512 }
513
514 return false;
515 }
516
GetStringAttribute(ui::AXStringAttribute attribute) const517 const std::string& BrowserAccessibility::GetStringAttribute(
518 ui::AXStringAttribute attribute) const {
519 const ui::AXNodeData& data = GetData();
520 CR_DEFINE_STATIC_LOCAL(std::string, empty_string, ());
521 for (size_t i = 0; i < data.string_attributes.size(); ++i) {
522 if (data.string_attributes[i].first == attribute)
523 return data.string_attributes[i].second;
524 }
525
526 return empty_string;
527 }
528
GetStringAttribute(ui::AXStringAttribute attribute,std::string * value) const529 bool BrowserAccessibility::GetStringAttribute(
530 ui::AXStringAttribute attribute, std::string* value) const {
531 const ui::AXNodeData& data = GetData();
532 for (size_t i = 0; i < data.string_attributes.size(); ++i) {
533 if (data.string_attributes[i].first == attribute) {
534 *value = data.string_attributes[i].second;
535 return true;
536 }
537 }
538
539 return false;
540 }
541
GetString16Attribute(ui::AXStringAttribute attribute) const542 base::string16 BrowserAccessibility::GetString16Attribute(
543 ui::AXStringAttribute attribute) const {
544 std::string value_utf8;
545 if (!GetStringAttribute(attribute, &value_utf8))
546 return base::string16();
547 return base::UTF8ToUTF16(value_utf8);
548 }
549
GetString16Attribute(ui::AXStringAttribute attribute,base::string16 * value) const550 bool BrowserAccessibility::GetString16Attribute(
551 ui::AXStringAttribute attribute,
552 base::string16* value) const {
553 std::string value_utf8;
554 if (!GetStringAttribute(attribute, &value_utf8))
555 return false;
556 *value = base::UTF8ToUTF16(value_utf8);
557 return true;
558 }
559
SetStringAttribute(ui::AXStringAttribute attribute,const std::string & value)560 void BrowserAccessibility::SetStringAttribute(
561 ui::AXStringAttribute attribute, const std::string& value) {
562 if (!node_)
563 return;
564 ui::AXNodeData data = GetData();
565 for (size_t i = 0; i < data.string_attributes.size(); ++i) {
566 if (data.string_attributes[i].first == attribute) {
567 data.string_attributes[i].second = value;
568 node_->SetData(data);
569 return;
570 }
571 }
572 if (!value.empty()) {
573 data.string_attributes.push_back(std::make_pair(attribute, value));
574 node_->SetData(data);
575 }
576 }
577
HasIntListAttribute(ui::AXIntListAttribute attribute) const578 bool BrowserAccessibility::HasIntListAttribute(
579 ui::AXIntListAttribute attribute) const {
580 const ui::AXNodeData& data = GetData();
581 for (size_t i = 0; i < data.intlist_attributes.size(); ++i) {
582 if (data.intlist_attributes[i].first == attribute)
583 return true;
584 }
585
586 return false;
587 }
588
GetIntListAttribute(ui::AXIntListAttribute attribute) const589 const std::vector<int32>& BrowserAccessibility::GetIntListAttribute(
590 ui::AXIntListAttribute attribute) const {
591 const ui::AXNodeData& data = GetData();
592 CR_DEFINE_STATIC_LOCAL(std::vector<int32>, empty_vector, ());
593 for (size_t i = 0; i < data.intlist_attributes.size(); ++i) {
594 if (data.intlist_attributes[i].first == attribute)
595 return data.intlist_attributes[i].second;
596 }
597
598 return empty_vector;
599 }
600
GetIntListAttribute(ui::AXIntListAttribute attribute,std::vector<int32> * value) const601 bool BrowserAccessibility::GetIntListAttribute(
602 ui::AXIntListAttribute attribute,
603 std::vector<int32>* value) const {
604 const ui::AXNodeData& data = GetData();
605 for (size_t i = 0; i < data.intlist_attributes.size(); ++i) {
606 if (data.intlist_attributes[i].first == attribute) {
607 *value = data.intlist_attributes[i].second;
608 return true;
609 }
610 }
611
612 return false;
613 }
614
GetHtmlAttribute(const char * html_attr,std::string * value) const615 bool BrowserAccessibility::GetHtmlAttribute(
616 const char* html_attr, std::string* value) const {
617 for (size_t i = 0; i < GetHtmlAttributes().size(); ++i) {
618 const std::string& attr = GetHtmlAttributes()[i].first;
619 if (LowerCaseEqualsASCII(attr, html_attr)) {
620 *value = GetHtmlAttributes()[i].second;
621 return true;
622 }
623 }
624
625 return false;
626 }
627
GetHtmlAttribute(const char * html_attr,base::string16 * value) const628 bool BrowserAccessibility::GetHtmlAttribute(
629 const char* html_attr, base::string16* value) const {
630 std::string value_utf8;
631 if (!GetHtmlAttribute(html_attr, &value_utf8))
632 return false;
633 *value = base::UTF8ToUTF16(value_utf8);
634 return true;
635 }
636
GetAriaTristate(const char * html_attr,bool * is_defined,bool * is_mixed) const637 bool BrowserAccessibility::GetAriaTristate(
638 const char* html_attr,
639 bool* is_defined,
640 bool* is_mixed) const {
641 *is_defined = false;
642 *is_mixed = false;
643
644 base::string16 value;
645 if (!GetHtmlAttribute(html_attr, &value) ||
646 value.empty() ||
647 EqualsASCII(value, "undefined")) {
648 return false; // Not set (and *is_defined is also false)
649 }
650
651 *is_defined = true;
652
653 if (EqualsASCII(value, "true"))
654 return true;
655
656 if (EqualsASCII(value, "mixed"))
657 *is_mixed = true;
658
659 return false; // Not set
660 }
661
HasState(ui::AXState state_enum) const662 bool BrowserAccessibility::HasState(ui::AXState state_enum) const {
663 return (GetState() >> state_enum) & 1;
664 }
665
IsEditableText() const666 bool BrowserAccessibility::IsEditableText() const {
667 // These roles don't have readonly set, but they're not editable text.
668 if (GetRole() == ui::AX_ROLE_SCROLL_AREA ||
669 GetRole() == ui::AX_ROLE_COLUMN ||
670 GetRole() == ui::AX_ROLE_TABLE_HEADER_CONTAINER) {
671 return false;
672 }
673
674 // Note: WebAXStateReadonly being false means it's either a text control,
675 // or contenteditable. We also check for editable text roles to cover
676 // another element that has role=textbox set on it.
677 return (!HasState(ui::AX_STATE_READ_ONLY) ||
678 GetRole() == ui::AX_ROLE_TEXT_FIELD ||
679 GetRole() == ui::AX_ROLE_TEXT_AREA);
680 }
681
GetTextRecursive() const682 std::string BrowserAccessibility::GetTextRecursive() const {
683 if (!name_.empty()) {
684 return name_;
685 }
686
687 std::string result;
688 for (uint32 i = 0; i < PlatformChildCount(); ++i)
689 result += PlatformGetChild(i)->GetTextRecursive();
690 return result;
691 }
692
GetStaticTextLenRecursive() const693 int BrowserAccessibility::GetStaticTextLenRecursive() const {
694 if (GetRole() == ui::AX_ROLE_STATIC_TEXT)
695 return static_cast<int>(GetStringAttribute(ui::AX_ATTR_VALUE).size());
696
697 int len = 0;
698 for (size_t i = 0; i < InternalChildCount(); ++i)
699 len += InternalGetChild(i)->GetStaticTextLenRecursive();
700 return len;
701 }
702
703 } // namespace content
704