Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(80)

Side by Side Diff: content/renderer/accessibility_node_serializer.cc

Issue 10544099: Refactor all accessibility code out of webkit/glue. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix Mac build Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/renderer/accessibility_node_serializer.h"
6
7 #include <set>
8
9 #include "base/string_number_conversions.h"
10 #include "base/string_util.h"
11 #include "base/utf_string_conversions.h"
12 #include "third_party/WebKit/Source/WebKit/chromium/public/WebAccessibilityObjec t.h"
13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebAccessibilityRole. h"
14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
15 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocumentType.h"
16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFormControlElement .h"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputElement.h"
20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebNode.h"
21 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h"
22 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h"
23 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
24 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h"
25
26 using content::AccessibilityNodeData;
27 using WebKit::WebAccessibilityRole;
28 using WebKit::WebAccessibilityObject;
29 using WebKit::WebDocument;
30 using WebKit::WebDocumentType;
31 using WebKit::WebElement;
32 using WebKit::WebNode;
33 using WebKit::WebVector;
34
35 namespace {
36
37 // Returns true if |ancestor| is the first unignored parent of |child|,
38 // which means that when walking up the parent chain from |child|,
39 // |ancestor| is the *first* ancestor that isn't marked as
40 // accessibilityIsIgnored().
41 bool IsParentUnignoredOf(const WebAccessibilityObject& ancestor,
42 const WebAccessibilityObject& child) {
43 WebAccessibilityObject parent = child.parentObject();
44 while (!parent.isNull() && parent.accessibilityIsIgnored())
45 parent = parent.parentObject();
46 return parent.equals(ancestor);
47 }
48
49 // Provides a conversion between the WebKit::WebAccessibilityRole and a role
50 // supported on the Browser side. Listed alphabetically by the
51 // WebKit::WebAccessibilityRole (except for default role).
52 AccessibilityNodeData::Role ConvertRole(WebKit::WebAccessibilityRole role) {
53 switch (role) {
54 case WebKit::WebAccessibilityRoleAnnotation:
55 return AccessibilityNodeData::ROLE_ANNOTATION;
56 case WebKit::WebAccessibilityRoleApplication:
57 return AccessibilityNodeData::ROLE_APPLICATION;
58 case WebKit::WebAccessibilityRoleApplicationAlert:
59 return AccessibilityNodeData::ROLE_ALERT;
60 case WebKit::WebAccessibilityRoleApplicationAlertDialog:
61 return AccessibilityNodeData::ROLE_ALERT_DIALOG;
62 case WebKit::WebAccessibilityRoleApplicationDialog:
63 return AccessibilityNodeData::ROLE_DIALOG;
64 case WebKit::WebAccessibilityRoleApplicationLog:
65 return AccessibilityNodeData::ROLE_LOG;
66 case WebKit::WebAccessibilityRoleApplicationMarquee:
67 return AccessibilityNodeData::ROLE_MARQUEE;
68 case WebKit::WebAccessibilityRoleApplicationStatus:
69 return AccessibilityNodeData::ROLE_STATUS;
70 case WebKit::WebAccessibilityRoleApplicationTimer:
71 return AccessibilityNodeData::ROLE_TIMER;
72 case WebKit::WebAccessibilityRoleBrowser:
73 return AccessibilityNodeData::ROLE_BROWSER;
74 case WebKit::WebAccessibilityRoleBusyIndicator:
75 return AccessibilityNodeData::ROLE_BUSY_INDICATOR;
76 case WebKit::WebAccessibilityRoleButton:
77 return AccessibilityNodeData::ROLE_BUTTON;
78 case WebKit::WebAccessibilityRoleCell:
79 return AccessibilityNodeData::ROLE_CELL;
80 case WebKit::WebAccessibilityRoleCheckBox:
81 return AccessibilityNodeData::ROLE_CHECKBOX;
82 case WebKit::WebAccessibilityRoleColorWell:
83 return AccessibilityNodeData::ROLE_COLOR_WELL;
84 case WebKit::WebAccessibilityRoleColumn:
85 return AccessibilityNodeData::ROLE_COLUMN;
86 case WebKit::WebAccessibilityRoleColumnHeader:
87 return AccessibilityNodeData::ROLE_COLUMN_HEADER;
88 case WebKit::WebAccessibilityRoleComboBox:
89 return AccessibilityNodeData::ROLE_COMBO_BOX;
90 case WebKit::WebAccessibilityRoleDefinitionListDefinition:
91 return AccessibilityNodeData::ROLE_DEFINITION_LIST_DEFINITION;
92 case WebKit::WebAccessibilityRoleDefinitionListTerm:
93 return AccessibilityNodeData::ROLE_DEFINITION_LIST_TERM;
94 case WebKit::WebAccessibilityRoleDirectory:
95 return AccessibilityNodeData::ROLE_DIRECTORY;
96 case WebKit::WebAccessibilityRoleDisclosureTriangle:
97 return AccessibilityNodeData::ROLE_DISCLOSURE_TRIANGLE;
98 case WebKit::WebAccessibilityRoleDocument:
99 return AccessibilityNodeData::ROLE_DOCUMENT;
100 case WebKit::WebAccessibilityRoleDocumentArticle:
101 return AccessibilityNodeData::ROLE_ARTICLE;
102 case WebKit::WebAccessibilityRoleDocumentMath:
103 return AccessibilityNodeData::ROLE_MATH;
104 case WebKit::WebAccessibilityRoleDocumentNote:
105 return AccessibilityNodeData::ROLE_NOTE;
106 case WebKit::WebAccessibilityRoleDocumentRegion:
107 return AccessibilityNodeData::ROLE_REGION;
108 case WebKit::WebAccessibilityRoleDrawer:
109 return AccessibilityNodeData::ROLE_DRAWER;
110 case WebKit::WebAccessibilityRoleEditableText:
111 return AccessibilityNodeData::ROLE_EDITABLE_TEXT;
112 case WebKit::WebAccessibilityRoleFooter:
113 return AccessibilityNodeData::ROLE_FOOTER;
114 case WebKit::WebAccessibilityRoleGrid:
115 return AccessibilityNodeData::ROLE_GRID;
116 case WebKit::WebAccessibilityRoleGroup:
117 return AccessibilityNodeData::ROLE_GROUP;
118 case WebKit::WebAccessibilityRoleGrowArea:
119 return AccessibilityNodeData::ROLE_GROW_AREA;
120 case WebKit::WebAccessibilityRoleHeading:
121 return AccessibilityNodeData::ROLE_HEADING;
122 case WebKit::WebAccessibilityRoleHelpTag:
123 return AccessibilityNodeData::ROLE_HELP_TAG;
124 case WebKit::WebAccessibilityRoleIgnored:
125 return AccessibilityNodeData::ROLE_IGNORED;
126 case WebKit::WebAccessibilityRoleImage:
127 return AccessibilityNodeData::ROLE_IMAGE;
128 case WebKit::WebAccessibilityRoleImageMap:
129 return AccessibilityNodeData::ROLE_IMAGE_MAP;
130 case WebKit::WebAccessibilityRoleImageMapLink:
131 return AccessibilityNodeData::ROLE_IMAGE_MAP_LINK;
132 case WebKit::WebAccessibilityRoleIncrementor:
133 return AccessibilityNodeData::ROLE_INCREMENTOR;
134 case WebKit::WebAccessibilityRoleLandmarkApplication:
135 return AccessibilityNodeData::ROLE_LANDMARK_APPLICATION;
136 case WebKit::WebAccessibilityRoleLandmarkBanner:
137 return AccessibilityNodeData::ROLE_LANDMARK_BANNER;
138 case WebKit::WebAccessibilityRoleLandmarkComplementary:
139 return AccessibilityNodeData::ROLE_LANDMARK_COMPLEMENTARY;
140 case WebKit::WebAccessibilityRoleLandmarkContentInfo:
141 return AccessibilityNodeData::ROLE_LANDMARK_CONTENTINFO;
142 case WebKit::WebAccessibilityRoleLandmarkMain:
143 return AccessibilityNodeData::ROLE_LANDMARK_MAIN;
144 case WebKit::WebAccessibilityRoleLandmarkNavigation:
145 return AccessibilityNodeData::ROLE_LANDMARK_NAVIGATION;
146 case WebKit::WebAccessibilityRoleLandmarkSearch:
147 return AccessibilityNodeData::ROLE_LANDMARK_SEARCH;
148 case WebKit::WebAccessibilityRoleLink:
149 return AccessibilityNodeData::ROLE_LINK;
150 case WebKit::WebAccessibilityRoleList:
151 return AccessibilityNodeData::ROLE_LIST;
152 case WebKit::WebAccessibilityRoleListBox:
153 return AccessibilityNodeData::ROLE_LISTBOX;
154 case WebKit::WebAccessibilityRoleListBoxOption:
155 return AccessibilityNodeData::ROLE_LISTBOX_OPTION;
156 case WebKit::WebAccessibilityRoleListItem:
157 return AccessibilityNodeData::ROLE_LIST_ITEM;
158 case WebKit::WebAccessibilityRoleListMarker:
159 return AccessibilityNodeData::ROLE_LIST_MARKER;
160 case WebKit::WebAccessibilityRoleMatte:
161 return AccessibilityNodeData::ROLE_MATTE;
162 case WebKit::WebAccessibilityRoleMenu:
163 return AccessibilityNodeData::ROLE_MENU;
164 case WebKit::WebAccessibilityRoleMenuBar:
165 return AccessibilityNodeData::ROLE_MENU_BAR;
166 case WebKit::WebAccessibilityRoleMenuButton:
167 return AccessibilityNodeData::ROLE_MENU_BUTTON;
168 case WebKit::WebAccessibilityRoleMenuItem:
169 return AccessibilityNodeData::ROLE_MENU_ITEM;
170 case WebKit::WebAccessibilityRoleMenuListOption:
171 return AccessibilityNodeData::ROLE_MENU_LIST_OPTION;
172 case WebKit::WebAccessibilityRoleMenuListPopup:
173 return AccessibilityNodeData::ROLE_MENU_LIST_POPUP;
174 case WebKit::WebAccessibilityRoleOutline:
175 return AccessibilityNodeData::ROLE_OUTLINE;
176 case WebKit::WebAccessibilityRolePopUpButton:
177 return AccessibilityNodeData::ROLE_POPUP_BUTTON;
178 case WebKit::WebAccessibilityRoleProgressIndicator:
179 return AccessibilityNodeData::ROLE_PROGRESS_INDICATOR;
180 case WebKit::WebAccessibilityRoleRadioButton:
181 return AccessibilityNodeData::ROLE_RADIO_BUTTON;
182 case WebKit::WebAccessibilityRoleRadioGroup:
183 return AccessibilityNodeData::ROLE_RADIO_GROUP;
184 case WebKit::WebAccessibilityRoleRow:
185 return AccessibilityNodeData::ROLE_ROW;
186 case WebKit::WebAccessibilityRoleRowHeader:
187 return AccessibilityNodeData::ROLE_ROW_HEADER;
188 case WebKit::WebAccessibilityRoleRuler:
189 return AccessibilityNodeData::ROLE_RULER;
190 case WebKit::WebAccessibilityRoleRulerMarker:
191 return AccessibilityNodeData::ROLE_RULER_MARKER;
192 case WebKit::WebAccessibilityRoleScrollArea:
193 return AccessibilityNodeData::ROLE_SCROLLAREA;
194 case WebKit::WebAccessibilityRoleScrollBar:
195 return AccessibilityNodeData::ROLE_SCROLLBAR;
196 case WebKit::WebAccessibilityRoleSheet:
197 return AccessibilityNodeData::ROLE_SHEET;
198 case WebKit::WebAccessibilityRoleSlider:
199 return AccessibilityNodeData::ROLE_SLIDER;
200 case WebKit::WebAccessibilityRoleSliderThumb:
201 return AccessibilityNodeData::ROLE_SLIDER_THUMB;
202 case WebKit::WebAccessibilityRoleSplitGroup:
203 return AccessibilityNodeData::ROLE_SPLIT_GROUP;
204 case WebKit::WebAccessibilityRoleSplitter:
205 return AccessibilityNodeData::ROLE_SPLITTER;
206 case WebKit::WebAccessibilityRoleStaticText:
207 return AccessibilityNodeData::ROLE_STATIC_TEXT;
208 case WebKit::WebAccessibilityRoleSystemWide:
209 return AccessibilityNodeData::ROLE_SYSTEM_WIDE;
210 case WebKit::WebAccessibilityRoleTab:
211 return AccessibilityNodeData::ROLE_TAB;
212 case WebKit::WebAccessibilityRoleTabGroup:
213 return AccessibilityNodeData::ROLE_TAB_GROUP_UNUSED;
214 case WebKit::WebAccessibilityRoleTabList:
215 return AccessibilityNodeData::ROLE_TAB_LIST;
216 case WebKit::WebAccessibilityRoleTabPanel:
217 return AccessibilityNodeData::ROLE_TAB_PANEL;
218 case WebKit::WebAccessibilityRoleTable:
219 return AccessibilityNodeData::ROLE_TABLE;
220 case WebKit::WebAccessibilityRoleTableHeaderContainer:
221 return AccessibilityNodeData::ROLE_TABLE_HEADER_CONTAINER;
222 case WebKit::WebAccessibilityRoleTextArea:
223 return AccessibilityNodeData::ROLE_TEXTAREA;
224 case WebKit::WebAccessibilityRoleTextField:
225 return AccessibilityNodeData::ROLE_TEXT_FIELD;
226 case WebKit::WebAccessibilityRoleToolbar:
227 return AccessibilityNodeData::ROLE_TOOLBAR;
228 case WebKit::WebAccessibilityRoleTreeGrid:
229 return AccessibilityNodeData::ROLE_TREE_GRID;
230 case WebKit::WebAccessibilityRoleTreeItemRole:
231 return AccessibilityNodeData::ROLE_TREE_ITEM;
232 case WebKit::WebAccessibilityRoleTreeRole:
233 return AccessibilityNodeData::ROLE_TREE;
234 case WebKit::WebAccessibilityRoleUserInterfaceTooltip:
235 return AccessibilityNodeData::ROLE_TOOLTIP;
236 case WebKit::WebAccessibilityRoleValueIndicator:
237 return AccessibilityNodeData::ROLE_VALUE_INDICATOR;
238 case WebKit::WebAccessibilityRoleWebArea:
239 return AccessibilityNodeData::ROLE_WEB_AREA;
240 case WebKit::WebAccessibilityRoleWebCoreLink:
241 return AccessibilityNodeData::ROLE_WEBCORE_LINK;
242 case WebKit::WebAccessibilityRoleWindow:
243 return AccessibilityNodeData::ROLE_WINDOW;
244
245 default:
246 return AccessibilityNodeData::ROLE_UNKNOWN;
247 }
248 }
249
250 // Provides a conversion between the WebAccessibilityObject state
251 // accessors and a state bitmask that can be serialized and sent to the
252 // Browser process. Rare state are sent as boolean attributes instead.
253 uint32 ConvertState(const WebAccessibilityObject& o) {
254 uint32 state = 0;
255 if (o.isChecked())
256 state |= (1 << AccessibilityNodeData::STATE_CHECKED);
257
258 if (o.isCollapsed())
259 state |= (1 << AccessibilityNodeData::STATE_COLLAPSED);
260
261 if (o.canSetFocusAttribute())
262 state |= (1 << AccessibilityNodeData::STATE_FOCUSABLE);
263
264 if (o.isFocused())
265 state |= (1 << AccessibilityNodeData::STATE_FOCUSED);
266
267 if (o.roleValue() == WebKit::WebAccessibilityRolePopUpButton ||
268 o.ariaHasPopup()) {
269 state |= (1 << AccessibilityNodeData::STATE_HASPOPUP);
270 if (!o.isCollapsed())
271 state |= (1 << AccessibilityNodeData::STATE_EXPANDED);
272 }
273
274 if (o.isHovered())
275 state |= (1 << AccessibilityNodeData::STATE_HOTTRACKED);
276
277 if (o.isIndeterminate())
278 state |= (1 << AccessibilityNodeData::STATE_INDETERMINATE);
279
280 if (!o.isVisible())
281 state |= (1 << AccessibilityNodeData::STATE_INVISIBLE);
282
283 if (o.isLinked())
284 state |= (1 << AccessibilityNodeData::STATE_LINKED);
285
286 if (o.isMultiSelectable())
287 state |= (1 << AccessibilityNodeData::STATE_MULTISELECTABLE);
288
289 if (o.isOffScreen())
290 state |= (1 << AccessibilityNodeData::STATE_OFFSCREEN);
291
292 if (o.isPressed())
293 state |= (1 << AccessibilityNodeData::STATE_PRESSED);
294
295 if (o.isPasswordField())
296 state |= (1 << AccessibilityNodeData::STATE_PROTECTED);
297
298 if (o.isReadOnly())
299 state |= (1 << AccessibilityNodeData::STATE_READONLY);
300
301 if (o.isRequired())
302 state |= (1 << AccessibilityNodeData::STATE_REQUIRED);
303
304 if (o.canSetSelectedAttribute())
305 state |= (1 << AccessibilityNodeData::STATE_SELECTABLE);
306
307 if (o.isSelected())
308 state |= (1 << AccessibilityNodeData::STATE_SELECTED);
309
310 if (o.isVisited())
311 state |= (1 << AccessibilityNodeData::STATE_TRAVERSED);
312
313 if (!o.isEnabled())
314 state |= (1 << AccessibilityNodeData::STATE_UNAVAILABLE);
315
316 if (o.isVertical())
317 state |= (1 << AccessibilityNodeData::STATE_VERTICAL);
318
319 if (o.isVisited())
320 state |= (1 << AccessibilityNodeData::STATE_VISITED);
321
322 return state;
323 }
324
325 } // Anonymous namespace
326
327 namespace content {
328
329 // static
330 void AccessibilityNodeSerializer::Serialize(
331 const WebAccessibilityObject& src,
332 AccessibilityNodeData* dst,
333 IncludeChildren include_children,
334 IncludeLineBreaks include_line_breaks) {
335 dst->name = src.title();
336 dst->role = ConvertRole(src.roleValue());
337 dst->state = ConvertState(src);
338 dst->location = src.boundingBoxRect();
339 dst->id = src.axID();
340
341 if (src.valueDescription().length())
342 dst->value = src.valueDescription();
343 else
344 dst->value = src.stringValue();
345
346 if (src.accessKey().length())
347 dst->string_attributes[dst->ATTR_ACCESS_KEY] = src.accessKey();
348 if (src.actionVerb().length())
349 dst->string_attributes[dst->ATTR_ACTION] = src.actionVerb();
350 if (src.isAriaReadOnly())
351 dst->bool_attributes[dst->ATTR_ARIA_READONLY] = true;
352 if (src.isButtonStateMixed())
353 dst->bool_attributes[dst->ATTR_BUTTON_MIXED] = true;
354 if (src.canSetValueAttribute())
355 dst->bool_attributes[dst->ATTR_CAN_SET_VALUE] = true;
356 if (src.accessibilityDescription().length())
357 dst->string_attributes[dst->ATTR_DESCRIPTION] =
358 src.accessibilityDescription();
359 if (src.hasComputedStyle())
360 dst->string_attributes[dst->ATTR_DISPLAY] = src.computedStyleDisplay();
361 if (src.helpText().length())
362 dst->string_attributes[dst->ATTR_HELP] = src.helpText();
363 if (src.keyboardShortcut().length())
364 dst->string_attributes[dst->ATTR_SHORTCUT] = src.keyboardShortcut();
365 if (src.titleUIElement().isValid()) {
366 dst->int_attributes[dst->ATTR_TITLE_UI_ELEMENT] =
367 src.titleUIElement().axID();
368 }
369 if (!src.url().isEmpty())
370 dst->string_attributes[dst->ATTR_URL] = src.url().spec().utf16();
371
372 if (dst->role == dst->ROLE_TREE_ITEM)
373 dst->int_attributes[dst->ATTR_HIERARCHICAL_LEVEL] = src.hierarchicalLevel();
374
375 if (dst->role == dst->ROLE_SLIDER)
376 include_children = NO_CHILDREN;
377
378 // Treat the active list box item as focused.
379 if (dst->role == dst->ROLE_LISTBOX_OPTION && src.isSelectedOptionActive())
380 dst->state |= (1 << AccessibilityNodeData::STATE_FOCUSED);
381
382 WebNode node = src.node();
383 bool is_iframe = false;
384
385 if (!node.isNull() && node.isElementNode()) {
386 WebElement element = node.to<WebElement>();
387 is_iframe = (element.tagName() == ASCIIToUTF16("IFRAME"));
388
389 // TODO(ctguil): The tagName in WebKit is lower cased but
390 // HTMLElement::nodeName calls localNameUpper. Consider adding
391 // a WebElement method that returns the original lower cased tagName.
392 dst->string_attributes[dst->ATTR_HTML_TAG] =
393 StringToLowerASCII(string16(element.tagName()));
394 for (unsigned i = 0; i < element.attributeCount(); ++i) {
395 string16 name = StringToLowerASCII(string16(
396 element.attributeLocalName(i)));
397 string16 value = element.attributeValue(i);
398 dst->html_attributes.push_back(
399 std::pair<string16, string16>(name, value));
400 }
401
402 if (dst->role == dst->ROLE_EDITABLE_TEXT ||
403 dst->role == dst->ROLE_TEXTAREA ||
404 dst->role == dst->ROLE_TEXT_FIELD) {
405 // Jaws gets confused by children of text fields, so we ignore them.
406 include_children = NO_CHILDREN;
407
408 dst->int_attributes[dst->ATTR_TEXT_SEL_START] = src.selectionStart();
409 dst->int_attributes[dst->ATTR_TEXT_SEL_END] = src.selectionEnd();
410
411 if (include_line_breaks == INCLUDE_LINE_BREAKS) {
412 WebVector<int> src_line_breaks;
413 src.lineBreaks(src_line_breaks);
414 dst->line_breaks.reserve(src_line_breaks.size());
415 for (size_t i = 0; i < src_line_breaks.size(); ++i)
416 dst->line_breaks.push_back(src_line_breaks[i]);
417 }
418 }
419
420 // ARIA role.
421 if (element.hasAttribute("role")) {
422 dst->string_attributes[dst->ATTR_ROLE] = element.getAttribute("role");
423 }
424
425 // Live region attributes
426 if (element.hasAttribute("aria-atomic")) {
427 dst->bool_attributes[dst->ATTR_LIVE_ATOMIC] =
428 LowerCaseEqualsASCII(element.getAttribute("aria-atomic"), "true");
429 }
430 if (element.hasAttribute("aria-busy")) {
431 dst->bool_attributes[dst->ATTR_LIVE_BUSY] =
432 LowerCaseEqualsASCII(element.getAttribute("aria-busy"), "true");
433 }
434 if (element.hasAttribute("aria-live")) {
435 dst->string_attributes[dst->ATTR_LIVE_STATUS] =
436 element.getAttribute("aria-live");
437 }
438 if (element.hasAttribute("aria-relevant")) {
439 dst->string_attributes[dst->ATTR_LIVE_RELEVANT] =
440 element.getAttribute("aria-relevant");
441 }
442 }
443
444 // Walk up the parent chain to set live region attributes of containers
445
446 WebAccessibilityObject container_accessible = src;
447 while (!container_accessible.isNull()) {
448 WebNode container_node = container_accessible.node();
449 if (!container_node.isNull() && container_node.isElementNode()) {
450 WebElement container_elem =
451 container_node.to<WebElement>();
452 if (container_elem.hasAttribute("aria-atomic") &&
453 dst->bool_attributes.find(dst->ATTR_CONTAINER_LIVE_ATOMIC) ==
454 dst->bool_attributes.end()) {
455 dst->bool_attributes[dst->ATTR_CONTAINER_LIVE_ATOMIC] =
456 LowerCaseEqualsASCII(container_elem.getAttribute("aria-atomic"),
457 "true");
458 }
459 if (container_elem.hasAttribute("aria-busy") &&
460 dst->bool_attributes.find(dst->ATTR_CONTAINER_LIVE_BUSY) ==
461 dst->bool_attributes.end()) {
462 dst->bool_attributes[dst->ATTR_CONTAINER_LIVE_BUSY] =
463 LowerCaseEqualsASCII(container_elem.getAttribute("aria-busy"),
464 "true");
465 }
466 if (container_elem.hasAttribute("aria-live") &&
467 dst->string_attributes.find(dst->ATTR_CONTAINER_LIVE_STATUS) ==
468 dst->string_attributes.end()) {
469 dst->string_attributes[dst->ATTR_CONTAINER_LIVE_STATUS] =
470 container_elem.getAttribute("aria-live");
471 }
472 if (container_elem.hasAttribute("aria-relevant") &&
473 dst->string_attributes.find(dst->ATTR_CONTAINER_LIVE_RELEVANT) ==
474 dst->string_attributes.end()) {
475 dst->string_attributes[dst->ATTR_CONTAINER_LIVE_RELEVANT] =
476 container_elem.getAttribute("aria-relevant");
477 }
478 }
479 container_accessible = container_accessible.parentObject();
480 }
481
482 if (dst->role == dst->ROLE_PROGRESS_INDICATOR ||
483 dst->role == dst->ROLE_SCROLLBAR ||
484 dst->role == dst->ROLE_SLIDER) {
485 dst->float_attributes[dst->ATTR_VALUE_FOR_RANGE] = src.valueForRange();
486 dst->float_attributes[dst->ATTR_MAX_VALUE_FOR_RANGE] =
487 src.minValueForRange();
488 dst->float_attributes[dst->ATTR_MIN_VALUE_FOR_RANGE] =
489 src.maxValueForRange();
490 }
491
492 if (dst->role == dst->ROLE_DOCUMENT ||
493 dst->role == dst->ROLE_WEB_AREA) {
494 const WebDocument& document = src.document();
495 if (dst->name.empty())
496 dst->name = document.title();
497 dst->string_attributes[dst->ATTR_DOC_TITLE] = document.title();
498 dst->string_attributes[dst->ATTR_DOC_URL] = document.url().spec().utf16();
499 dst->string_attributes[dst->ATTR_DOC_MIMETYPE] =
500 ASCIIToUTF16(document.isXHTMLDocument() ? "text/xhtml" : "text/html");
501 dst->bool_attributes[dst->ATTR_DOC_LOADED] = src.isLoaded();
502 dst->float_attributes[dst->ATTR_DOC_LOADING_PROGRESS] =
503 src.estimatedLoadingProgress();
504
505 const WebDocumentType& doctype = document.doctype();
506 if (!doctype.isNull())
507 dst->string_attributes[dst->ATTR_DOC_DOCTYPE] = doctype.name();
508
509 const gfx::Size& scroll_offset = document.frame()->scrollOffset();
510 dst->int_attributes[dst->ATTR_SCROLL_X] = scroll_offset.width();
511 dst->int_attributes[dst->ATTR_SCROLL_Y] = scroll_offset.height();
512
513 const gfx::Size& min_offset = document.frame()->minimumScrollOffset();
514 dst->int_attributes[dst->ATTR_SCROLL_X_MIN] = min_offset.width();
515 dst->int_attributes[dst->ATTR_SCROLL_Y_MIN] = min_offset.height();
516
517 const gfx::Size& max_offset = document.frame()->maximumScrollOffset();
518 dst->int_attributes[dst->ATTR_SCROLL_X_MAX] = max_offset.width();
519 dst->int_attributes[dst->ATTR_SCROLL_Y_MAX] = max_offset.height();
520 }
521
522 if (dst->role == dst->ROLE_TABLE) {
523 int column_count = src.columnCount();
524 int row_count = src.rowCount();
525 if (column_count > 0 && row_count > 0) {
526 std::set<int> unique_cell_id_set;
527 dst->int_attributes[dst->ATTR_TABLE_COLUMN_COUNT] = column_count;
528 dst->int_attributes[dst->ATTR_TABLE_ROW_COUNT] = row_count;
529 for (int i = 0; i < column_count * row_count; ++i) {
530 WebAccessibilityObject cell = src.cellForColumnAndRow(
531 i % column_count, i / column_count);
532 int cell_id = -1;
533 if (!cell.isNull()) {
534 cell_id = cell.axID();
535 if (unique_cell_id_set.find(cell_id) == unique_cell_id_set.end()) {
536 unique_cell_id_set.insert(cell_id);
537 dst->unique_cell_ids.push_back(cell_id);
538 }
539 }
540 dst->cell_ids.push_back(cell_id);
541 }
542 }
543 }
544
545 if (dst->role == dst->ROLE_CELL ||
546 dst->role == dst->ROLE_ROW_HEADER ||
547 dst->role == dst->ROLE_COLUMN_HEADER) {
548 dst->int_attributes[dst->ATTR_TABLE_CELL_COLUMN_INDEX] =
549 src.cellColumnIndex();
550 dst->int_attributes[dst->ATTR_TABLE_CELL_COLUMN_SPAN] =
551 src.cellColumnSpan();
552 dst->int_attributes[dst->ATTR_TABLE_CELL_ROW_INDEX] = src.cellRowIndex();
553 dst->int_attributes[dst->ATTR_TABLE_CELL_ROW_SPAN] = src.cellRowSpan();
554 }
555
556 if (include_children == INCLUDE_CHILDREN) {
557 // Recursively create children.
558 int child_count = src.childCount();
559 std::set<int32> child_ids;
560 for (int i = 0; i < child_count; ++i) {
561 WebAccessibilityObject child = src.childAt(i);
562 int32 child_id = child.axID();
563
564 // The child may be invalid due to issues in webkit accessibility code.
565 // Don't add children that are invalid thus preventing a crash.
566 // https://bugs.webkit.org/show_bug.cgi?id=44149
567 // TODO(ctguil): We may want to remove this check as webkit stabilizes.
568 if (!child.isValid())
569 continue;
570
571 // Children may duplicated in the webkit accessibility tree. Only add a
572 // child once for the web accessibility tree.
573 // https://bugs.webkit.org/show_bug.cgi?id=58930
574 if (child_ids.find(child_id) != child_ids.end())
575 continue;
576 child_ids.insert(child_id);
577
578 // Some nodes appear in the tree in more than one place: for example,
579 // a cell in a table appears as a child of both a row and a column.
580 // Only recursively add child nodes that have this node as its
581 // unignored parent. For child nodes that are actually parented to
582 // somethinng else, store only the ID.
583 //
584 // As an exception, also add children of an iframe element.
585 // https://bugs.webkit.org/show_bug.cgi?id=57066
586 if (is_iframe || IsParentUnignoredOf(src, child)) {
587 dst->children.push_back(AccessibilityNodeData());
588 Serialize(child,
589 &dst->children.back(),
590 include_children,
591 include_line_breaks);
592 } else {
593 dst->indirect_child_ids.push_back(child_id);
594 }
595 }
596 }
597 }
598
599 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698