• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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