[Ozone-Gbm] Explicitly crash if trying software rendering on GBM
[chromium-blink-merge.git] / content / renderer / accessibility / blink_ax_tree_source.cc
blob6d7cb9680c66451914d46414082f7958648e6f8c
1 // Copyright 2014 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/renderer/accessibility/blink_ax_tree_source.h"
7 #include <set>
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "content/renderer/accessibility/blink_ax_enum_conversion.h"
13 #include "content/renderer/browser_plugin/browser_plugin.h"
14 #include "content/renderer/render_frame_impl.h"
15 #include "content/renderer/render_frame_proxy.h"
16 #include "content/renderer/render_view_impl.h"
17 #include "third_party/WebKit/public/platform/WebRect.h"
18 #include "third_party/WebKit/public/platform/WebSize.h"
19 #include "third_party/WebKit/public/platform/WebString.h"
20 #include "third_party/WebKit/public/platform/WebVector.h"
21 #include "third_party/WebKit/public/web/WebAXEnums.h"
22 #include "third_party/WebKit/public/web/WebAXObject.h"
23 #include "third_party/WebKit/public/web/WebDocument.h"
24 #include "third_party/WebKit/public/web/WebDocumentType.h"
25 #include "third_party/WebKit/public/web/WebElement.h"
26 #include "third_party/WebKit/public/web/WebFormControlElement.h"
27 #include "third_party/WebKit/public/web/WebFrame.h"
28 #include "third_party/WebKit/public/web/WebLocalFrame.h"
29 #include "third_party/WebKit/public/web/WebNode.h"
30 #include "third_party/WebKit/public/web/WebPlugin.h"
31 #include "third_party/WebKit/public/web/WebPluginContainer.h"
32 #include "third_party/WebKit/public/web/WebView.h"
34 using base::ASCIIToUTF16;
35 using base::UTF16ToUTF8;
36 using blink::WebAXObject;
37 using blink::WebDocument;
38 using blink::WebDocumentType;
39 using blink::WebElement;
40 using blink::WebLocalFrame;
41 using blink::WebNode;
42 using blink::WebPlugin;
43 using blink::WebPluginContainer;
44 using blink::WebVector;
45 using blink::WebView;
47 namespace content {
49 namespace {
51 // Returns true if |ancestor| is the first unignored parent of |child|,
52 // which means that when walking up the parent chain from |child|,
53 // |ancestor| is the *first* ancestor that isn't marked as
54 // accessibilityIsIgnored().
55 bool IsParentUnignoredOf(WebAXObject ancestor,
56 WebAXObject child) {
57 WebAXObject parent = child.parentObject();
58 while (!parent.isDetached() && parent.accessibilityIsIgnored())
59 parent = parent.parentObject();
60 return parent.equals(ancestor);
63 std::string GetEquivalentAriaRoleString(const ui::AXRole role) {
64 switch (role) {
65 case ui::AX_ROLE_ARTICLE:
66 return "article";
67 case ui::AX_ROLE_BANNER:
68 return "banner";
69 case ui::AX_ROLE_BUTTON:
70 return "button";
71 case ui::AX_ROLE_COMPLEMENTARY:
72 return "complementary";
73 case ui::AX_ROLE_FIGURE:
74 return "figure";
75 case ui::AX_ROLE_FOOTER:
76 return "contentinfo";
77 case ui::AX_ROLE_HEADING:
78 return "heading";
79 case ui::AX_ROLE_IMAGE:
80 return "img";
81 case ui::AX_ROLE_MAIN:
82 return "main";
83 case ui::AX_ROLE_NAVIGATION:
84 return "navigation";
85 case ui::AX_ROLE_RADIO_BUTTON:
86 return "radio";
87 case ui::AX_ROLE_REGION:
88 return "region";
89 case ui::AX_ROLE_SLIDER:
90 return "slider";
91 default:
92 break;
95 return std::string();
98 void AddIntListAttributeFromWebObjects(ui::AXIntListAttribute attr,
99 WebVector<WebAXObject> objects,
100 ui::AXNodeData* dst) {
101 std::vector<int32> ids;
102 for(size_t i = 0; i < objects.size(); i++)
103 ids.push_back(objects[i].axID());
104 if (ids.size() > 0)
105 dst->AddIntListAttribute(attr, ids);
108 } // Anonymous namespace
110 BlinkAXTreeSource::BlinkAXTreeSource(RenderFrameImpl* render_frame)
111 : render_frame_(render_frame),
112 node_to_frame_routing_id_map_(NULL),
113 node_to_browser_plugin_instance_id_map_(NULL),
114 accessibility_focus_id_(-1) {
117 BlinkAXTreeSource::~BlinkAXTreeSource() {
120 bool BlinkAXTreeSource::IsInTree(blink::WebAXObject node) const {
121 const blink::WebAXObject& root = GetRoot();
122 while (IsValid(node)) {
123 if (node.equals(root))
124 return true;
125 node = GetParent(node);
127 return false;
130 void BlinkAXTreeSource::CollectChildFrameIdMapping(
131 std::map<int32, int>* node_to_frame_routing_id_map,
132 std::map<int32, int>* node_to_browser_plugin_instance_id_map) {
133 node_to_frame_routing_id_map_ = node_to_frame_routing_id_map;
134 node_to_browser_plugin_instance_id_map_ =
135 node_to_browser_plugin_instance_id_map;
138 blink::WebAXObject BlinkAXTreeSource::GetRoot() const {
139 return GetMainDocument().accessibilityObject();
142 blink::WebAXObject BlinkAXTreeSource::GetFromId(int32 id) const {
143 return GetMainDocument().accessibilityObjectFromID(id);
146 int32 BlinkAXTreeSource::GetId(blink::WebAXObject node) const {
147 return node.axID();
150 void BlinkAXTreeSource::GetChildren(
151 blink::WebAXObject parent,
152 std::vector<blink::WebAXObject>* out_children) const {
153 if (parent.role() == blink::WebAXRoleStaticText) {
154 blink::WebAXObject ancestor = parent;
155 while (!ancestor.isDetached()) {
156 if (ancestor.axID() == accessibility_focus_id_) {
157 parent.loadInlineTextBoxes();
158 break;
160 ancestor = ancestor.parentObject();
164 bool is_iframe = false;
165 WebNode node = parent.node();
166 if (!node.isNull() && node.isElementNode()) {
167 WebElement element = node.to<WebElement>();
168 is_iframe = (element.tagName() == ASCIIToUTF16("IFRAME"));
171 for (unsigned i = 0; i < parent.childCount(); i++) {
172 blink::WebAXObject child = parent.childAt(i);
174 // The child may be invalid due to issues in blink accessibility code.
175 if (child.isDetached())
176 continue;
178 // Skip children whose parent isn't |parent|.
179 // As an exception, include children of an iframe element.
180 if (!is_iframe && !IsParentUnignoredOf(parent, child))
181 continue;
183 out_children->push_back(child);
187 blink::WebAXObject BlinkAXTreeSource::GetParent(
188 blink::WebAXObject node) const {
189 // Blink returns ignored objects when walking up the parent chain,
190 // we have to skip those here. Also, stop when we get to the root
191 // element.
192 blink::WebAXObject root = GetRoot();
193 do {
194 if (node.equals(root))
195 return blink::WebAXObject();
196 node = node.parentObject();
197 } while (!node.isDetached() && node.accessibilityIsIgnored());
199 return node;
202 bool BlinkAXTreeSource::IsValid(blink::WebAXObject node) const {
203 return !node.isDetached(); // This also checks if it's null.
206 bool BlinkAXTreeSource::IsEqual(blink::WebAXObject node1,
207 blink::WebAXObject node2) const {
208 return node1.equals(node2);
211 blink::WebAXObject BlinkAXTreeSource::GetNull() const {
212 return blink::WebAXObject();
215 void BlinkAXTreeSource::SerializeNode(blink::WebAXObject src,
216 ui::AXNodeData* dst) const {
217 dst->role = AXRoleFromBlink(src.role());
218 dst->state = AXStateFromBlink(src);
219 dst->location = src.boundingBoxRect();
220 dst->id = src.axID();
221 std::string name = UTF16ToUTF8(src.title());
223 std::string value;
224 if (src.valueDescription().length()) {
225 dst->AddStringAttribute(ui::AX_ATTR_VALUE,
226 UTF16ToUTF8(src.valueDescription()));
227 } else {
228 dst->AddStringAttribute(ui::AX_ATTR_VALUE, UTF16ToUTF8(src.stringValue()));
231 if (dst->role == ui::AX_ROLE_COLOR_WELL) {
232 int r, g, b;
233 src.colorValue(r, g, b);
234 dst->AddIntAttribute(ui::AX_ATTR_COLOR_VALUE_RED, r);
235 dst->AddIntAttribute(ui::AX_ATTR_COLOR_VALUE_GREEN, g);
236 dst->AddIntAttribute(ui::AX_ATTR_COLOR_VALUE_BLUE, b);
239 if (src.invalidState()) {
240 dst->AddIntAttribute(ui::AX_ATTR_INVALID_STATE,
241 AXInvalidStateFromBlink(src.invalidState()));
243 if (src.invalidState() == blink::WebAXInvalidStateOther) {
244 dst->AddStringAttribute(ui::AX_ATTR_ARIA_INVALID_VALUE,
245 UTF16ToUTF8(src.ariaInvalidValue()));
248 if (dst->role == ui::AX_ROLE_INLINE_TEXT_BOX) {
249 dst->AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION,
250 AXTextDirectionFromBlink(src.textDirection()));
252 WebVector<int> src_character_offsets;
253 src.characterOffsets(src_character_offsets);
254 std::vector<int32> character_offsets;
255 character_offsets.reserve(src_character_offsets.size());
256 for (size_t i = 0; i < src_character_offsets.size(); ++i)
257 character_offsets.push_back(src_character_offsets[i]);
258 dst->AddIntListAttribute(ui::AX_ATTR_CHARACTER_OFFSETS, character_offsets);
260 WebVector<int> src_word_starts;
261 WebVector<int> src_word_ends;
262 src.wordBoundaries(src_word_starts, src_word_ends);
263 std::vector<int32> word_starts;
264 std::vector<int32> word_ends;
265 word_starts.reserve(src_word_starts.size());
266 word_ends.reserve(src_word_starts.size());
267 for (size_t i = 0; i < src_word_starts.size(); ++i) {
268 word_starts.push_back(src_word_starts[i]);
269 word_ends.push_back(src_word_ends[i]);
271 dst->AddIntListAttribute(ui::AX_ATTR_WORD_STARTS, word_starts);
272 dst->AddIntListAttribute(ui::AX_ATTR_WORD_ENDS, word_ends);
275 if (src.accessKey().length()) {
276 dst->AddStringAttribute(ui::AX_ATTR_ACCESS_KEY,
277 UTF16ToUTF8(src.accessKey()));
280 if (src.actionVerb().length())
281 dst->AddStringAttribute(ui::AX_ATTR_ACTION, UTF16ToUTF8(src.actionVerb()));
282 if (src.ariaAutoComplete().length())
283 dst->AddStringAttribute(ui::AX_ATTR_AUTO_COMPLETE,
284 UTF16ToUTF8(src.ariaAutoComplete()));
285 if (src.isAriaReadOnly())
286 dst->AddBoolAttribute(ui::AX_ATTR_ARIA_READONLY, true);
287 if (src.isButtonStateMixed())
288 dst->AddBoolAttribute(ui::AX_ATTR_BUTTON_MIXED, true);
289 if (src.canSetValueAttribute())
290 dst->AddBoolAttribute(ui::AX_ATTR_CAN_SET_VALUE, true);
291 if (src.accessibilityDescription().length()) {
292 dst->AddStringAttribute(ui::AX_ATTR_DESCRIPTION,
293 UTF16ToUTF8(src.accessibilityDescription()));
295 if (src.hasComputedStyle()) {
296 dst->AddStringAttribute(ui::AX_ATTR_DISPLAY,
297 UTF16ToUTF8(src.computedStyleDisplay()));
299 if (src.helpText().length())
300 dst->AddStringAttribute(ui::AX_ATTR_HELP, UTF16ToUTF8(src.helpText()));
301 if (src.placeholder().length()) {
302 dst->AddStringAttribute(ui::AX_ATTR_PLACEHOLDER,
303 UTF16ToUTF8(src.placeholder()));
305 if (src.keyboardShortcut().length()) {
306 dst->AddStringAttribute(ui::AX_ATTR_SHORTCUT,
307 UTF16ToUTF8(src.keyboardShortcut()));
309 if (!src.titleUIElement().isDetached()) {
310 dst->AddIntAttribute(ui::AX_ATTR_TITLE_UI_ELEMENT,
311 src.titleUIElement().axID());
313 if (!src.ariaActiveDescendant().isDetached()) {
314 dst->AddIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID,
315 src.ariaActiveDescendant().axID());
318 if (!src.url().isEmpty())
319 dst->AddStringAttribute(ui::AX_ATTR_URL, src.url().spec());
321 if (dst->role == ui::AX_ROLE_HEADING)
322 dst->AddIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL, src.headingLevel());
323 else if ((dst->role == ui::AX_ROLE_TREE_ITEM ||
324 dst->role == ui::AX_ROLE_ROW) &&
325 src.hierarchicalLevel() > 0) {
326 dst->AddIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL,
327 src.hierarchicalLevel());
330 // Treat the active list box item as focused.
331 if (dst->role == ui::AX_ROLE_LIST_BOX_OPTION &&
332 src.isSelectedOptionActive()) {
333 dst->state |= (1 << ui::AX_STATE_FOCUSED);
336 if (src.canvasHasFallbackContent())
337 dst->AddBoolAttribute(ui::AX_ATTR_CANVAS_HAS_FALLBACK, true);
339 WebNode node = src.node();
340 bool is_iframe = false;
342 if (!node.isNull() && node.isElementNode()) {
343 WebElement element = node.to<WebElement>();
344 is_iframe = (element.tagName() == ASCIIToUTF16("IFRAME"));
346 // TODO(ctguil): The tagName in WebKit is lower cased but
347 // HTMLElement::nodeName calls localNameUpper. Consider adding
348 // a WebElement method that returns the original lower cased tagName.
349 dst->AddStringAttribute(
350 ui::AX_ATTR_HTML_TAG,
351 base::StringToLowerASCII(UTF16ToUTF8(element.tagName())));
352 for (unsigned i = 0; i < element.attributeCount(); ++i) {
353 std::string name = base::StringToLowerASCII(UTF16ToUTF8(
354 element.attributeLocalName(i)));
355 std::string value = UTF16ToUTF8(element.attributeValue(i));
356 dst->html_attributes.push_back(std::make_pair(name, value));
359 if (dst->role == ui::AX_ROLE_TEXT_AREA ||
360 dst->role == ui::AX_ROLE_TEXT_FIELD) {
361 dst->AddIntAttribute(ui::AX_ATTR_TEXT_SEL_START, src.selectionStart());
362 dst->AddIntAttribute(ui::AX_ATTR_TEXT_SEL_END, src.selectionEnd());
364 WebVector<int> src_line_breaks;
365 src.lineBreaks(src_line_breaks);
366 if (src_line_breaks.size() > 0) {
367 std::vector<int32> line_breaks;
368 line_breaks.reserve(src_line_breaks.size());
369 for (size_t i = 0; i < src_line_breaks.size(); ++i)
370 line_breaks.push_back(src_line_breaks[i]);
371 dst->AddIntListAttribute(ui::AX_ATTR_LINE_BREAKS, line_breaks);
374 if (dst->role == ui::AX_ROLE_TEXT_FIELD &&
375 src.textInputType().length()) {
376 dst->AddStringAttribute(ui::AX_ATTR_TEXT_INPUT_TYPE,
377 UTF16ToUTF8(src.textInputType()));
381 blink::WebAXOptionalBool optionalBool = src.isAriaGrabbed();
382 if (optionalBool == blink::WebAXOptionalBoolFalse)
383 dst->AddBoolAttribute(ui::AX_ATTR_GRABBED, false);
384 else if (optionalBool == blink::WebAXOptionalBoolTrue)
385 dst->AddBoolAttribute(ui::AX_ATTR_GRABBED, true);
387 // ARIA role.
388 if (element.hasAttribute("role")) {
389 dst->AddStringAttribute(ui::AX_ATTR_ROLE,
390 UTF16ToUTF8(element.getAttribute("role")));
391 } else {
392 std::string role = GetEquivalentAriaRoleString(dst->role);
393 if (!role.empty())
394 dst->AddStringAttribute(ui::AX_ATTR_ROLE, role);
397 // Browser plugin (used in a <webview>).
398 if (node_to_browser_plugin_instance_id_map_) {
399 BrowserPlugin* browser_plugin = BrowserPlugin::GetFromNode(element);
400 if (browser_plugin) {
401 (*node_to_browser_plugin_instance_id_map_)[dst->id] =
402 browser_plugin->browser_plugin_instance_id();
403 dst->AddBoolAttribute(ui::AX_ATTR_IS_AX_TREE_HOST, true);
408 if (src.isInLiveRegion()) {
409 dst->AddBoolAttribute(ui::AX_ATTR_LIVE_ATOMIC, src.liveRegionAtomic());
410 dst->AddBoolAttribute(ui::AX_ATTR_LIVE_BUSY, src.liveRegionBusy());
411 if (src.liveRegionBusy())
412 dst->state |= (1 << ui::AX_STATE_BUSY);
413 if (!src.liveRegionStatus().isEmpty()) {
414 dst->AddStringAttribute(ui::AX_ATTR_LIVE_STATUS,
415 UTF16ToUTF8(src.liveRegionStatus()));
417 dst->AddStringAttribute(ui::AX_ATTR_LIVE_RELEVANT,
418 UTF16ToUTF8(src.liveRegionRelevant()));
419 dst->AddBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_ATOMIC,
420 src.containerLiveRegionAtomic());
421 dst->AddBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_BUSY,
422 src.containerLiveRegionBusy());
423 dst->AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS,
424 UTF16ToUTF8(src.containerLiveRegionStatus()));
425 dst->AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_RELEVANT,
426 UTF16ToUTF8(src.containerLiveRegionRelevant()));
429 if (dst->role == ui::AX_ROLE_PROGRESS_INDICATOR ||
430 dst->role == ui::AX_ROLE_METER ||
431 dst->role == ui::AX_ROLE_SCROLL_BAR ||
432 dst->role == ui::AX_ROLE_SLIDER ||
433 dst->role == ui::AX_ROLE_SPIN_BUTTON) {
434 dst->AddFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, src.valueForRange());
435 dst->AddFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE,
436 src.maxValueForRange());
437 dst->AddFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE,
438 src.minValueForRange());
441 if (dst->role == ui::AX_ROLE_WEB_AREA) {
442 dst->AddStringAttribute(ui::AX_ATTR_HTML_TAG, "#document");
443 const WebDocument& document = src.document();
444 if (name.empty())
445 name = UTF16ToUTF8(document.title());
446 dst->AddStringAttribute(ui::AX_ATTR_DOC_TITLE,
447 UTF16ToUTF8(document.title()));
448 dst->AddStringAttribute(ui::AX_ATTR_DOC_URL, document.url().spec());
449 dst->AddStringAttribute(
450 ui::AX_ATTR_DOC_MIMETYPE,
451 document.isXHTMLDocument() ? "text/xhtml" : "text/html");
452 dst->AddBoolAttribute(ui::AX_ATTR_DOC_LOADED, src.isLoaded());
453 dst->AddFloatAttribute(ui::AX_ATTR_DOC_LOADING_PROGRESS,
454 src.estimatedLoadingProgress());
456 const WebDocumentType& doctype = document.doctype();
457 if (!doctype.isNull()) {
458 dst->AddStringAttribute(ui::AX_ATTR_DOC_DOCTYPE,
459 UTF16ToUTF8(doctype.name()));
462 const gfx::Size& scroll_offset = document.scrollOffset();
463 dst->AddIntAttribute(ui::AX_ATTR_SCROLL_X, scroll_offset.width());
464 dst->AddIntAttribute(ui::AX_ATTR_SCROLL_Y, scroll_offset.height());
466 const gfx::Size& min_offset = document.minimumScrollOffset();
467 dst->AddIntAttribute(ui::AX_ATTR_SCROLL_X_MIN, min_offset.width());
468 dst->AddIntAttribute(ui::AX_ATTR_SCROLL_Y_MIN, min_offset.height());
470 const gfx::Size& max_offset = document.maximumScrollOffset();
471 dst->AddIntAttribute(ui::AX_ATTR_SCROLL_X_MAX, max_offset.width());
472 dst->AddIntAttribute(ui::AX_ATTR_SCROLL_Y_MAX, max_offset.height());
474 if (node_to_frame_routing_id_map_ && !src.equals(GetRoot())) {
475 WebLocalFrame* frame = document.frame();
476 RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(frame);
477 if (render_frame) {
478 (*node_to_frame_routing_id_map_)[dst->id] =
479 render_frame->GetRoutingID();
480 dst->AddBoolAttribute(ui::AX_ATTR_IS_AX_TREE_HOST, true);
481 } else {
482 RenderFrameProxy* render_frame_proxy =
483 RenderFrameProxy::FromWebFrame(frame);
484 if (render_frame_proxy) {
485 (*node_to_frame_routing_id_map_)[dst->id] =
486 render_frame_proxy->routing_id();
487 dst->AddBoolAttribute(ui::AX_ATTR_IS_AX_TREE_HOST, true);
493 if (dst->role == ui::AX_ROLE_TABLE) {
494 int column_count = src.columnCount();
495 int row_count = src.rowCount();
496 if (column_count > 0 && row_count > 0) {
497 std::set<int32> unique_cell_id_set;
498 std::vector<int32> cell_ids;
499 std::vector<int32> unique_cell_ids;
500 dst->AddIntAttribute(ui::AX_ATTR_TABLE_COLUMN_COUNT, column_count);
501 dst->AddIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT, row_count);
502 WebAXObject header = src.headerContainerObject();
503 if (!header.isDetached())
504 dst->AddIntAttribute(ui::AX_ATTR_TABLE_HEADER_ID, header.axID());
505 for (int i = 0; i < column_count * row_count; ++i) {
506 WebAXObject cell = src.cellForColumnAndRow(
507 i % column_count, i / column_count);
508 int cell_id = -1;
509 if (!cell.isDetached()) {
510 cell_id = cell.axID();
511 if (unique_cell_id_set.find(cell_id) == unique_cell_id_set.end()) {
512 unique_cell_id_set.insert(cell_id);
513 unique_cell_ids.push_back(cell_id);
516 cell_ids.push_back(cell_id);
518 dst->AddIntListAttribute(ui::AX_ATTR_CELL_IDS, cell_ids);
519 dst->AddIntListAttribute(ui::AX_ATTR_UNIQUE_CELL_IDS, unique_cell_ids);
523 if (dst->role == ui::AX_ROLE_ROW) {
524 dst->AddIntAttribute(ui::AX_ATTR_TABLE_ROW_INDEX, src.rowIndex());
525 WebAXObject header = src.rowHeader();
526 if (!header.isDetached())
527 dst->AddIntAttribute(ui::AX_ATTR_TABLE_ROW_HEADER_ID, header.axID());
530 if (dst->role == ui::AX_ROLE_COLUMN) {
531 dst->AddIntAttribute(ui::AX_ATTR_TABLE_COLUMN_INDEX, src.columnIndex());
532 WebAXObject header = src.columnHeader();
533 if (!header.isDetached())
534 dst->AddIntAttribute(ui::AX_ATTR_TABLE_COLUMN_HEADER_ID, header.axID());
537 if (dst->role == ui::AX_ROLE_CELL ||
538 dst->role == ui::AX_ROLE_ROW_HEADER ||
539 dst->role == ui::AX_ROLE_COLUMN_HEADER) {
540 dst->AddIntAttribute(ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX,
541 src.cellColumnIndex());
542 dst->AddIntAttribute(ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN,
543 src.cellColumnSpan());
544 dst->AddIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX, src.cellRowIndex());
545 dst->AddIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_SPAN, src.cellRowSpan());
548 if ((dst->role == ui::AX_ROLE_ROW_HEADER ||
549 dst->role == ui::AX_ROLE_COLUMN_HEADER) && src.sortDirection()) {
550 dst->AddIntAttribute(ui::AX_ATTR_SORT_DIRECTION,
551 AXSortDirectionFromBlink(src.sortDirection()));
554 dst->AddStringAttribute(ui::AX_ATTR_NAME, name);
556 // Add the ids of *indirect* children - those who are children of this node,
557 // but whose parent is *not* this node. One example is a table
558 // cell, which is a child of both a row and a column. Because the cell's
559 // parent is the row, the row adds it as a child, and the column adds it
560 // as an indirect child.
561 int child_count = src.childCount();
562 for (int i = 0; i < child_count; ++i) {
563 WebAXObject child = src.childAt(i);
564 std::vector<int32> indirect_child_ids;
565 if (!is_iframe && !child.isDetached() && !IsParentUnignoredOf(src, child))
566 indirect_child_ids.push_back(child.axID());
567 if (indirect_child_ids.size() > 0) {
568 dst->AddIntListAttribute(
569 ui::AX_ATTR_INDIRECT_CHILD_IDS, indirect_child_ids);
573 WebVector<WebAXObject> controls;
574 if (src.ariaControls(controls))
575 AddIntListAttributeFromWebObjects(ui::AX_ATTR_CONTROLS_IDS, controls, dst);
577 WebVector<WebAXObject> describedby;
578 if (src.ariaDescribedby(describedby)) {
579 AddIntListAttributeFromWebObjects(
580 ui::AX_ATTR_DESCRIBEDBY_IDS, describedby, dst);
583 if (src.ariaDropEffect().length()) {
584 dst->AddStringAttribute(ui::AX_ATTR_DROPEFFECT,
585 UTF16ToUTF8(src.ariaDropEffect()));
588 WebVector<WebAXObject> flowTo;
589 if (src.ariaFlowTo(flowTo))
590 AddIntListAttributeFromWebObjects(ui::AX_ATTR_FLOWTO_IDS, flowTo, dst);
592 WebVector<WebAXObject> labelledby;
593 if (src.ariaLabelledby(labelledby)) {
594 AddIntListAttributeFromWebObjects(
595 ui::AX_ATTR_LABELLEDBY_IDS, labelledby, dst);
598 WebVector<WebAXObject> owns;
599 if (src.ariaOwns(owns))
600 AddIntListAttributeFromWebObjects(ui::AX_ATTR_OWNS_IDS, owns, dst);
603 blink::WebDocument BlinkAXTreeSource::GetMainDocument() const {
604 if (render_frame_ && render_frame_->GetWebFrame())
605 return render_frame_->GetWebFrame()->document();
606 return WebDocument();
609 } // namespace content