OLD | NEW |
| (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 "webkit/glue/webaccessibility.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 base::DoubleToString; | |
27 using base::IntToString; | |
28 using WebKit::WebAccessibilityRole; | |
29 using WebKit::WebAccessibilityObject; | |
30 | |
31 namespace { | |
32 | |
33 std::string IntVectorToString(const std::vector<int>& items) { | |
34 std::string str; | |
35 for (size_t i = 0; i < items.size(); ++i) { | |
36 if (i > 0) | |
37 str += ","; | |
38 str += IntToString(items[i]); | |
39 } | |
40 return str; | |
41 } | |
42 | |
43 } // Anonymous namespace | |
44 | |
45 namespace webkit_glue { | |
46 | |
47 // Provides a conversion between the WebKit::WebAccessibilityRole and a role | |
48 // supported on the Browser side. Listed alphabetically by the | |
49 // WebAccessibilityRole (except for default role). | |
50 WebAccessibility::Role ConvertRole(WebKit::WebAccessibilityRole role) { | |
51 switch (role) { | |
52 case WebKit::WebAccessibilityRoleAnnotation: | |
53 return WebAccessibility::ROLE_ANNOTATION; | |
54 case WebKit::WebAccessibilityRoleApplication: | |
55 return WebAccessibility::ROLE_APPLICATION; | |
56 case WebKit::WebAccessibilityRoleApplicationAlert: | |
57 return WebAccessibility::ROLE_ALERT; | |
58 case WebKit::WebAccessibilityRoleApplicationAlertDialog: | |
59 return WebAccessibility::ROLE_ALERT_DIALOG; | |
60 case WebKit::WebAccessibilityRoleApplicationDialog: | |
61 return WebAccessibility::ROLE_DIALOG; | |
62 case WebKit::WebAccessibilityRoleApplicationLog: | |
63 return WebAccessibility::ROLE_LOG; | |
64 case WebKit::WebAccessibilityRoleApplicationMarquee: | |
65 return WebAccessibility::ROLE_MARQUEE; | |
66 case WebKit::WebAccessibilityRoleApplicationStatus: | |
67 return WebAccessibility::ROLE_STATUS; | |
68 case WebKit::WebAccessibilityRoleApplicationTimer: | |
69 return WebAccessibility::ROLE_TIMER; | |
70 case WebKit::WebAccessibilityRoleBrowser: | |
71 return WebAccessibility::ROLE_BROWSER; | |
72 case WebKit::WebAccessibilityRoleBusyIndicator: | |
73 return WebAccessibility::ROLE_BUSY_INDICATOR; | |
74 case WebKit::WebAccessibilityRoleButton: | |
75 return WebAccessibility::ROLE_BUTTON; | |
76 case WebKit::WebAccessibilityRoleCell: | |
77 return WebAccessibility::ROLE_CELL; | |
78 case WebKit::WebAccessibilityRoleCheckBox: | |
79 return WebAccessibility::ROLE_CHECKBOX; | |
80 case WebKit::WebAccessibilityRoleColorWell: | |
81 return WebAccessibility::ROLE_COLOR_WELL; | |
82 case WebKit::WebAccessibilityRoleColumn: | |
83 return WebAccessibility::ROLE_COLUMN; | |
84 case WebKit::WebAccessibilityRoleColumnHeader: | |
85 return WebAccessibility::ROLE_COLUMN_HEADER; | |
86 case WebKit::WebAccessibilityRoleComboBox: | |
87 return WebAccessibility::ROLE_COMBO_BOX; | |
88 case WebKit::WebAccessibilityRoleDefinitionListDefinition: | |
89 return WebAccessibility::ROLE_DEFINITION_LIST_DEFINITION; | |
90 case WebKit::WebAccessibilityRoleDefinitionListTerm: | |
91 return WebAccessibility::ROLE_DEFINITION_LIST_TERM; | |
92 case WebKit::WebAccessibilityRoleDirectory: | |
93 return WebAccessibility::ROLE_DIRECTORY; | |
94 case WebKit::WebAccessibilityRoleDisclosureTriangle: | |
95 return WebAccessibility::ROLE_DISCLOSURE_TRIANGLE; | |
96 case WebKit::WebAccessibilityRoleDocument: | |
97 return WebAccessibility::ROLE_DOCUMENT; | |
98 case WebKit::WebAccessibilityRoleDocumentArticle: | |
99 return WebAccessibility::ROLE_ARTICLE; | |
100 case WebKit::WebAccessibilityRoleDocumentMath: | |
101 return WebAccessibility::ROLE_MATH; | |
102 case WebKit::WebAccessibilityRoleDocumentNote: | |
103 return WebAccessibility::ROLE_NOTE; | |
104 case WebKit::WebAccessibilityRoleDocumentRegion: | |
105 return WebAccessibility::ROLE_REGION; | |
106 case WebKit::WebAccessibilityRoleDrawer: | |
107 return WebAccessibility::ROLE_DRAWER; | |
108 case WebKit::WebAccessibilityRoleEditableText: | |
109 return WebAccessibility::ROLE_EDITABLE_TEXT; | |
110 case WebKit::WebAccessibilityRoleFooter: | |
111 return WebAccessibility::ROLE_FOOTER; | |
112 case WebKit::WebAccessibilityRoleGrid: | |
113 return WebAccessibility::ROLE_GRID; | |
114 case WebKit::WebAccessibilityRoleGroup: | |
115 return WebAccessibility::ROLE_GROUP; | |
116 case WebKit::WebAccessibilityRoleGrowArea: | |
117 return WebAccessibility::ROLE_GROW_AREA; | |
118 case WebKit::WebAccessibilityRoleHeading: | |
119 return WebAccessibility::ROLE_HEADING; | |
120 case WebKit::WebAccessibilityRoleHelpTag: | |
121 return WebAccessibility::ROLE_HELP_TAG; | |
122 case WebKit::WebAccessibilityRoleIgnored: | |
123 return WebAccessibility::ROLE_IGNORED; | |
124 case WebKit::WebAccessibilityRoleImage: | |
125 return WebAccessibility::ROLE_IMAGE; | |
126 case WebKit::WebAccessibilityRoleImageMap: | |
127 return WebAccessibility::ROLE_IMAGE_MAP; | |
128 case WebKit::WebAccessibilityRoleImageMapLink: | |
129 return WebAccessibility::ROLE_IMAGE_MAP_LINK; | |
130 case WebKit::WebAccessibilityRoleIncrementor: | |
131 return WebAccessibility::ROLE_INCREMENTOR; | |
132 case WebKit::WebAccessibilityRoleLandmarkApplication: | |
133 return WebAccessibility::ROLE_LANDMARK_APPLICATION; | |
134 case WebKit::WebAccessibilityRoleLandmarkBanner: | |
135 return WebAccessibility::ROLE_LANDMARK_BANNER; | |
136 case WebKit::WebAccessibilityRoleLandmarkComplementary: | |
137 return WebAccessibility::ROLE_LANDMARK_COMPLEMENTARY; | |
138 case WebKit::WebAccessibilityRoleLandmarkContentInfo: | |
139 return WebAccessibility::ROLE_LANDMARK_CONTENTINFO; | |
140 case WebKit::WebAccessibilityRoleLandmarkMain: | |
141 return WebAccessibility::ROLE_LANDMARK_MAIN; | |
142 case WebKit::WebAccessibilityRoleLandmarkNavigation: | |
143 return WebAccessibility::ROLE_LANDMARK_NAVIGATION; | |
144 case WebKit::WebAccessibilityRoleLandmarkSearch: | |
145 return WebAccessibility::ROLE_LANDMARK_SEARCH; | |
146 case WebKit::WebAccessibilityRoleLink: | |
147 return WebAccessibility::ROLE_LINK; | |
148 case WebKit::WebAccessibilityRoleList: | |
149 return WebAccessibility::ROLE_LIST; | |
150 case WebKit::WebAccessibilityRoleListBox: | |
151 return WebAccessibility::ROLE_LISTBOX; | |
152 case WebKit::WebAccessibilityRoleListBoxOption: | |
153 return WebAccessibility::ROLE_LISTBOX_OPTION; | |
154 case WebKit::WebAccessibilityRoleListItem: | |
155 return WebAccessibility::ROLE_LIST_ITEM; | |
156 case WebKit::WebAccessibilityRoleListMarker: | |
157 return WebAccessibility::ROLE_LIST_MARKER; | |
158 case WebKit::WebAccessibilityRoleMatte: | |
159 return WebAccessibility::ROLE_MATTE; | |
160 case WebKit::WebAccessibilityRoleMenu: | |
161 return WebAccessibility::ROLE_MENU; | |
162 case WebKit::WebAccessibilityRoleMenuBar: | |
163 return WebAccessibility::ROLE_MENU_BAR; | |
164 case WebKit::WebAccessibilityRoleMenuButton: | |
165 return WebAccessibility::ROLE_MENU_BUTTON; | |
166 case WebKit::WebAccessibilityRoleMenuItem: | |
167 return WebAccessibility::ROLE_MENU_ITEM; | |
168 case WebKit::WebAccessibilityRoleMenuListOption: | |
169 return WebAccessibility::ROLE_MENU_LIST_OPTION; | |
170 case WebKit::WebAccessibilityRoleMenuListPopup: | |
171 return WebAccessibility::ROLE_MENU_LIST_POPUP; | |
172 case WebKit::WebAccessibilityRoleOutline: | |
173 return WebAccessibility::ROLE_OUTLINE; | |
174 case WebKit::WebAccessibilityRolePopUpButton: | |
175 return WebAccessibility::ROLE_POPUP_BUTTON; | |
176 case WebKit::WebAccessibilityRoleProgressIndicator: | |
177 return WebAccessibility::ROLE_PROGRESS_INDICATOR; | |
178 case WebKit::WebAccessibilityRoleRadioButton: | |
179 return WebAccessibility::ROLE_RADIO_BUTTON; | |
180 case WebKit::WebAccessibilityRoleRadioGroup: | |
181 return WebAccessibility::ROLE_RADIO_GROUP; | |
182 case WebKit::WebAccessibilityRoleRow: | |
183 return WebAccessibility::ROLE_ROW; | |
184 case WebKit::WebAccessibilityRoleRowHeader: | |
185 return WebAccessibility::ROLE_ROW_HEADER; | |
186 case WebKit::WebAccessibilityRoleRuler: | |
187 return WebAccessibility::ROLE_RULER; | |
188 case WebKit::WebAccessibilityRoleRulerMarker: | |
189 return WebAccessibility::ROLE_RULER_MARKER; | |
190 case WebKit::WebAccessibilityRoleScrollArea: | |
191 return WebAccessibility::ROLE_SCROLLAREA; | |
192 case WebKit::WebAccessibilityRoleScrollBar: | |
193 return WebAccessibility::ROLE_SCROLLBAR; | |
194 case WebKit::WebAccessibilityRoleSheet: | |
195 return WebAccessibility::ROLE_SHEET; | |
196 case WebKit::WebAccessibilityRoleSlider: | |
197 return WebAccessibility::ROLE_SLIDER; | |
198 case WebKit::WebAccessibilityRoleSliderThumb: | |
199 return WebAccessibility::ROLE_SLIDER_THUMB; | |
200 case WebKit::WebAccessibilityRoleSplitGroup: | |
201 return WebAccessibility::ROLE_SPLIT_GROUP; | |
202 case WebKit::WebAccessibilityRoleSplitter: | |
203 return WebAccessibility::ROLE_SPLITTER; | |
204 case WebKit::WebAccessibilityRoleStaticText: | |
205 return WebAccessibility::ROLE_STATIC_TEXT; | |
206 case WebKit::WebAccessibilityRoleSystemWide: | |
207 return WebAccessibility::ROLE_SYSTEM_WIDE; | |
208 case WebKit::WebAccessibilityRoleTab: | |
209 return WebAccessibility::ROLE_TAB; | |
210 case WebKit::WebAccessibilityRoleTabGroup: | |
211 return WebAccessibility::ROLE_TAB_GROUP_UNUSED; | |
212 case WebKit::WebAccessibilityRoleTabList: | |
213 return WebAccessibility::ROLE_TAB_LIST; | |
214 case WebKit::WebAccessibilityRoleTabPanel: | |
215 return WebAccessibility::ROLE_TAB_PANEL; | |
216 case WebKit::WebAccessibilityRoleTable: | |
217 return WebAccessibility::ROLE_TABLE; | |
218 case WebKit::WebAccessibilityRoleTableHeaderContainer: | |
219 return WebAccessibility::ROLE_TABLE_HEADER_CONTAINER; | |
220 case WebKit::WebAccessibilityRoleTextArea: | |
221 return WebAccessibility::ROLE_TEXTAREA; | |
222 case WebKit::WebAccessibilityRoleTextField: | |
223 return WebAccessibility::ROLE_TEXT_FIELD; | |
224 case WebKit::WebAccessibilityRoleToolbar: | |
225 return WebAccessibility::ROLE_TOOLBAR; | |
226 case WebKit::WebAccessibilityRoleTreeGrid: | |
227 return WebAccessibility::ROLE_TREE_GRID; | |
228 case WebKit::WebAccessibilityRoleTreeItemRole: | |
229 return WebAccessibility::ROLE_TREE_ITEM; | |
230 case WebKit::WebAccessibilityRoleTreeRole: | |
231 return WebAccessibility::ROLE_TREE; | |
232 case WebKit::WebAccessibilityRoleUserInterfaceTooltip: | |
233 return WebAccessibility::ROLE_TOOLTIP; | |
234 case WebKit::WebAccessibilityRoleValueIndicator: | |
235 return WebAccessibility::ROLE_VALUE_INDICATOR; | |
236 case WebKit::WebAccessibilityRoleWebArea: | |
237 return WebAccessibility::ROLE_WEB_AREA; | |
238 case WebKit::WebAccessibilityRoleWebCoreLink: | |
239 return WebAccessibility::ROLE_WEBCORE_LINK; | |
240 case WebKit::WebAccessibilityRoleWindow: | |
241 return WebAccessibility::ROLE_WINDOW; | |
242 | |
243 default: | |
244 return WebAccessibility::ROLE_UNKNOWN; | |
245 } | |
246 } | |
247 | |
248 uint32 ConvertState(const WebAccessibilityObject& o) { | |
249 uint32 state = 0; | |
250 if (o.isChecked()) | |
251 state |= (1 << WebAccessibility::STATE_CHECKED); | |
252 | |
253 if (o.isCollapsed()) | |
254 state |= (1 << WebAccessibility::STATE_COLLAPSED); | |
255 | |
256 if (o.canSetFocusAttribute()) | |
257 state |= (1 << WebAccessibility::STATE_FOCUSABLE); | |
258 | |
259 if (o.isFocused()) | |
260 state |= (1 << WebAccessibility::STATE_FOCUSED); | |
261 | |
262 if (o.roleValue() == WebKit::WebAccessibilityRolePopUpButton || | |
263 o.ariaHasPopup()) { | |
264 state |= (1 << WebAccessibility::STATE_HASPOPUP); | |
265 if (!o.isCollapsed()) | |
266 state |= (1 << WebAccessibility::STATE_EXPANDED); | |
267 } | |
268 | |
269 if (o.isHovered()) | |
270 state |= (1 << WebAccessibility::STATE_HOTTRACKED); | |
271 | |
272 if (o.isIndeterminate()) | |
273 state |= (1 << WebAccessibility::STATE_INDETERMINATE); | |
274 | |
275 if (!o.isVisible()) | |
276 state |= (1 << WebAccessibility::STATE_INVISIBLE); | |
277 | |
278 if (o.isLinked()) | |
279 state |= (1 << WebAccessibility::STATE_LINKED); | |
280 | |
281 if (o.isMultiSelectable()) | |
282 state |= (1 << WebAccessibility::STATE_MULTISELECTABLE); | |
283 | |
284 if (o.isOffScreen()) | |
285 state |= (1 << WebAccessibility::STATE_OFFSCREEN); | |
286 | |
287 if (o.isPressed()) | |
288 state |= (1 << WebAccessibility::STATE_PRESSED); | |
289 | |
290 if (o.isPasswordField()) | |
291 state |= (1 << WebAccessibility::STATE_PROTECTED); | |
292 | |
293 if (o.isReadOnly()) | |
294 state |= (1 << WebAccessibility::STATE_READONLY); | |
295 | |
296 if (o.isRequired()) | |
297 state |= (1 << WebAccessibility::STATE_REQUIRED); | |
298 | |
299 if (o.canSetSelectedAttribute()) | |
300 state |= (1 << WebAccessibility::STATE_SELECTABLE); | |
301 | |
302 if (o.isSelected()) | |
303 state |= (1 << WebAccessibility::STATE_SELECTED); | |
304 | |
305 if (o.isVisited()) | |
306 state |= (1 << WebAccessibility::STATE_TRAVERSED); | |
307 | |
308 if (!o.isEnabled()) | |
309 state |= (1 << WebAccessibility::STATE_UNAVAILABLE); | |
310 | |
311 if (o.isVertical()) | |
312 state |= (1 << WebAccessibility::STATE_VERTICAL); | |
313 | |
314 if (o.isVisited()) | |
315 state |= (1 << WebAccessibility::STATE_VISITED); | |
316 | |
317 return state; | |
318 } | |
319 | |
320 WebAccessibility::WebAccessibility() | |
321 : id(-1), | |
322 role(ROLE_UNKNOWN), | |
323 state(-1) { | |
324 } | |
325 | |
326 WebAccessibility::WebAccessibility(const WebKit::WebAccessibilityObject& src, | |
327 IncludeChildren include_children, | |
328 IncludeLineBreaks include_line_breaks) { | |
329 Init(src, include_children, include_line_breaks); | |
330 } | |
331 | |
332 WebAccessibility::~WebAccessibility() { | |
333 } | |
334 | |
335 #ifndef NDEBUG | |
336 std::string WebAccessibility::DebugString(bool recursive) const { | |
337 std::string result; | |
338 static int indent = 0; | |
339 result += "\n"; | |
340 for (int i = 0; i < indent; ++i) | |
341 result += " "; | |
342 | |
343 result += "id=" + IntToString(id); | |
344 | |
345 switch (role) { | |
346 case ROLE_ALERT: result += " ALERT"; break; | |
347 case ROLE_ALERT_DIALOG: result += " ALERT_DIALOG"; break; | |
348 case ROLE_ANNOTATION: result += " ANNOTATION"; break; | |
349 case ROLE_APPLICATION: result += " APPLICATION"; break; | |
350 case ROLE_ARTICLE: result += " ARTICLE"; break; | |
351 case ROLE_BROWSER: result += " BROWSER"; break; | |
352 case ROLE_BUSY_INDICATOR: result += " BUSY_INDICATOR"; break; | |
353 case ROLE_BUTTON: result += " BUTTON"; break; | |
354 case ROLE_CELL: result += " CELL"; break; | |
355 case ROLE_CHECKBOX: result += " CHECKBOX"; break; | |
356 case ROLE_COLOR_WELL: result += " COLOR_WELL"; break; | |
357 case ROLE_COLUMN: result += " COLUMN"; break; | |
358 case ROLE_COLUMN_HEADER: result += " COLUMN_HEADER"; break; | |
359 case ROLE_COMBO_BOX: result += " COMBO_BOX"; break; | |
360 case ROLE_DEFINITION_LIST_DEFINITION: result += " DL_DEFINITION"; break; | |
361 case ROLE_DEFINITION_LIST_TERM: result += " DL_TERM"; break; | |
362 case ROLE_DIALOG: result += " DIALOG"; break; | |
363 case ROLE_DIRECTORY: result += " DIRECTORY"; break; | |
364 case ROLE_DISCLOSURE_TRIANGLE: result += " DISCLOSURE_TRIANGLE"; break; | |
365 case ROLE_DOCUMENT: result += " DOCUMENT"; break; | |
366 case ROLE_DRAWER: result += " DRAWER"; break; | |
367 case ROLE_EDITABLE_TEXT: result += " EDITABLE_TEXT"; break; | |
368 case ROLE_GRID: result += " GRID"; break; | |
369 case ROLE_GROUP: result += " GROUP"; break; | |
370 case ROLE_GROW_AREA: result += " GROW_AREA"; break; | |
371 case ROLE_HEADING: result += " HEADING"; break; | |
372 case ROLE_HELP_TAG: result += " HELP_TAG"; break; | |
373 case ROLE_IGNORED: result += " IGNORED"; break; | |
374 case ROLE_IMAGE: result += " IMAGE"; break; | |
375 case ROLE_IMAGE_MAP: result += " IMAGE_MAP"; break; | |
376 case ROLE_IMAGE_MAP_LINK: result += " IMAGE_MAP_LINK"; break; | |
377 case ROLE_INCREMENTOR: result += " INCREMENTOR"; break; | |
378 case ROLE_LANDMARK_APPLICATION: result += " L_APPLICATION"; break; | |
379 case ROLE_LANDMARK_BANNER: result += " L_BANNER"; break; | |
380 case ROLE_LANDMARK_COMPLEMENTARY: result += " L_COMPLEMENTARY"; break; | |
381 case ROLE_LANDMARK_CONTENTINFO: result += " L_CONTENTINFO"; break; | |
382 case ROLE_LANDMARK_MAIN: result += " L_MAIN"; break; | |
383 case ROLE_LANDMARK_NAVIGATION: result += " L_NAVIGATION"; break; | |
384 case ROLE_LANDMARK_SEARCH: result += " L_SEARCH"; break; | |
385 case ROLE_LINK: result += " LINK"; break; | |
386 case ROLE_LIST: result += " LIST"; break; | |
387 case ROLE_LISTBOX: result += " LISTBOX"; break; | |
388 case ROLE_LISTBOX_OPTION: result += " LISTBOX_OPTION"; break; | |
389 case ROLE_LIST_ITEM: result += " LIST_ITEM"; break; | |
390 case ROLE_LIST_MARKER: result += " LIST_MARKER"; break; | |
391 case ROLE_LOG: result += " LOG"; break; | |
392 case ROLE_MARQUEE: result += " MARQUEE"; break; | |
393 case ROLE_MATH: result += " MATH"; break; | |
394 case ROLE_MATTE: result += " MATTE"; break; | |
395 case ROLE_MENU: result += " MENU"; break; | |
396 case ROLE_MENU_BAR: result += " MENU_BAR"; break; | |
397 case ROLE_MENU_BUTTON: result += " MENU_BUTTON"; break; | |
398 case ROLE_MENU_ITEM: result += " MENU_ITEM"; break; | |
399 case ROLE_MENU_LIST_OPTION: result += " MENU_LIST_OPTION"; break; | |
400 case ROLE_MENU_LIST_POPUP: result += " MENU_LIST_POPUP"; break; | |
401 case ROLE_NOTE: result += " NOTE"; break; | |
402 case ROLE_OUTLINE: result += " OUTLINE"; break; | |
403 case ROLE_POPUP_BUTTON: result += " POPUP_BUTTON"; break; | |
404 case ROLE_PROGRESS_INDICATOR: result += " PROGRESS_INDICATOR"; break; | |
405 case ROLE_RADIO_BUTTON: result += " RADIO_BUTTON"; break; | |
406 case ROLE_RADIO_GROUP: result += " RADIO_GROUP"; break; | |
407 case ROLE_REGION: result += " REGION"; break; | |
408 case ROLE_ROOT_WEB_AREA: result += " ROOT_WEB_AREA"; break; | |
409 case ROLE_ROW: result += " ROW"; break; | |
410 case ROLE_ROW_HEADER: result += " ROW_HEADER"; break; | |
411 case ROLE_RULER: result += " RULER"; break; | |
412 case ROLE_RULER_MARKER: result += " RULER_MARKER"; break; | |
413 case ROLE_SCROLLAREA: result += " SCROLLAREA"; break; | |
414 case ROLE_SCROLLBAR: result += " SCROLLBAR"; break; | |
415 case ROLE_SHEET: result += " SHEET"; break; | |
416 case ROLE_SLIDER: result += " SLIDER"; break; | |
417 case ROLE_SLIDER_THUMB: result += " SLIDER_THUMB"; break; | |
418 case ROLE_SPLITTER: result += " SPLITTER"; break; | |
419 case ROLE_SPLIT_GROUP: result += " SPLIT_GROUP"; break; | |
420 case ROLE_STATIC_TEXT: result += " STATIC_TEXT"; break; | |
421 case ROLE_STATUS: result += " STATUS"; break; | |
422 case ROLE_SYSTEM_WIDE: result += " SYSTEM_WIDE"; break; | |
423 case ROLE_TAB: result += " TAB"; break; | |
424 case ROLE_TABLE: result += " TABLE"; break; | |
425 case ROLE_TABLE_HEADER_CONTAINER: result += " TABLE_HDR_CONTAINER"; break; | |
426 case ROLE_TAB_GROUP_UNUSED: result += " TAB_GROUP_UNUSED"; break; | |
427 case ROLE_TAB_LIST: result += " TAB_LIST"; break; | |
428 case ROLE_TAB_PANEL: result += " TAB_PANEL"; break; | |
429 case ROLE_TEXTAREA: result += " TEXTAREA"; break; | |
430 case ROLE_TEXT_FIELD: result += " TEXT_FIELD"; break; | |
431 case ROLE_TIMER: result += " TIMER"; break; | |
432 case ROLE_TOOLBAR: result += " TOOLBAR"; break; | |
433 case ROLE_TOOLTIP: result += " TOOLTIP"; break; | |
434 case ROLE_TREE: result += " TREE"; break; | |
435 case ROLE_TREE_GRID: result += " TREE_GRID"; break; | |
436 case ROLE_TREE_ITEM: result += " TREE_ITEM"; break; | |
437 case ROLE_UNKNOWN: result += " UNKNOWN"; break; | |
438 case ROLE_VALUE_INDICATOR: result += " VALUE_INDICATOR"; break; | |
439 case ROLE_WEBCORE_LINK: result += " WEBCORE_LINK"; break; | |
440 case ROLE_WEB_AREA: result += " WEB_AREA"; break; | |
441 case ROLE_WINDOW: result += " WINDOW"; break; | |
442 default: | |
443 assert(false); | |
444 } | |
445 | |
446 if (state & (1 << STATE_BUSY)) | |
447 result += " BUSY"; | |
448 if (state & (1 << STATE_CHECKED)) | |
449 result += " CHECKED"; | |
450 if (state & (1 << STATE_COLLAPSED)) | |
451 result += " COLLAPSED"; | |
452 if (state & (1 << STATE_EXPANDED)) | |
453 result += " EXPANDED"; | |
454 if (state & (1 << STATE_FOCUSABLE)) | |
455 result += " FOCUSABLE"; | |
456 if (state & (1 << STATE_FOCUSED)) | |
457 result += " FOCUSED"; | |
458 if (state & (1 << STATE_HASPOPUP)) | |
459 result += " HASPOPUP"; | |
460 if (state & (1 << STATE_HOTTRACKED)) | |
461 result += " HOTTRACKED"; | |
462 if (state & (1 << STATE_INDETERMINATE)) | |
463 result += " INDETERMINATE"; | |
464 if (state & (1 << STATE_INVISIBLE)) | |
465 result += " INVISIBLE"; | |
466 if (state & (1 << STATE_LINKED)) | |
467 result += " LINKED"; | |
468 if (state & (1 << STATE_MULTISELECTABLE)) | |
469 result += " MULTISELECTABLE"; | |
470 if (state & (1 << STATE_OFFSCREEN)) | |
471 result += " OFFSCREEN"; | |
472 if (state & (1 << STATE_PRESSED)) | |
473 result += " PRESSED"; | |
474 if (state & (1 << STATE_PROTECTED)) | |
475 result += " PROTECTED"; | |
476 if (state & (1 << STATE_READONLY)) | |
477 result += " READONLY"; | |
478 if (state & (1 << STATE_REQUIRED)) | |
479 result += " REQUIRED"; | |
480 if (state & (1 << STATE_SELECTABLE)) | |
481 result += " SELECTABLE"; | |
482 if (state & (1 << STATE_SELECTED)) | |
483 result += " SELECTED"; | |
484 if (state & (1 << STATE_TRAVERSED)) | |
485 result += " TRAVERSED"; | |
486 if (state & (1 << STATE_UNAVAILABLE)) | |
487 result += " UNAVAILABLE"; | |
488 if (state & (1 << STATE_VERTICAL)) | |
489 result += " VERTICAL"; | |
490 if (state & (1 << STATE_VISITED)) | |
491 result += " VISITED"; | |
492 | |
493 std::string tmp = UTF16ToUTF8(name); | |
494 RemoveChars(tmp, "\n", &tmp); | |
495 if (!tmp.empty()) | |
496 result += " name=" + tmp; | |
497 | |
498 tmp = UTF16ToUTF8(value); | |
499 RemoveChars(tmp, "\n", &tmp); | |
500 if (!tmp.empty()) | |
501 result += " value=" + tmp; | |
502 | |
503 result += " (" + IntToString(location.x()) + ", " + | |
504 IntToString(location.y()) + ")-(" + | |
505 IntToString(location.width()) + ", " + | |
506 IntToString(location.height()) + ")"; | |
507 | |
508 for (std::map<IntAttribute, int32>::const_iterator iter = | |
509 int_attributes.begin(); | |
510 iter != int_attributes.end(); | |
511 ++iter) { | |
512 std::string value = IntToString(iter->second); | |
513 switch (iter->first) { | |
514 case ATTR_SCROLL_X: | |
515 result += " scroll_x=" + value; | |
516 break; | |
517 case ATTR_SCROLL_X_MIN: | |
518 result += " scroll_x_min=" + value; | |
519 break; | |
520 case ATTR_SCROLL_X_MAX: | |
521 result += " scroll_x_max=" + value; | |
522 break; | |
523 case ATTR_SCROLL_Y: | |
524 result += " scroll_y=" + value; | |
525 break; | |
526 case ATTR_SCROLL_Y_MIN: | |
527 result += " scroll_y_min=" + value; | |
528 break; | |
529 case ATTR_SCROLL_Y_MAX: | |
530 result += " scroll_y_max=" + value; | |
531 break; | |
532 case ATTR_HIERARCHICAL_LEVEL: | |
533 result += " level=" + value; | |
534 break; | |
535 case ATTR_TEXT_SEL_START: | |
536 result += " sel_start=" + value; | |
537 break; | |
538 case ATTR_TEXT_SEL_END: | |
539 result += " sel_end=" + value; | |
540 break; | |
541 case ATTR_TABLE_ROW_COUNT: | |
542 result += " rows=" + value; | |
543 break; | |
544 case ATTR_TABLE_COLUMN_COUNT: | |
545 result += " cols=" + value; | |
546 break; | |
547 case ATTR_TABLE_CELL_COLUMN_INDEX: | |
548 result += " col=" + value; | |
549 break; | |
550 case ATTR_TABLE_CELL_ROW_INDEX: | |
551 result += " row=" + value; | |
552 break; | |
553 case ATTR_TABLE_CELL_COLUMN_SPAN: | |
554 result += " colspan=" + value; | |
555 break; | |
556 case ATTR_TABLE_CELL_ROW_SPAN: | |
557 result += " rowspan=" + value; | |
558 break; | |
559 case ATTR_TITLE_UI_ELEMENT: | |
560 result += " title_elem=" + value; | |
561 break; | |
562 } | |
563 } | |
564 | |
565 for (std::map<StringAttribute, string16>::const_iterator iter = | |
566 string_attributes.begin(); | |
567 iter != string_attributes.end(); | |
568 ++iter) { | |
569 std::string value = UTF16ToUTF8(iter->second); | |
570 switch (iter->first) { | |
571 case ATTR_DOC_URL: | |
572 result += " doc_url=" + value; | |
573 break; | |
574 case ATTR_DOC_TITLE: | |
575 result += " doc_title=" + value; | |
576 break; | |
577 case ATTR_DOC_MIMETYPE: | |
578 result += " doc_mimetype=" + value; | |
579 break; | |
580 case ATTR_DOC_DOCTYPE: | |
581 result += " doc_doctype=" + value; | |
582 break; | |
583 case ATTR_ACCESS_KEY: | |
584 result += " access_key=" + value; | |
585 break; | |
586 case ATTR_ACTION: | |
587 result += " action=" + value; | |
588 break; | |
589 case ATTR_DESCRIPTION: | |
590 result += " description=" + value; | |
591 break; | |
592 case ATTR_DISPLAY: | |
593 result += " display=" + value; | |
594 break; | |
595 case ATTR_HELP: | |
596 result += " help=" + value; | |
597 break; | |
598 case ATTR_HTML_TAG: | |
599 result += " html_tag=" + value; | |
600 break; | |
601 case ATTR_LIVE_RELEVANT: | |
602 result += " relevant=" + value; | |
603 break; | |
604 case ATTR_LIVE_STATUS: | |
605 result += " live=" + value; | |
606 break; | |
607 case ATTR_CONTAINER_LIVE_RELEVANT: | |
608 result += " container_relevant=" + value; | |
609 break; | |
610 case ATTR_CONTAINER_LIVE_STATUS: | |
611 result += " container_live=" + value; | |
612 break; | |
613 case ATTR_ROLE: | |
614 result += " role=" + value; | |
615 break; | |
616 case ATTR_SHORTCUT: | |
617 result += " shortcut=" + value; | |
618 break; | |
619 case ATTR_URL: | |
620 result += " url=" + value; | |
621 break; | |
622 } | |
623 } | |
624 | |
625 for (std::map<FloatAttribute, float>::const_iterator iter = | |
626 float_attributes.begin(); | |
627 iter != float_attributes.end(); | |
628 ++iter) { | |
629 std::string value = DoubleToString(iter->second); | |
630 switch (iter->first) { | |
631 case ATTR_DOC_LOADING_PROGRESS: | |
632 result += " doc_progress=" + value; | |
633 break; | |
634 case ATTR_VALUE_FOR_RANGE: | |
635 result += " value_for_range=" + value; | |
636 break; | |
637 case ATTR_MAX_VALUE_FOR_RANGE: | |
638 result += " max_value=" + value; | |
639 break; | |
640 case ATTR_MIN_VALUE_FOR_RANGE: | |
641 result += " min_value=" + value; | |
642 break; | |
643 } | |
644 } | |
645 | |
646 for (std::map<BoolAttribute, bool>::const_iterator iter = | |
647 bool_attributes.begin(); | |
648 iter != bool_attributes.end(); | |
649 ++iter) { | |
650 std::string value = iter->second ? "true" : "false"; | |
651 switch (iter->first) { | |
652 case ATTR_DOC_LOADED: | |
653 result += " doc_loaded=" + value; | |
654 break; | |
655 case ATTR_BUTTON_MIXED: | |
656 result += " mixed=" + value; | |
657 break; | |
658 case ATTR_LIVE_ATOMIC: | |
659 result += " atomic=" + value; | |
660 break; | |
661 case ATTR_LIVE_BUSY: | |
662 result += " busy=" + value; | |
663 break; | |
664 case ATTR_CONTAINER_LIVE_ATOMIC: | |
665 result += " container_atomic=" + value; | |
666 break; | |
667 case ATTR_CONTAINER_LIVE_BUSY: | |
668 result += " container_busy=" + value; | |
669 break; | |
670 case ATTR_ARIA_READONLY: | |
671 result += " aria_readonly=" + value; | |
672 break; | |
673 case ATTR_CAN_SET_VALUE: | |
674 result += " can_set_value=" + value; | |
675 break; | |
676 } | |
677 } | |
678 | |
679 if (!children.empty()) | |
680 result += " children=" + IntToString(children.size()); | |
681 | |
682 if (!indirect_child_ids.empty()) | |
683 result += " indirect_child_ids=" + IntVectorToString(indirect_child_ids); | |
684 | |
685 if (!line_breaks.empty()) | |
686 result += " line_breaks=" + IntVectorToString(line_breaks); | |
687 | |
688 if (!cell_ids.empty()) | |
689 result += " cell_ids=" + IntVectorToString(cell_ids); | |
690 | |
691 if (recursive) { | |
692 result += "\n"; | |
693 ++indent; | |
694 for (size_t i = 0; i < children.size(); ++i) | |
695 result += children[i].DebugString(true); | |
696 --indent; | |
697 } | |
698 | |
699 return result; | |
700 } | |
701 #endif // ifndef NDEBUG | |
702 | |
703 void WebAccessibility::Init(const WebKit::WebAccessibilityObject& src, | |
704 IncludeChildren include_children, | |
705 IncludeLineBreaks include_line_breaks) { | |
706 name = src.title(); | |
707 role = ConvertRole(src.roleValue()); | |
708 state = ConvertState(src); | |
709 location = src.boundingBoxRect(); | |
710 id = src.axID(); | |
711 | |
712 if (src.valueDescription().length()) | |
713 value = src.valueDescription(); | |
714 else | |
715 value = src.stringValue(); | |
716 | |
717 if (src.accessKey().length()) | |
718 string_attributes[ATTR_ACCESS_KEY] = src.accessKey(); | |
719 if (src.actionVerb().length()) | |
720 string_attributes[ATTR_ACTION] = src.actionVerb(); | |
721 if (src.isAriaReadOnly()) | |
722 bool_attributes[ATTR_ARIA_READONLY] = true; | |
723 if (src.isButtonStateMixed()) | |
724 bool_attributes[ATTR_BUTTON_MIXED] = true; | |
725 if (src.canSetValueAttribute()) | |
726 bool_attributes[ATTR_CAN_SET_VALUE] = true; | |
727 if (src.accessibilityDescription().length()) | |
728 string_attributes[ATTR_DESCRIPTION] = src.accessibilityDescription(); | |
729 if (src.hasComputedStyle()) | |
730 string_attributes[ATTR_DISPLAY] = src.computedStyleDisplay(); | |
731 if (src.helpText().length()) | |
732 string_attributes[ATTR_HELP] = src.helpText(); | |
733 if (src.keyboardShortcut().length()) | |
734 string_attributes[ATTR_SHORTCUT] = src.keyboardShortcut(); | |
735 if (src.titleUIElement().isValid()) | |
736 int_attributes[ATTR_TITLE_UI_ELEMENT] = src.titleUIElement().axID(); | |
737 if (!src.url().isEmpty()) | |
738 string_attributes[ATTR_URL] = src.url().spec().utf16(); | |
739 | |
740 if (role == ROLE_TREE_ITEM) | |
741 int_attributes[ATTR_HIERARCHICAL_LEVEL] = src.hierarchicalLevel(); | |
742 | |
743 if (role == ROLE_SLIDER) | |
744 include_children = NO_CHILDREN; | |
745 | |
746 // Treat the active list box item as focused. | |
747 if (role == ROLE_LISTBOX_OPTION && src.isSelectedOptionActive()) | |
748 state |= (1 << WebAccessibility::STATE_FOCUSED); | |
749 | |
750 WebKit::WebNode node = src.node(); | |
751 bool is_iframe = false; | |
752 | |
753 if (!node.isNull() && node.isElementNode()) { | |
754 WebKit::WebElement element = node.to<WebKit::WebElement>(); | |
755 is_iframe = (element.tagName() == ASCIIToUTF16("IFRAME")); | |
756 | |
757 // TODO(ctguil): The tagName in WebKit is lower cased but | |
758 // HTMLElement::nodeName calls localNameUpper. Consider adding | |
759 // a WebElement method that returns the original lower cased tagName. | |
760 string_attributes[ATTR_HTML_TAG] = | |
761 StringToLowerASCII(string16(element.tagName())); | |
762 for (unsigned i = 0; i < element.attributeCount(); ++i) { | |
763 string16 name = StringToLowerASCII(string16( | |
764 element.attributeLocalName(i))); | |
765 string16 value = element.attributeValue(i); | |
766 html_attributes.push_back(std::pair<string16, string16>(name, value)); | |
767 } | |
768 | |
769 if (role == ROLE_EDITABLE_TEXT || | |
770 role == ROLE_TEXTAREA || | |
771 role == ROLE_TEXT_FIELD) { | |
772 // Jaws gets confused by children of text fields, so we ignore them. | |
773 include_children = NO_CHILDREN; | |
774 | |
775 int_attributes[ATTR_TEXT_SEL_START] = src.selectionStart(); | |
776 int_attributes[ATTR_TEXT_SEL_END] = src.selectionEnd(); | |
777 | |
778 if (include_line_breaks == INCLUDE_LINE_BREAKS) { | |
779 WebKit::WebVector<int> src_line_breaks; | |
780 src.lineBreaks(src_line_breaks); | |
781 line_breaks.reserve(src_line_breaks.size()); | |
782 for (size_t i = 0; i < src_line_breaks.size(); ++i) | |
783 line_breaks.push_back(src_line_breaks[i]); | |
784 } | |
785 } | |
786 | |
787 // ARIA role. | |
788 if (element.hasAttribute("role")) { | |
789 string_attributes[ATTR_ROLE] = element.getAttribute("role"); | |
790 } | |
791 | |
792 // Live region attributes | |
793 if (element.hasAttribute("aria-atomic")) { | |
794 bool_attributes[ATTR_LIVE_ATOMIC] = | |
795 LowerCaseEqualsASCII(element.getAttribute("aria-atomic"), "true"); | |
796 } | |
797 if (element.hasAttribute("aria-busy")) { | |
798 bool_attributes[ATTR_LIVE_BUSY] = | |
799 LowerCaseEqualsASCII(element.getAttribute("aria-busy"), "true"); | |
800 } | |
801 if (element.hasAttribute("aria-live")) { | |
802 string_attributes[ATTR_LIVE_STATUS] = element.getAttribute("aria-live"); | |
803 } | |
804 if (element.hasAttribute("aria-relevant")) { | |
805 string_attributes[ATTR_LIVE_RELEVANT] = | |
806 element.getAttribute("aria-relevant"); | |
807 } | |
808 } | |
809 | |
810 // Walk up the parent chain to set live region attributes of containers | |
811 | |
812 WebKit::WebAccessibilityObject container_accessible = src; | |
813 while (!container_accessible.isNull()) { | |
814 WebKit::WebNode container_node = container_accessible.node(); | |
815 if (!container_node.isNull() && container_node.isElementNode()) { | |
816 WebKit::WebElement container_elem = | |
817 container_node.to<WebKit::WebElement>(); | |
818 if (container_elem.hasAttribute("aria-atomic") && | |
819 bool_attributes.find(ATTR_CONTAINER_LIVE_ATOMIC) == | |
820 bool_attributes.end()) { | |
821 bool_attributes[ATTR_CONTAINER_LIVE_ATOMIC] = | |
822 LowerCaseEqualsASCII(container_elem.getAttribute("aria-atomic"), | |
823 "true"); | |
824 } | |
825 if (container_elem.hasAttribute("aria-busy") && | |
826 bool_attributes.find(ATTR_CONTAINER_LIVE_BUSY) == | |
827 bool_attributes.end()) { | |
828 bool_attributes[ATTR_CONTAINER_LIVE_BUSY] = | |
829 LowerCaseEqualsASCII(container_elem.getAttribute("aria-busy"), | |
830 "true"); | |
831 } | |
832 if (container_elem.hasAttribute("aria-live") && | |
833 string_attributes.find(ATTR_CONTAINER_LIVE_STATUS) == | |
834 string_attributes.end()) { | |
835 string_attributes[ATTR_CONTAINER_LIVE_STATUS] = | |
836 container_elem.getAttribute("aria-live"); | |
837 } | |
838 if (container_elem.hasAttribute("aria-relevant") && | |
839 string_attributes.find(ATTR_CONTAINER_LIVE_RELEVANT) == | |
840 string_attributes.end()) { | |
841 string_attributes[ATTR_CONTAINER_LIVE_RELEVANT] = | |
842 container_elem.getAttribute("aria-relevant"); | |
843 } | |
844 } | |
845 container_accessible = container_accessible.parentObject(); | |
846 } | |
847 | |
848 if (role == WebAccessibility::ROLE_PROGRESS_INDICATOR || | |
849 role == WebAccessibility::ROLE_SCROLLBAR || | |
850 role == WebAccessibility::ROLE_SLIDER) { | |
851 float_attributes[ATTR_VALUE_FOR_RANGE] = src.valueForRange(); | |
852 float_attributes[ATTR_MAX_VALUE_FOR_RANGE] = src.minValueForRange(); | |
853 float_attributes[ATTR_MIN_VALUE_FOR_RANGE] = src.maxValueForRange(); | |
854 } | |
855 | |
856 if (role == WebAccessibility::ROLE_DOCUMENT || | |
857 role == WebAccessibility::ROLE_WEB_AREA) { | |
858 const WebKit::WebDocument& document = src.document(); | |
859 if (name.empty()) | |
860 name = document.title(); | |
861 string_attributes[ATTR_DOC_TITLE] = document.title(); | |
862 string_attributes[ATTR_DOC_URL] = document.url().spec().utf16(); | |
863 if (document.isXHTMLDocument()) | |
864 string_attributes[ATTR_DOC_MIMETYPE] = WebKit::WebString("text/xhtml"); | |
865 else | |
866 string_attributes[ATTR_DOC_MIMETYPE] = WebKit::WebString("text/html"); | |
867 bool_attributes[ATTR_DOC_LOADED] = src.isLoaded(); | |
868 float_attributes[ATTR_DOC_LOADING_PROGRESS] = | |
869 src.estimatedLoadingProgress(); | |
870 | |
871 const WebKit::WebDocumentType& doctype = document.doctype(); | |
872 if (!doctype.isNull()) | |
873 string_attributes[ATTR_DOC_DOCTYPE] = doctype.name(); | |
874 | |
875 const gfx::Size& scroll_offset = document.frame()->scrollOffset(); | |
876 int_attributes[ATTR_SCROLL_X] = scroll_offset.width(); | |
877 int_attributes[ATTR_SCROLL_Y] = scroll_offset.height(); | |
878 | |
879 const gfx::Size& min_offset = document.frame()->minimumScrollOffset(); | |
880 int_attributes[ATTR_SCROLL_X_MIN] = min_offset.width(); | |
881 int_attributes[ATTR_SCROLL_Y_MIN] = min_offset.height(); | |
882 | |
883 const gfx::Size& max_offset = document.frame()->maximumScrollOffset(); | |
884 int_attributes[ATTR_SCROLL_X_MAX] = max_offset.width(); | |
885 int_attributes[ATTR_SCROLL_Y_MAX] = max_offset.height(); | |
886 } | |
887 | |
888 if (role == WebAccessibility::ROLE_TABLE) { | |
889 int column_count = src.columnCount(); | |
890 int row_count = src.rowCount(); | |
891 if (column_count > 0 && row_count > 0) { | |
892 std::set<int> unique_cell_id_set; | |
893 int_attributes[ATTR_TABLE_COLUMN_COUNT] = column_count; | |
894 int_attributes[ATTR_TABLE_ROW_COUNT] = row_count; | |
895 for (int i = 0; i < column_count * row_count; ++i) { | |
896 WebAccessibilityObject cell = src.cellForColumnAndRow( | |
897 i % column_count, i / column_count); | |
898 int cell_id = -1; | |
899 if (!cell.isNull()) { | |
900 cell_id = cell.axID(); | |
901 if (unique_cell_id_set.find(cell_id) == unique_cell_id_set.end()) { | |
902 unique_cell_id_set.insert(cell_id); | |
903 unique_cell_ids.push_back(cell_id); | |
904 } | |
905 } | |
906 cell_ids.push_back(cell_id); | |
907 } | |
908 } | |
909 } | |
910 | |
911 if (role == WebAccessibility::ROLE_CELL || | |
912 role == WebAccessibility::ROLE_ROW_HEADER || | |
913 role == WebAccessibility::ROLE_COLUMN_HEADER) { | |
914 int_attributes[ATTR_TABLE_CELL_COLUMN_INDEX] = src.cellColumnIndex(); | |
915 int_attributes[ATTR_TABLE_CELL_COLUMN_SPAN] = src.cellColumnSpan(); | |
916 int_attributes[ATTR_TABLE_CELL_ROW_INDEX] = src.cellRowIndex(); | |
917 int_attributes[ATTR_TABLE_CELL_ROW_SPAN] = src.cellRowSpan(); | |
918 } | |
919 | |
920 if (include_children == INCLUDE_CHILDREN) { | |
921 // Recursively create children. | |
922 int child_count = src.childCount(); | |
923 std::set<int32> child_ids; | |
924 for (int i = 0; i < child_count; ++i) { | |
925 WebAccessibilityObject child = src.childAt(i); | |
926 int32 child_id = child.axID(); | |
927 | |
928 // The child may be invalid due to issues in webkit accessibility code. | |
929 // Don't add children that are invalid thus preventing a crash. | |
930 // https://bugs.webkit.org/show_bug.cgi?id=44149 | |
931 // TODO(ctguil): We may want to remove this check as webkit stabilizes. | |
932 if (!child.isValid()) | |
933 continue; | |
934 | |
935 // Children may duplicated in the webkit accessibility tree. Only add a | |
936 // child once for the web accessibility tree. | |
937 // https://bugs.webkit.org/show_bug.cgi?id=58930 | |
938 if (child_ids.find(child_id) != child_ids.end()) | |
939 continue; | |
940 child_ids.insert(child_id); | |
941 | |
942 // Some nodes appear in the tree in more than one place: for example, | |
943 // a cell in a table appears as a child of both a row and a column. | |
944 // Only recursively add child nodes that have this node as its | |
945 // unignored parent. For child nodes that are actually parented to | |
946 // somethinng else, store only the ID. | |
947 // | |
948 // As an exception, also add children of an iframe element. | |
949 // https://bugs.webkit.org/show_bug.cgi?id=57066 | |
950 if (is_iframe || IsParentUnignoredOf(src, child)) { | |
951 children.push_back( | |
952 WebAccessibility(child, include_children, include_line_breaks)); | |
953 } else { | |
954 indirect_child_ids.push_back(child_id); | |
955 } | |
956 } | |
957 } | |
958 } | |
959 | |
960 bool WebAccessibility::IsParentUnignoredOf( | |
961 const WebKit::WebAccessibilityObject& ancestor, | |
962 const WebKit::WebAccessibilityObject& child) { | |
963 WebKit::WebAccessibilityObject parent = child.parentObject(); | |
964 while (!parent.isNull() && parent.accessibilityIsIgnored()) | |
965 parent = parent.parentObject(); | |
966 return parent.equals(ancestor); | |
967 } | |
968 | |
969 } // namespace webkit_glue | |
OLD | NEW |