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

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: More Mac compile errors 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 void SerializeAccessibilityNode(
330 const WebAccessibilityObject& src,
331 AccessibilityNodeData* dst,
332 bool include_children) {
333 dst->name = src.title();
334 dst->role = ConvertRole(src.roleValue());
335 dst->state = ConvertState(src);
336 dst->location = src.boundingBoxRect();
337 dst->id = src.axID();
338
339 if (src.valueDescription().length())
340 dst->value = src.valueDescription();
341 else
342 dst->value = src.stringValue();
343
344 if (src.accessKey().length())
345 dst->string_attributes[dst->ATTR_ACCESS_KEY] = src.accessKey();
346 if (src.actionVerb().length())
347 dst->string_attributes[dst->ATTR_ACTION] = src.actionVerb();
348 if (src.isAriaReadOnly())
349 dst->bool_attributes[dst->ATTR_ARIA_READONLY] = true;
350 if (src.isButtonStateMixed())
351 dst->bool_attributes[dst->ATTR_BUTTON_MIXED] = true;
352 if (src.canSetValueAttribute())
353 dst->bool_attributes[dst->ATTR_CAN_SET_VALUE] = true;
354 if (src.accessibilityDescription().length())
355 dst->string_attributes[dst->ATTR_DESCRIPTION] =
356 src.accessibilityDescription();
357 if (src.hasComputedStyle())
358 dst->string_attributes[dst->ATTR_DISPLAY] = src.computedStyleDisplay();
359 if (src.helpText().length())
360 dst->string_attributes[dst->ATTR_HELP] = src.helpText();
361 if (src.keyboardShortcut().length())
362 dst->string_attributes[dst->ATTR_SHORTCUT] = src.keyboardShortcut();
363 if (src.titleUIElement().isValid()) {
364 dst->int_attributes[dst->ATTR_TITLE_UI_ELEMENT] =
365 src.titleUIElement().axID();
366 }
367 if (!src.url().isEmpty())
368 dst->string_attributes[dst->ATTR_URL] = src.url().spec().utf16();
369
370 if (dst->role == dst->ROLE_TREE_ITEM)
371 dst->int_attributes[dst->ATTR_HIERARCHICAL_LEVEL] = src.hierarchicalLevel();
372
373 if (dst->role == dst->ROLE_SLIDER)
374 include_children = false;
375
376 // Treat the active list box item as focused.
377 if (dst->role == dst->ROLE_LISTBOX_OPTION && src.isSelectedOptionActive())
378 dst->state |= (1 << AccessibilityNodeData::STATE_FOCUSED);
379
380 WebNode node = src.node();
381 bool is_iframe = false;
382
383 if (!node.isNull() && node.isElementNode()) {
384 WebElement element = node.to<WebElement>();
385 is_iframe = (element.tagName() == ASCIIToUTF16("IFRAME"));
386
387 // TODO(ctguil): The tagName in WebKit is lower cased but
388 // HTMLElement::nodeName calls localNameUpper. Consider adding
389 // a WebElement method that returns the original lower cased tagName.
390 dst->string_attributes[dst->ATTR_HTML_TAG] =
391 StringToLowerASCII(string16(element.tagName()));
392 for (unsigned i = 0; i < element.attributeCount(); ++i) {
393 string16 name = StringToLowerASCII(string16(
394 element.attributeLocalName(i)));
395 string16 value = element.attributeValue(i);
396 dst->html_attributes.push_back(
397 std::pair<string16, string16>(name, value));
398 }
399
400 if (dst->role == dst->ROLE_EDITABLE_TEXT ||
401 dst->role == dst->ROLE_TEXTAREA ||
402 dst->role == dst->ROLE_TEXT_FIELD) {
403 // Jaws gets confused by children of text fields, so we ignore them.
404 include_children = false;
405
406 dst->int_attributes[dst->ATTR_TEXT_SEL_START] = src.selectionStart();
407 dst->int_attributes[dst->ATTR_TEXT_SEL_END] = src.selectionEnd();
408
409 WebVector<int> src_line_breaks;
410 src.lineBreaks(src_line_breaks);
411 dst->line_breaks.reserve(src_line_breaks.size());
412 for (size_t i = 0; i < src_line_breaks.size(); ++i)
413 dst->line_breaks.push_back(src_line_breaks[i]);
414 }
415
416 // ARIA role.
417 if (element.hasAttribute("role")) {
418 dst->string_attributes[dst->ATTR_ROLE] = element.getAttribute("role");
419 }
420
421 // Live region attributes
422 if (element.hasAttribute("aria-atomic")) {
423 dst->bool_attributes[dst->ATTR_LIVE_ATOMIC] =
424 LowerCaseEqualsASCII(element.getAttribute("aria-atomic"), "true");
425 }
426 if (element.hasAttribute("aria-busy")) {
427 dst->bool_attributes[dst->ATTR_LIVE_BUSY] =
428 LowerCaseEqualsASCII(element.getAttribute("aria-busy"), "true");
429 }
430 if (element.hasAttribute("aria-live")) {
431 dst->string_attributes[dst->ATTR_LIVE_STATUS] =
432 element.getAttribute("aria-live");
433 }
434 if (element.hasAttribute("aria-relevant")) {
435 dst->string_attributes[dst->ATTR_LIVE_RELEVANT] =
436 element.getAttribute("aria-relevant");
437 }
438 }
439
440 // Walk up the parent chain to set live region attributes of containers
441
442 WebAccessibilityObject container_accessible = src;
443 while (!container_accessible.isNull()) {
444 WebNode container_node = container_accessible.node();
445 if (!container_node.isNull() && container_node.isElementNode()) {
446 WebElement container_elem =
447 container_node.to<WebElement>();
448 if (container_elem.hasAttribute("aria-atomic") &&
449 dst->bool_attributes.find(dst->ATTR_CONTAINER_LIVE_ATOMIC) ==
450 dst->bool_attributes.end()) {
451 dst->bool_attributes[dst->ATTR_CONTAINER_LIVE_ATOMIC] =
452 LowerCaseEqualsASCII(container_elem.getAttribute("aria-atomic"),
453 "true");
454 }
455 if (container_elem.hasAttribute("aria-busy") &&
456 dst->bool_attributes.find(dst->ATTR_CONTAINER_LIVE_BUSY) ==
457 dst->bool_attributes.end()) {
458 dst->bool_attributes[dst->ATTR_CONTAINER_LIVE_BUSY] =
459 LowerCaseEqualsASCII(container_elem.getAttribute("aria-busy"),
460 "true");
461 }
462 if (container_elem.hasAttribute("aria-live") &&
463 dst->string_attributes.find(dst->ATTR_CONTAINER_LIVE_STATUS) ==
464 dst->string_attributes.end()) {
465 dst->string_attributes[dst->ATTR_CONTAINER_LIVE_STATUS] =
466 container_elem.getAttribute("aria-live");
467 }
468 if (container_elem.hasAttribute("aria-relevant") &&
469 dst->string_attributes.find(dst->ATTR_CONTAINER_LIVE_RELEVANT) ==
470 dst->string_attributes.end()) {
471 dst->string_attributes[dst->ATTR_CONTAINER_LIVE_RELEVANT] =
472 container_elem.getAttribute("aria-relevant");
473 }
474 }
475 container_accessible = container_accessible.parentObject();
476 }
477
478 if (dst->role == dst->ROLE_PROGRESS_INDICATOR ||
479 dst->role == dst->ROLE_SCROLLBAR ||
480 dst->role == dst->ROLE_SLIDER) {
481 dst->float_attributes[dst->ATTR_VALUE_FOR_RANGE] = src.valueForRange();
482 dst->float_attributes[dst->ATTR_MAX_VALUE_FOR_RANGE] =
483 src.minValueForRange();
484 dst->float_attributes[dst->ATTR_MIN_VALUE_FOR_RANGE] =
485 src.maxValueForRange();
486 }
487
488 if (dst->role == dst->ROLE_DOCUMENT ||
489 dst->role == dst->ROLE_WEB_AREA) {
490 const WebDocument& document = src.document();
491 if (dst->name.empty())
492 dst->name = document.title();
493 dst->string_attributes[dst->ATTR_DOC_TITLE] = document.title();
494 dst->string_attributes[dst->ATTR_DOC_URL] = document.url().spec().utf16();
495 dst->string_attributes[dst->ATTR_DOC_MIMETYPE] =
496 ASCIIToUTF16(document.isXHTMLDocument() ? "text/xhtml" : "text/html");
497 dst->bool_attributes[dst->ATTR_DOC_LOADED] = src.isLoaded();
498 dst->float_attributes[dst->ATTR_DOC_LOADING_PROGRESS] =
499 src.estimatedLoadingProgress();
500
501 const WebDocumentType& doctype = document.doctype();
502 if (!doctype.isNull())
503 dst->string_attributes[dst->ATTR_DOC_DOCTYPE] = doctype.name();
504
505 const gfx::Size& scroll_offset = document.frame()->scrollOffset();
506 dst->int_attributes[dst->ATTR_SCROLL_X] = scroll_offset.width();
507 dst->int_attributes[dst->ATTR_SCROLL_Y] = scroll_offset.height();
508
509 const gfx::Size& min_offset = document.frame()->minimumScrollOffset();
510 dst->int_attributes[dst->ATTR_SCROLL_X_MIN] = min_offset.width();
511 dst->int_attributes[dst->ATTR_SCROLL_Y_MIN] = min_offset.height();
512
513 const gfx::Size& max_offset = document.frame()->maximumScrollOffset();
514 dst->int_attributes[dst->ATTR_SCROLL_X_MAX] = max_offset.width();
515 dst->int_attributes[dst->ATTR_SCROLL_Y_MAX] = max_offset.height();
516 }
517
518 if (dst->role == dst->ROLE_TABLE) {
519 int column_count = src.columnCount();
520 int row_count = src.rowCount();
521 if (column_count > 0 && row_count > 0) {
522 std::set<int> unique_cell_id_set;
523 dst->int_attributes[dst->ATTR_TABLE_COLUMN_COUNT] = column_count;
524 dst->int_attributes[dst->ATTR_TABLE_ROW_COUNT] = row_count;
525 for (int i = 0; i < column_count * row_count; ++i) {
526 WebAccessibilityObject cell = src.cellForColumnAndRow(
527 i % column_count, i / column_count);
528 int cell_id = -1;
529 if (!cell.isNull()) {
530 cell_id = cell.axID();
531 if (unique_cell_id_set.find(cell_id) == unique_cell_id_set.end()) {
532 unique_cell_id_set.insert(cell_id);
533 dst->unique_cell_ids.push_back(cell_id);
534 }
535 }
536 dst->cell_ids.push_back(cell_id);
537 }
538 }
539 }
540
541 if (dst->role == dst->ROLE_CELL ||
542 dst->role == dst->ROLE_ROW_HEADER ||
543 dst->role == dst->ROLE_COLUMN_HEADER) {
544 dst->int_attributes[dst->ATTR_TABLE_CELL_COLUMN_INDEX] =
545 src.cellColumnIndex();
546 dst->int_attributes[dst->ATTR_TABLE_CELL_COLUMN_SPAN] =
547 src.cellColumnSpan();
548 dst->int_attributes[dst->ATTR_TABLE_CELL_ROW_INDEX] = src.cellRowIndex();
549 dst->int_attributes[dst->ATTR_TABLE_CELL_ROW_SPAN] = src.cellRowSpan();
550 }
551
552 if (include_children) {
553 // Recursively create children.
554 int child_count = src.childCount();
555 std::set<int32> child_ids;
556 for (int i = 0; i < child_count; ++i) {
557 WebAccessibilityObject child = src.childAt(i);
558 int32 child_id = child.axID();
559
560 // The child may be invalid due to issues in webkit accessibility code.
561 // Don't add children that are invalid thus preventing a crash.
562 // https://bugs.webkit.org/show_bug.cgi?id=44149
563 // TODO(ctguil): We may want to remove this check as webkit stabilizes.
564 if (!child.isValid())
565 continue;
566
567 // Children may duplicated in the webkit accessibility tree. Only add a
568 // child once for the web accessibility tree.
569 // https://bugs.webkit.org/show_bug.cgi?id=58930
570 if (child_ids.find(child_id) != child_ids.end())
571 continue;
572 child_ids.insert(child_id);
573
574 // Some nodes appear in the tree in more than one place: for example,
575 // a cell in a table appears as a child of both a row and a column.
576 // Only recursively add child nodes that have this node as its
577 // unignored parent. For child nodes that are actually parented to
578 // somethinng else, store only the ID.
579 //
580 // As an exception, also add children of an iframe element.
581 // https://bugs.webkit.org/show_bug.cgi?id=57066
582 if (is_iframe || IsParentUnignoredOf(src, child)) {
583 dst->children.push_back(AccessibilityNodeData());
584 SerializeAccessibilityNode(child,
585 &dst->children.back(),
586 include_children);
587 } else {
588 dst->indirect_child_ids.push_back(child_id);
589 }
590 }
591 }
592 }
593
594 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/accessibility_node_serializer.h ('k') | content/renderer/renderer_accessibility.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698