• 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   return InternalGetChild(child_index);
88 }
89 
GetPreviousSibling()90 BrowserAccessibility* BrowserAccessibility::GetPreviousSibling() {
91   if (GetParent() && GetIndexInParent() > 0)
92     return GetParent()->InternalGetChild(GetIndexInParent() - 1);
93 
94   return NULL;
95 }
96 
GetNextSibling()97 BrowserAccessibility* BrowserAccessibility::GetNextSibling() {
98   if (GetParent() &&
99       GetIndexInParent() >= 0 &&
100       GetIndexInParent() < static_cast<int>(
101           GetParent()->InternalChildCount() - 1)) {
102     return GetParent()->InternalGetChild(GetIndexInParent() + 1);
103   }
104 
105   return NULL;
106 }
107 
InternalChildCount() const108 uint32 BrowserAccessibility::InternalChildCount() const {
109   if (!node_ || !manager_)
110     return 0;
111   return static_cast<uint32>(node_->child_count());
112 }
113 
InternalGetChild(uint32 child_index) const114 BrowserAccessibility* BrowserAccessibility::InternalGetChild(
115     uint32 child_index) const {
116   if (!node_ || !manager_)
117     return NULL;
118   return manager_->GetFromAXNode(node_->children()[child_index]);
119 }
120 
GetParent() const121 BrowserAccessibility* BrowserAccessibility::GetParent() const {
122   if (!node_ || !manager_)
123     return NULL;
124   ui::AXNode* parent = node_->parent();
125   return parent ? manager_->GetFromAXNode(parent) : NULL;
126 }
127 
GetIndexInParent() const128 int32 BrowserAccessibility::GetIndexInParent() const {
129   return node_ ? node_->index_in_parent() : -1;
130 }
131 
GetId() const132 int32 BrowserAccessibility::GetId() const {
133   return node_ ? node_->id() : -1;
134 }
135 
GetData() const136 const ui::AXNodeData& BrowserAccessibility::GetData() const {
137   CR_DEFINE_STATIC_LOCAL(ui::AXNodeData, empty_data, ());
138   if (node_)
139     return node_->data();
140   else
141     return empty_data;
142 }
143 
GetLocation() const144 gfx::Rect BrowserAccessibility::GetLocation() const {
145   return GetData().location;
146 }
147 
GetRole() const148 int32 BrowserAccessibility::GetRole() const {
149   return GetData().role;
150 }
151 
GetState() const152 int32 BrowserAccessibility::GetState() const {
153   return GetData().state;
154 }
155 
156 const std::vector<std::pair<std::string, std::string> >&
GetHtmlAttributes() const157 BrowserAccessibility::GetHtmlAttributes() const {
158   return GetData().html_attributes;
159 }
160 
GetLocalBoundsRect() const161 gfx::Rect BrowserAccessibility::GetLocalBoundsRect() const {
162   gfx::Rect bounds = GetLocation();
163 
164   // Walk up the parent chain. Every time we encounter a Web Area, offset
165   // based on the scroll bars and then offset based on the origin of that
166   // nested web area.
167   BrowserAccessibility* parent = GetParent();
168   bool need_to_offset_web_area =
169       (GetRole() == ui::AX_ROLE_WEB_AREA ||
170        GetRole() == ui::AX_ROLE_ROOT_WEB_AREA);
171   while (parent) {
172     if (need_to_offset_web_area &&
173         parent->GetLocation().width() > 0 &&
174         parent->GetLocation().height() > 0) {
175       bounds.Offset(parent->GetLocation().x(), parent->GetLocation().y());
176       need_to_offset_web_area = false;
177     }
178 
179     // On some platforms, we don't want to take the root scroll offsets
180     // into account.
181     if (parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA &&
182         !manager()->UseRootScrollOffsetsWhenComputingBounds()) {
183       break;
184     }
185 
186     if (parent->GetRole() == ui::AX_ROLE_WEB_AREA ||
187         parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA) {
188       int sx = 0;
189       int sy = 0;
190       if (parent->GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
191           parent->GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
192         bounds.Offset(-sx, -sy);
193       }
194       need_to_offset_web_area = true;
195     }
196     parent = parent->GetParent();
197   }
198 
199   return bounds;
200 }
201 
GetGlobalBoundsRect() const202 gfx::Rect BrowserAccessibility::GetGlobalBoundsRect() const {
203   gfx::Rect bounds = GetLocalBoundsRect();
204 
205   // Adjust the bounds by the top left corner of the containing view's bounds
206   // in screen coordinates.
207   bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin());
208 
209   return bounds;
210 }
211 
GetLocalBoundsForRange(int start,int len) const212 gfx::Rect BrowserAccessibility::GetLocalBoundsForRange(int start, int len)
213     const {
214   if (GetRole() != ui::AX_ROLE_STATIC_TEXT) {
215     // Apply recursively to all static text descendants. For example, if
216     // you call it on a div with two text node children, it just calls
217     // GetLocalBoundsForRange on each of the two children (adjusting
218     // |start| for each one) and unions the resulting rects.
219     gfx::Rect bounds;
220     for (size_t i = 0; i < InternalChildCount(); ++i) {
221       BrowserAccessibility* child = InternalGetChild(i);
222       int child_len = child->GetStaticTextLenRecursive();
223       if (start < child_len && start + len > 0) {
224         gfx::Rect child_rect = child->GetLocalBoundsForRange(start, len);
225         bounds.Union(child_rect);
226       }
227       start -= child_len;
228     }
229     return bounds;
230   }
231 
232   int end = start + len;
233   int child_start = 0;
234   int child_end = 0;
235 
236   gfx::Rect bounds;
237   for (size_t i = 0; i < InternalChildCount() && child_end < start + len; ++i) {
238     BrowserAccessibility* child = InternalGetChild(i);
239     DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX);
240     std::string child_text;
241     child->GetStringAttribute(ui::AX_ATTR_VALUE, &child_text);
242     int child_len = static_cast<int>(child_text.size());
243     child_start = child_end;
244     child_end += child_len;
245 
246     if (child_end < start)
247       continue;
248 
249     int overlap_start = std::max(start, child_start);
250     int overlap_end = std::min(end, child_end);
251 
252     int local_start = overlap_start - child_start;
253     int local_end = overlap_end - child_start;
254 
255     gfx::Rect child_rect = child->GetLocation();
256     int text_direction = child->GetIntAttribute(
257         ui::AX_ATTR_TEXT_DIRECTION);
258     const std::vector<int32>& character_offsets = child->GetIntListAttribute(
259         ui::AX_ATTR_CHARACTER_OFFSETS);
260     int start_pixel_offset =
261         local_start > 0 ? character_offsets[local_start - 1] : 0;
262     int end_pixel_offset =
263         local_end > 0 ? character_offsets[local_end - 1] : 0;
264 
265     gfx::Rect child_overlap_rect;
266     switch (text_direction) {
267       case ui::AX_TEXT_DIRECTION_NONE:
268       case ui::AX_TEXT_DIRECTION_LR: {
269         int left = child_rect.x() + start_pixel_offset;
270         int right = child_rect.x() + end_pixel_offset;
271         child_overlap_rect = gfx::Rect(left, child_rect.y(),
272                                        right - left, child_rect.height());
273         break;
274       }
275       case ui::AX_TEXT_DIRECTION_RL: {
276         int right = child_rect.right() - start_pixel_offset;
277         int left = child_rect.right() - end_pixel_offset;
278         child_overlap_rect = gfx::Rect(left, child_rect.y(),
279                                        right - left, child_rect.height());
280         break;
281       }
282       case ui::AX_TEXT_DIRECTION_TB: {
283         int top = child_rect.y() + start_pixel_offset;
284         int bottom = child_rect.y() + end_pixel_offset;
285         child_overlap_rect = gfx::Rect(child_rect.x(), top,
286                                        child_rect.width(), bottom - top);
287         break;
288       }
289       case ui::AX_TEXT_DIRECTION_BT: {
290         int bottom = child_rect.bottom() - start_pixel_offset;
291         int top = child_rect.bottom() - end_pixel_offset;
292         child_overlap_rect = gfx::Rect(child_rect.x(), top,
293                                        child_rect.width(), bottom - top);
294         break;
295       }
296       default:
297         NOTREACHED();
298     }
299 
300     if (bounds.width() == 0 && bounds.height() == 0)
301       bounds = child_overlap_rect;
302     else
303       bounds.Union(child_overlap_rect);
304   }
305 
306   return bounds;
307 }
308 
GetGlobalBoundsForRange(int start,int len) const309 gfx::Rect BrowserAccessibility::GetGlobalBoundsForRange(int start, int len)
310     const {
311   gfx::Rect bounds = GetLocalBoundsForRange(start, len);
312 
313   // Adjust the bounds by the top left corner of the containing view's bounds
314   // in screen coordinates.
315   bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin());
316 
317   return bounds;
318 }
319 
BrowserAccessibilityForPoint(const gfx::Point & point)320 BrowserAccessibility* BrowserAccessibility::BrowserAccessibilityForPoint(
321     const gfx::Point& point) {
322   // The best result found that's a child of this object.
323   BrowserAccessibility* child_result = NULL;
324   // The best result that's an indirect descendant like grandchild, etc.
325   BrowserAccessibility* descendant_result = NULL;
326 
327   // Walk the children recursively looking for the BrowserAccessibility that
328   // most tightly encloses the specified point. Walk backwards so that in
329   // the absence of any other information, we assume the object that occurs
330   // later in the tree is on top of one that comes before it.
331   for (int i = static_cast<int>(PlatformChildCount()) - 1; i >= 0; --i) {
332     BrowserAccessibility* child = PlatformGetChild(i);
333 
334     // Skip table columns because cells are only contained in rows,
335     // not columns.
336     if (child->GetRole() == ui::AX_ROLE_COLUMN)
337       continue;
338 
339     if (child->GetGlobalBoundsRect().Contains(point)) {
340       BrowserAccessibility* result = child->BrowserAccessibilityForPoint(point);
341       if (result == child && !child_result)
342         child_result = result;
343       if (result != child && !descendant_result)
344         descendant_result = result;
345     }
346 
347     if (child_result && descendant_result)
348       break;
349   }
350 
351   // Explanation of logic: it's possible that this point overlaps more than
352   // one child of this object. If so, as a heuristic we prefer if the point
353   // overlaps a descendant of one of the two children and not the other.
354   // As an example, suppose you have two rows of buttons - the buttons don't
355   // overlap, but the rows do. Without this heuristic, we'd greedily only
356   // consider one of the containers.
357   if (descendant_result)
358     return descendant_result;
359   if (child_result)
360     return child_result;
361 
362   return this;
363 }
364 
Destroy()365 void BrowserAccessibility::Destroy() {
366   // Allow the object to fire a TextRemoved notification.
367   name_.clear();
368   value_.clear();
369 
370   manager_->NotifyAccessibilityEvent(ui::AX_EVENT_HIDE, this);
371   node_ = NULL;
372   manager_ = NULL;
373 
374   NativeReleaseReference();
375 }
376 
NativeReleaseReference()377 void BrowserAccessibility::NativeReleaseReference() {
378   delete this;
379 }
380 
HasBoolAttribute(ui::AXBoolAttribute attribute) const381 bool BrowserAccessibility::HasBoolAttribute(
382     ui::AXBoolAttribute attribute) const {
383   const ui::AXNodeData& data = GetData();
384   for (size_t i = 0; i < data.bool_attributes.size(); ++i) {
385     if (data.bool_attributes[i].first == attribute)
386       return true;
387   }
388 
389   return false;
390 }
391 
392 
GetBoolAttribute(ui::AXBoolAttribute attribute) const393 bool BrowserAccessibility::GetBoolAttribute(
394     ui::AXBoolAttribute attribute) const {
395   const ui::AXNodeData& data = GetData();
396   for (size_t i = 0; i < data.bool_attributes.size(); ++i) {
397     if (data.bool_attributes[i].first == attribute)
398       return data.bool_attributes[i].second;
399   }
400 
401   return false;
402 }
403 
GetBoolAttribute(ui::AXBoolAttribute attribute,bool * value) const404 bool BrowserAccessibility::GetBoolAttribute(
405     ui::AXBoolAttribute attribute, bool* value) const {
406   const ui::AXNodeData& data = GetData();
407   for (size_t i = 0; i < data.bool_attributes.size(); ++i) {
408     if (data.bool_attributes[i].first == attribute) {
409       *value = data.bool_attributes[i].second;
410       return true;
411     }
412   }
413 
414   return false;
415 }
416 
HasFloatAttribute(ui::AXFloatAttribute attribute) const417 bool BrowserAccessibility::HasFloatAttribute(
418     ui::AXFloatAttribute attribute) const {
419   const ui::AXNodeData& data = GetData();
420   for (size_t i = 0; i < data.float_attributes.size(); ++i) {
421     if (data.float_attributes[i].first == attribute)
422       return true;
423   }
424 
425   return false;
426 }
427 
GetFloatAttribute(ui::AXFloatAttribute attribute) const428 float BrowserAccessibility::GetFloatAttribute(
429     ui::AXFloatAttribute attribute) const {
430   const ui::AXNodeData& data = GetData();
431   for (size_t i = 0; i < data.float_attributes.size(); ++i) {
432     if (data.float_attributes[i].first == attribute)
433       return data.float_attributes[i].second;
434   }
435 
436   return 0.0;
437 }
438 
GetFloatAttribute(ui::AXFloatAttribute attribute,float * value) const439 bool BrowserAccessibility::GetFloatAttribute(
440     ui::AXFloatAttribute attribute, float* value) const {
441   const ui::AXNodeData& data = GetData();
442   for (size_t i = 0; i < data.float_attributes.size(); ++i) {
443     if (data.float_attributes[i].first == attribute) {
444       *value = data.float_attributes[i].second;
445       return true;
446     }
447   }
448 
449   return false;
450 }
451 
HasIntAttribute(ui::AXIntAttribute attribute) const452 bool BrowserAccessibility::HasIntAttribute(
453     ui::AXIntAttribute attribute) const {
454   const ui::AXNodeData& data = GetData();
455   for (size_t i = 0; i < data.int_attributes.size(); ++i) {
456     if (data.int_attributes[i].first == attribute)
457       return true;
458   }
459 
460   return false;
461 }
462 
GetIntAttribute(ui::AXIntAttribute attribute) const463 int BrowserAccessibility::GetIntAttribute(ui::AXIntAttribute attribute) const {
464   const ui::AXNodeData& data = GetData();
465   for (size_t i = 0; i < data.int_attributes.size(); ++i) {
466     if (data.int_attributes[i].first == attribute)
467       return data.int_attributes[i].second;
468   }
469 
470   return 0;
471 }
472 
GetIntAttribute(ui::AXIntAttribute attribute,int * value) const473 bool BrowserAccessibility::GetIntAttribute(
474     ui::AXIntAttribute attribute, int* value) const {
475   const ui::AXNodeData& data = GetData();
476   for (size_t i = 0; i < data.int_attributes.size(); ++i) {
477     if (data.int_attributes[i].first == attribute) {
478       *value = data.int_attributes[i].second;
479       return true;
480     }
481   }
482 
483   return false;
484 }
485 
HasStringAttribute(ui::AXStringAttribute attribute) const486 bool BrowserAccessibility::HasStringAttribute(
487     ui::AXStringAttribute attribute) const {
488   const ui::AXNodeData& data = GetData();
489   for (size_t i = 0; i < data.string_attributes.size(); ++i) {
490     if (data.string_attributes[i].first == attribute)
491       return true;
492   }
493 
494   return false;
495 }
496 
GetStringAttribute(ui::AXStringAttribute attribute) const497 const std::string& BrowserAccessibility::GetStringAttribute(
498     ui::AXStringAttribute attribute) const {
499   const ui::AXNodeData& data = GetData();
500   CR_DEFINE_STATIC_LOCAL(std::string, empty_string, ());
501   for (size_t i = 0; i < data.string_attributes.size(); ++i) {
502     if (data.string_attributes[i].first == attribute)
503       return data.string_attributes[i].second;
504   }
505 
506   return empty_string;
507 }
508 
GetStringAttribute(ui::AXStringAttribute attribute,std::string * value) const509 bool BrowserAccessibility::GetStringAttribute(
510     ui::AXStringAttribute attribute, std::string* value) const {
511   const ui::AXNodeData& data = GetData();
512   for (size_t i = 0; i < data.string_attributes.size(); ++i) {
513     if (data.string_attributes[i].first == attribute) {
514       *value = data.string_attributes[i].second;
515       return true;
516     }
517   }
518 
519   return false;
520 }
521 
GetString16Attribute(ui::AXStringAttribute attribute) const522 base::string16 BrowserAccessibility::GetString16Attribute(
523     ui::AXStringAttribute attribute) const {
524   std::string value_utf8;
525   if (!GetStringAttribute(attribute, &value_utf8))
526     return base::string16();
527   return base::UTF8ToUTF16(value_utf8);
528 }
529 
GetString16Attribute(ui::AXStringAttribute attribute,base::string16 * value) const530 bool BrowserAccessibility::GetString16Attribute(
531     ui::AXStringAttribute attribute,
532     base::string16* value) const {
533   std::string value_utf8;
534   if (!GetStringAttribute(attribute, &value_utf8))
535     return false;
536   *value = base::UTF8ToUTF16(value_utf8);
537   return true;
538 }
539 
SetStringAttribute(ui::AXStringAttribute attribute,const std::string & value)540 void BrowserAccessibility::SetStringAttribute(
541     ui::AXStringAttribute attribute, const std::string& value) {
542   if (!node_)
543     return;
544   ui::AXNodeData data = GetData();
545   for (size_t i = 0; i < data.string_attributes.size(); ++i) {
546     if (data.string_attributes[i].first == attribute) {
547       data.string_attributes[i].second = value;
548       node_->SetData(data);
549       return;
550     }
551   }
552   if (!value.empty()) {
553     data.string_attributes.push_back(std::make_pair(attribute, value));
554     node_->SetData(data);
555   }
556 }
557 
HasIntListAttribute(ui::AXIntListAttribute attribute) const558 bool BrowserAccessibility::HasIntListAttribute(
559     ui::AXIntListAttribute attribute) const {
560   const ui::AXNodeData& data = GetData();
561   for (size_t i = 0; i < data.intlist_attributes.size(); ++i) {
562     if (data.intlist_attributes[i].first == attribute)
563       return true;
564   }
565 
566   return false;
567 }
568 
GetIntListAttribute(ui::AXIntListAttribute attribute) const569 const std::vector<int32>& BrowserAccessibility::GetIntListAttribute(
570     ui::AXIntListAttribute attribute) const {
571   const ui::AXNodeData& data = GetData();
572   CR_DEFINE_STATIC_LOCAL(std::vector<int32>, empty_vector, ());
573   for (size_t i = 0; i < data.intlist_attributes.size(); ++i) {
574     if (data.intlist_attributes[i].first == attribute)
575       return data.intlist_attributes[i].second;
576   }
577 
578   return empty_vector;
579 }
580 
GetIntListAttribute(ui::AXIntListAttribute attribute,std::vector<int32> * value) const581 bool BrowserAccessibility::GetIntListAttribute(
582     ui::AXIntListAttribute attribute,
583     std::vector<int32>* value) const {
584   const ui::AXNodeData& data = GetData();
585   for (size_t i = 0; i < data.intlist_attributes.size(); ++i) {
586     if (data.intlist_attributes[i].first == attribute) {
587       *value = data.intlist_attributes[i].second;
588       return true;
589     }
590   }
591 
592   return false;
593 }
594 
GetHtmlAttribute(const char * html_attr,std::string * value) const595 bool BrowserAccessibility::GetHtmlAttribute(
596     const char* html_attr, std::string* value) const {
597   for (size_t i = 0; i < GetHtmlAttributes().size(); ++i) {
598     const std::string& attr = GetHtmlAttributes()[i].first;
599     if (LowerCaseEqualsASCII(attr, html_attr)) {
600       *value = GetHtmlAttributes()[i].second;
601       return true;
602     }
603   }
604 
605   return false;
606 }
607 
GetHtmlAttribute(const char * html_attr,base::string16 * value) const608 bool BrowserAccessibility::GetHtmlAttribute(
609     const char* html_attr, base::string16* value) const {
610   std::string value_utf8;
611   if (!GetHtmlAttribute(html_attr, &value_utf8))
612     return false;
613   *value = base::UTF8ToUTF16(value_utf8);
614   return true;
615 }
616 
GetAriaTristate(const char * html_attr,bool * is_defined,bool * is_mixed) const617 bool BrowserAccessibility::GetAriaTristate(
618     const char* html_attr,
619     bool* is_defined,
620     bool* is_mixed) const {
621   *is_defined = false;
622   *is_mixed = false;
623 
624   base::string16 value;
625   if (!GetHtmlAttribute(html_attr, &value) ||
626       value.empty() ||
627       EqualsASCII(value, "undefined")) {
628     return false;  // Not set (and *is_defined is also false)
629   }
630 
631   *is_defined = true;
632 
633   if (EqualsASCII(value, "true"))
634     return true;
635 
636   if (EqualsASCII(value, "mixed"))
637     *is_mixed = true;
638 
639   return false;  // Not set
640 }
641 
HasState(ui::AXState state_enum) const642 bool BrowserAccessibility::HasState(ui::AXState state_enum) const {
643   return (GetState() >> state_enum) & 1;
644 }
645 
IsEditableText() const646 bool BrowserAccessibility::IsEditableText() const {
647   // These roles don't have readonly set, but they're not editable text.
648   if (GetRole() == ui::AX_ROLE_SCROLL_AREA ||
649       GetRole() == ui::AX_ROLE_COLUMN ||
650       GetRole() == ui::AX_ROLE_TABLE_HEADER_CONTAINER) {
651     return false;
652   }
653 
654   // Note: WebAXStateReadonly being false means it's either a text control,
655   // or contenteditable. We also check for editable text roles to cover
656   // another element that has role=textbox set on it.
657   return (!HasState(ui::AX_STATE_READ_ONLY) ||
658           GetRole() == ui::AX_ROLE_TEXT_FIELD ||
659           GetRole() == ui::AX_ROLE_TEXT_AREA);
660 }
661 
GetTextRecursive() const662 std::string BrowserAccessibility::GetTextRecursive() const {
663   if (!name_.empty()) {
664     return name_;
665   }
666 
667   std::string result;
668   for (uint32 i = 0; i < PlatformChildCount(); ++i)
669     result += PlatformGetChild(i)->GetTextRecursive();
670   return result;
671 }
672 
GetStaticTextLenRecursive() const673 int BrowserAccessibility::GetStaticTextLenRecursive() const {
674   if (GetRole() == ui::AX_ROLE_STATIC_TEXT)
675     return static_cast<int>(GetStringAttribute(ui::AX_ATTR_VALUE).size());
676 
677   int len = 0;
678   for (size_t i = 0; i < InternalChildCount(); ++i)
679     len += InternalGetChild(i)->GetStaticTextLenRecursive();
680   return len;
681 }
682 
683 }  // namespace content
684