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

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

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

Powered by Google App Engine
This is Rietveld 408576698