OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 // TODO(hajimehoshi): Remove this when UnsafePersistent is removed. | |
6 #define V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR | |
7 | |
8 #include "content/shell/renderer/test_runner/web_ax_object_proxy.h" | |
9 | |
10 #include "base/strings/stringprintf.h" | |
11 #include "gin/handle.h" | |
12 #include "third_party/WebKit/public/platform/WebPoint.h" | |
13 #include "third_party/WebKit/public/platform/WebRect.h" | |
14 #include "third_party/WebKit/public/platform/WebString.h" | |
15 #include "third_party/WebKit/public/web/WebFrame.h" | |
16 #include "third_party/WebKit/public/web/WebKit.h" | |
17 | |
18 namespace content { | |
19 | |
20 namespace { | |
21 | |
22 // Map role value to string, matching Safari/Mac platform implementation to | |
23 // avoid rebaselining layout tests. | |
24 std::string RoleToString(blink::WebAXRole role) | |
25 { | |
26 std::string result = "AXRole: AX"; | |
27 switch (role) { | |
28 case blink::WebAXRoleAlertDialog: | |
29 return result.append("AlertDialog"); | |
30 case blink::WebAXRoleAlert: | |
31 return result.append("Alert"); | |
32 case blink::WebAXRoleAnnotation: | |
33 return result.append("Annotation"); | |
34 case blink::WebAXRoleApplication: | |
35 return result.append("Application"); | |
36 case blink::WebAXRoleArticle: | |
37 return result.append("Article"); | |
38 case blink::WebAXRoleBanner: | |
39 return result.append("Banner"); | |
40 case blink::WebAXRoleBrowser: | |
41 return result.append("Browser"); | |
42 case blink::WebAXRoleBusyIndicator: | |
43 return result.append("BusyIndicator"); | |
44 case blink::WebAXRoleButton: | |
45 return result.append("Button"); | |
46 case blink::WebAXRoleCanvas: | |
47 return result.append("Canvas"); | |
48 case blink::WebAXRoleCell: | |
49 return result.append("Cell"); | |
50 case blink::WebAXRoleCheckBox: | |
51 return result.append("CheckBox"); | |
52 case blink::WebAXRoleColorWell: | |
53 return result.append("ColorWell"); | |
54 case blink::WebAXRoleColumnHeader: | |
55 return result.append("ColumnHeader"); | |
56 case blink::WebAXRoleColumn: | |
57 return result.append("Column"); | |
58 case blink::WebAXRoleComboBox: | |
59 return result.append("ComboBox"); | |
60 case blink::WebAXRoleComplementary: | |
61 return result.append("Complementary"); | |
62 case blink::WebAXRoleContentInfo: | |
63 return result.append("ContentInfo"); | |
64 case blink::WebAXRoleDefinition: | |
65 return result.append("Definition"); | |
66 case blink::WebAXRoleDescriptionListDetail: | |
67 return result.append("DescriptionListDetail"); | |
68 case blink::WebAXRoleDescriptionListTerm: | |
69 return result.append("DescriptionListTerm"); | |
70 case blink::WebAXRoleDialog: | |
71 return result.append("Dialog"); | |
72 case blink::WebAXRoleDirectory: | |
73 return result.append("Directory"); | |
74 case blink::WebAXRoleDisclosureTriangle: | |
75 return result.append("DisclosureTriangle"); | |
76 case blink::WebAXRoleDiv: | |
77 return result.append("Div"); | |
78 case blink::WebAXRoleDocument: | |
79 return result.append("Document"); | |
80 case blink::WebAXRoleDrawer: | |
81 return result.append("Drawer"); | |
82 case blink::WebAXRoleEditableText: | |
83 return result.append("EditableText"); | |
84 case blink::WebAXRoleFooter: | |
85 return result.append("Footer"); | |
86 case blink::WebAXRoleForm: | |
87 return result.append("Form"); | |
88 case blink::WebAXRoleGrid: | |
89 return result.append("Grid"); | |
90 case blink::WebAXRoleGroup: | |
91 return result.append("Group"); | |
92 case blink::WebAXRoleGrowArea: | |
93 return result.append("GrowArea"); | |
94 case blink::WebAXRoleHeading: | |
95 return result.append("Heading"); | |
96 case blink::WebAXRoleHelpTag: | |
97 return result.append("HelpTag"); | |
98 case blink::WebAXRoleHorizontalRule: | |
99 return result.append("HorizontalRule"); | |
100 case blink::WebAXRoleIgnored: | |
101 return result.append("Ignored"); | |
102 case blink::WebAXRoleImageMapLink: | |
103 return result.append("ImageMapLink"); | |
104 case blink::WebAXRoleImageMap: | |
105 return result.append("ImageMap"); | |
106 case blink::WebAXRoleImage: | |
107 return result.append("Image"); | |
108 case blink::WebAXRoleIncrementor: | |
109 return result.append("Incrementor"); | |
110 case blink::WebAXRoleInlineTextBox: | |
111 return result.append("InlineTextBox"); | |
112 case blink::WebAXRoleLabel: | |
113 return result.append("Label"); | |
114 case blink::WebAXRoleLegend: | |
115 return result.append("Legend"); | |
116 case blink::WebAXRoleLink: | |
117 return result.append("Link"); | |
118 case blink::WebAXRoleListBoxOption: | |
119 return result.append("ListBoxOption"); | |
120 case blink::WebAXRoleListBox: | |
121 return result.append("ListBox"); | |
122 case blink::WebAXRoleListItem: | |
123 return result.append("ListItem"); | |
124 case blink::WebAXRoleListMarker: | |
125 return result.append("ListMarker"); | |
126 case blink::WebAXRoleList: | |
127 return result.append("List"); | |
128 case blink::WebAXRoleLog: | |
129 return result.append("Log"); | |
130 case blink::WebAXRoleMain: | |
131 return result.append("Main"); | |
132 case blink::WebAXRoleMarquee: | |
133 return result.append("Marquee"); | |
134 case blink::WebAXRoleMathElement: | |
135 return result.append("MathElement"); | |
136 case blink::WebAXRoleMath: | |
137 return result.append("Math"); | |
138 case blink::WebAXRoleMatte: | |
139 return result.append("Matte"); | |
140 case blink::WebAXRoleMenuBar: | |
141 return result.append("MenuBar"); | |
142 case blink::WebAXRoleMenuButton: | |
143 return result.append("MenuButton"); | |
144 case blink::WebAXRoleMenuItem: | |
145 return result.append("MenuItem"); | |
146 case blink::WebAXRoleMenuListOption: | |
147 return result.append("MenuListOption"); | |
148 case blink::WebAXRoleMenuListPopup: | |
149 return result.append("MenuListPopup"); | |
150 case blink::WebAXRoleMenu: | |
151 return result.append("Menu"); | |
152 case blink::WebAXRoleNavigation: | |
153 return result.append("Navigation"); | |
154 case blink::WebAXRoleNote: | |
155 return result.append("Note"); | |
156 case blink::WebAXRoleOutline: | |
157 return result.append("Outline"); | |
158 case blink::WebAXRoleParagraph: | |
159 return result.append("Paragraph"); | |
160 case blink::WebAXRolePopUpButton: | |
161 return result.append("PopUpButton"); | |
162 case blink::WebAXRolePresentational: | |
163 return result.append("Presentational"); | |
164 case blink::WebAXRoleProgressIndicator: | |
165 return result.append("ProgressIndicator"); | |
166 case blink::WebAXRoleRadioButton: | |
167 return result.append("RadioButton"); | |
168 case blink::WebAXRoleRadioGroup: | |
169 return result.append("RadioGroup"); | |
170 case blink::WebAXRoleRegion: | |
171 return result.append("Region"); | |
172 case blink::WebAXRoleRootWebArea: | |
173 return result.append("RootWebArea"); | |
174 case blink::WebAXRoleRowHeader: | |
175 return result.append("RowHeader"); | |
176 case blink::WebAXRoleRow: | |
177 return result.append("Row"); | |
178 case blink::WebAXRoleRulerMarker: | |
179 return result.append("RulerMarker"); | |
180 case blink::WebAXRoleRuler: | |
181 return result.append("Ruler"); | |
182 case blink::WebAXRoleSVGRoot: | |
183 return result.append("SVGRoot"); | |
184 case blink::WebAXRoleScrollArea: | |
185 return result.append("ScrollArea"); | |
186 case blink::WebAXRoleScrollBar: | |
187 return result.append("ScrollBar"); | |
188 case blink::WebAXRoleSeamlessWebArea: | |
189 return result.append("SeamlessWebArea"); | |
190 case blink::WebAXRoleSearch: | |
191 return result.append("Search"); | |
192 case blink::WebAXRoleSheet: | |
193 return result.append("Sheet"); | |
194 case blink::WebAXRoleSlider: | |
195 return result.append("Slider"); | |
196 case blink::WebAXRoleSliderThumb: | |
197 return result.append("SliderThumb"); | |
198 case blink::WebAXRoleSpinButtonPart: | |
199 return result.append("SpinButtonPart"); | |
200 case blink::WebAXRoleSpinButton: | |
201 return result.append("SpinButton"); | |
202 case blink::WebAXRoleSplitGroup: | |
203 return result.append("SplitGroup"); | |
204 case blink::WebAXRoleSplitter: | |
205 return result.append("Splitter"); | |
206 case blink::WebAXRoleStaticText: | |
207 return result.append("StaticText"); | |
208 case blink::WebAXRoleStatus: | |
209 return result.append("Status"); | |
210 case blink::WebAXRoleSystemWide: | |
211 return result.append("SystemWide"); | |
212 case blink::WebAXRoleTabGroup: | |
213 return result.append("TabGroup"); | |
214 case blink::WebAXRoleTabList: | |
215 return result.append("TabList"); | |
216 case blink::WebAXRoleTabPanel: | |
217 return result.append("TabPanel"); | |
218 case blink::WebAXRoleTab: | |
219 return result.append("Tab"); | |
220 case blink::WebAXRoleTableHeaderContainer: | |
221 return result.append("TableHeaderContainer"); | |
222 case blink::WebAXRoleTable: | |
223 return result.append("Table"); | |
224 case blink::WebAXRoleTextArea: | |
225 return result.append("TextArea"); | |
226 case blink::WebAXRoleTextField: | |
227 return result.append("TextField"); | |
228 case blink::WebAXRoleTimer: | |
229 return result.append("Timer"); | |
230 case blink::WebAXRoleToggleButton: | |
231 return result.append("ToggleButton"); | |
232 case blink::WebAXRoleToolbar: | |
233 return result.append("Toolbar"); | |
234 case blink::WebAXRoleTreeGrid: | |
235 return result.append("TreeGrid"); | |
236 case blink::WebAXRoleTreeItem: | |
237 return result.append("TreeItem"); | |
238 case blink::WebAXRoleTree: | |
239 return result.append("Tree"); | |
240 case blink::WebAXRoleUnknown: | |
241 return result.append("Unknown"); | |
242 case blink::WebAXRoleUserInterfaceTooltip: | |
243 return result.append("UserInterfaceTooltip"); | |
244 case blink::WebAXRoleValueIndicator: | |
245 return result.append("ValueIndicator"); | |
246 case blink::WebAXRoleWebArea: | |
247 return result.append("WebArea"); | |
248 case blink::WebAXRoleWindow: | |
249 return result.append("Window"); | |
250 default: | |
251 return result.append("Unknown"); | |
252 } | |
253 } | |
254 | |
255 std::string GetDescription(const blink::WebAXObject& object) { | |
256 std::string description = object.accessibilityDescription().utf8(); | |
257 return description.insert(0, "AXDescription: "); | |
258 } | |
259 | |
260 std::string GetHelpText(const blink::WebAXObject& object) { | |
261 std::string help_text = object.helpText().utf8(); | |
262 return help_text.insert(0, "AXHelp: "); | |
263 } | |
264 | |
265 std::string GetStringValue(const blink::WebAXObject& object) { | |
266 std::string value; | |
267 if (object.role() == blink::WebAXRoleColorWell) { | |
268 int r, g, b; | |
269 object.colorValue(r, g, b); | |
270 value = base::StringPrintf("rgb %7.5f %7.5f %7.5f 1", | |
271 r / 255., g / 255., b / 255.); | |
272 } else { | |
273 value = object.stringValue().utf8(); | |
274 } | |
275 return value.insert(0, "AXValue: "); | |
276 } | |
277 | |
278 std::string GetRole(const blink::WebAXObject& object) { | |
279 std::string role_string = RoleToString(object.role()); | |
280 | |
281 // Special-case canvas with fallback content because Chromium wants to treat | |
282 // this as essentially a separate role that it can map differently depending | |
283 // on the platform. | |
284 if (object.role() == blink::WebAXRoleCanvas && | |
285 object.canvasHasFallbackContent()) { | |
286 role_string += "WithFallbackContent"; | |
287 } | |
288 | |
289 return role_string; | |
290 } | |
291 | |
292 std::string GetTitle(const blink::WebAXObject& object) { | |
293 std::string title = object.title().utf8(); | |
294 return title.insert(0, "AXTitle: "); | |
295 } | |
296 | |
297 std::string GetOrientation(const blink::WebAXObject& object) { | |
298 if (object.isVertical()) | |
299 return "AXOrientation: AXVerticalOrientation"; | |
300 | |
301 return "AXOrientation: AXHorizontalOrientation"; | |
302 } | |
303 | |
304 std::string GetValueDescription(const blink::WebAXObject& object) { | |
305 std::string value_description = object.valueDescription().utf8(); | |
306 return value_description.insert(0, "AXValueDescription: "); | |
307 } | |
308 | |
309 std::string GetAttributes(const blink::WebAXObject& object) { | |
310 // FIXME: Concatenate all attributes of the AXObject. | |
311 std::string attributes(GetTitle(object)); | |
312 attributes.append("\n"); | |
313 attributes.append(GetRole(object)); | |
314 attributes.append("\n"); | |
315 attributes.append(GetDescription(object)); | |
316 return attributes; | |
317 } | |
318 | |
319 blink::WebRect BoundsForCharacter(const blink::WebAXObject& object, | |
320 int characterIndex) { | |
321 DCHECK_EQ(object.role(), blink::WebAXRoleStaticText); | |
322 int end = 0; | |
323 for (unsigned i = 0; i < object.childCount(); i++) { | |
324 blink::WebAXObject inline_text_box = object.childAt(i); | |
325 DCHECK_EQ(inline_text_box.role(), blink::WebAXRoleInlineTextBox); | |
326 int start = end; | |
327 end += inline_text_box.stringValue().length(); | |
328 if (end <= characterIndex) | |
329 continue; | |
330 blink::WebRect inline_text_box_rect = inline_text_box.boundingBoxRect(); | |
331 int localIndex = characterIndex - start; | |
332 blink::WebVector<int> character_offsets; | |
333 inline_text_box.characterOffsets(character_offsets); | |
334 DCHECK(character_offsets.size() > 0 && | |
335 character_offsets.size() == inline_text_box.stringValue().length()); | |
336 switch (inline_text_box.textDirection()) { | |
337 case blink::WebAXTextDirectionLR: { | |
338 if (localIndex) { | |
339 int left = inline_text_box_rect.x + character_offsets[localIndex - 1]; | |
340 int width = character_offsets[localIndex] - | |
341 character_offsets[localIndex - 1]; | |
342 return blink::WebRect(left, inline_text_box_rect.y, | |
343 width, inline_text_box_rect.height); | |
344 } | |
345 return blink::WebRect( | |
346 inline_text_box_rect.x, inline_text_box_rect.y, | |
347 character_offsets[0], inline_text_box_rect.height); | |
348 } | |
349 case blink::WebAXTextDirectionRL: { | |
350 int right = inline_text_box_rect.x + inline_text_box_rect.width; | |
351 | |
352 if (localIndex) { | |
353 int left = right - character_offsets[localIndex]; | |
354 int width = character_offsets[localIndex] - | |
355 character_offsets[localIndex - 1]; | |
356 return blink::WebRect(left, inline_text_box_rect.y, | |
357 width, inline_text_box_rect.height); | |
358 } | |
359 int left = right - character_offsets[0]; | |
360 return blink::WebRect( | |
361 left, inline_text_box_rect.y, | |
362 character_offsets[0], inline_text_box_rect.height); | |
363 } | |
364 case blink::WebAXTextDirectionTB: { | |
365 if (localIndex) { | |
366 int top = inline_text_box_rect.y + character_offsets[localIndex - 1]; | |
367 int height = character_offsets[localIndex] - | |
368 character_offsets[localIndex - 1]; | |
369 return blink::WebRect(inline_text_box_rect.x, top, | |
370 inline_text_box_rect.width, height); | |
371 } | |
372 return blink::WebRect(inline_text_box_rect.x, inline_text_box_rect.y, | |
373 inline_text_box_rect.width, character_offsets[0]); | |
374 } | |
375 case blink::WebAXTextDirectionBT: { | |
376 int bottom = inline_text_box_rect.y + inline_text_box_rect.height; | |
377 | |
378 if (localIndex) { | |
379 int top = bottom - character_offsets[localIndex]; | |
380 int height = character_offsets[localIndex] - | |
381 character_offsets[localIndex - 1]; | |
382 return blink::WebRect(inline_text_box_rect.x, top, | |
383 inline_text_box_rect.width, height); | |
384 } | |
385 int top = bottom - character_offsets[0]; | |
386 return blink::WebRect(inline_text_box_rect.x, top, | |
387 inline_text_box_rect.width, character_offsets[0]); | |
388 } | |
389 } | |
390 } | |
391 | |
392 DCHECK(false); | |
393 return blink::WebRect(); | |
394 } | |
395 | |
396 void GetBoundariesForOneWord(const blink::WebAXObject& object, | |
397 int character_index, | |
398 int& word_start, | |
399 int& word_end) { | |
400 int end = 0; | |
401 for (unsigned i = 0; i < object.childCount(); i++) { | |
402 blink::WebAXObject inline_text_box = object.childAt(i); | |
403 DCHECK_EQ(inline_text_box.role(), blink::WebAXRoleInlineTextBox); | |
404 int start = end; | |
405 end += inline_text_box.stringValue().length(); | |
406 if (end <= character_index) | |
407 continue; | |
408 int localIndex = character_index - start; | |
409 | |
410 blink::WebVector<int> starts; | |
411 blink::WebVector<int> ends; | |
412 inline_text_box.wordBoundaries(starts, ends); | |
413 size_t word_count = starts.size(); | |
414 DCHECK_EQ(ends.size(), word_count); | |
415 | |
416 // If there are no words, use the InlineTextBox boundaries. | |
417 if (!word_count) { | |
418 word_start = start; | |
419 word_end = end; | |
420 return; | |
421 } | |
422 | |
423 // Look for a character within any word other than the last. | |
424 for (size_t j = 0; j < word_count - 1; j++) { | |
425 if (localIndex <= ends[j]) { | |
426 word_start = start + starts[j]; | |
427 word_end = start + ends[j]; | |
428 return; | |
429 } | |
430 } | |
431 | |
432 // Return the last word by default. | |
433 word_start = start + starts[word_count - 1]; | |
434 word_end = start + ends[word_count - 1]; | |
435 return; | |
436 } | |
437 } | |
438 | |
439 // Collects attributes into a string, delimited by dashes. Used by all methods | |
440 // that output lists of attributes: attributesOfLinkedUIElementsCallback, | |
441 // AttributesOfChildrenCallback, etc. | |
442 class AttributesCollector { | |
443 public: | |
444 AttributesCollector() {} | |
445 ~AttributesCollector() {} | |
446 | |
447 void CollectAttributes(const blink::WebAXObject& object) { | |
448 attributes_.append("\n------------\n"); | |
449 attributes_.append(GetAttributes(object)); | |
450 } | |
451 | |
452 std::string attributes() const { return attributes_; } | |
453 | |
454 private: | |
455 std::string attributes_; | |
456 | |
457 DISALLOW_COPY_AND_ASSIGN(AttributesCollector); | |
458 }; | |
459 | |
460 } // namespace | |
461 | |
462 gin::WrapperInfo WebAXObjectProxy::kWrapperInfo = { | |
463 gin::kEmbedderNativeGin}; | |
464 | |
465 WebAXObjectProxy::WebAXObjectProxy(const blink::WebAXObject& object, | |
466 WebAXObjectProxy::Factory* factory) | |
467 : accessibility_object_(object), | |
468 factory_(factory) { | |
469 } | |
470 | |
471 WebAXObjectProxy::~WebAXObjectProxy() {} | |
472 | |
473 gin::ObjectTemplateBuilder | |
474 WebAXObjectProxy::GetObjectTemplateBuilder(v8::Isolate* isolate) { | |
475 return gin::Wrappable<WebAXObjectProxy>::GetObjectTemplateBuilder(isolate) | |
476 .SetProperty("role", &WebAXObjectProxy::Role) | |
477 .SetProperty("title", &WebAXObjectProxy::Title) | |
478 .SetProperty("description", &WebAXObjectProxy::Description) | |
479 .SetProperty("helpText", &WebAXObjectProxy::HelpText) | |
480 .SetProperty("stringValue", &WebAXObjectProxy::StringValue) | |
481 .SetProperty("x", &WebAXObjectProxy::X) | |
482 .SetProperty("y", &WebAXObjectProxy::Y) | |
483 .SetProperty("width", &WebAXObjectProxy::Width) | |
484 .SetProperty("height", &WebAXObjectProxy::Height) | |
485 .SetProperty("intValue", &WebAXObjectProxy::IntValue) | |
486 .SetProperty("minValue", &WebAXObjectProxy::MinValue) | |
487 .SetProperty("maxValue", &WebAXObjectProxy::MaxValue) | |
488 .SetProperty("valueDescription", &WebAXObjectProxy::ValueDescription) | |
489 .SetProperty("childrenCount", &WebAXObjectProxy::ChildrenCount) | |
490 .SetProperty("insertionPointLineNumber", | |
491 &WebAXObjectProxy::InsertionPointLineNumber) | |
492 .SetProperty("selectedTextRange", &WebAXObjectProxy::SelectedTextRange) | |
493 .SetProperty("isEnabled", &WebAXObjectProxy::IsEnabled) | |
494 .SetProperty("isRequired", &WebAXObjectProxy::IsRequired) | |
495 .SetProperty("isFocused", &WebAXObjectProxy::IsFocused) | |
496 .SetProperty("isFocusable", &WebAXObjectProxy::IsFocusable) | |
497 .SetProperty("isSelected", &WebAXObjectProxy::IsSelected) | |
498 .SetProperty("isSelectable", &WebAXObjectProxy::IsSelectable) | |
499 .SetProperty("isMultiSelectable", &WebAXObjectProxy::IsMultiSelectable) | |
500 .SetProperty("isSelectedOptionActive", | |
501 &WebAXObjectProxy::IsSelectedOptionActive) | |
502 .SetProperty("isExpanded", &WebAXObjectProxy::IsExpanded) | |
503 .SetProperty("isChecked", &WebAXObjectProxy::IsChecked) | |
504 .SetProperty("isVisible", &WebAXObjectProxy::IsVisible) | |
505 .SetProperty("isOffScreen", &WebAXObjectProxy::IsOffScreen) | |
506 .SetProperty("isCollapsed", &WebAXObjectProxy::IsCollapsed) | |
507 .SetProperty("hasPopup", &WebAXObjectProxy::HasPopup) | |
508 .SetProperty("isValid", &WebAXObjectProxy::IsValid) | |
509 .SetProperty("isReadOnly", &WebAXObjectProxy::IsReadOnly) | |
510 .SetProperty("orientation", &WebAXObjectProxy::Orientation) | |
511 .SetProperty("clickPointX", &WebAXObjectProxy::ClickPointX) | |
512 .SetProperty("clickPointY", &WebAXObjectProxy::ClickPointY) | |
513 .SetProperty("rowCount", &WebAXObjectProxy::RowCount) | |
514 .SetProperty("columnCount", &WebAXObjectProxy::ColumnCount) | |
515 .SetProperty("isClickable", &WebAXObjectProxy::IsClickable) | |
516 .SetMethod("allAttributes", &WebAXObjectProxy::AllAttributes) | |
517 .SetMethod("attributesOfChildren", | |
518 &WebAXObjectProxy::AttributesOfChildren) | |
519 .SetMethod("lineForIndex", &WebAXObjectProxy::LineForIndex) | |
520 .SetMethod("boundsForRange", &WebAXObjectProxy::BoundsForRange) | |
521 .SetMethod("childAtIndex", &WebAXObjectProxy::ChildAtIndex) | |
522 .SetMethod("elementAtPoint", &WebAXObjectProxy::ElementAtPoint) | |
523 .SetMethod("tableHeader", &WebAXObjectProxy::TableHeader) | |
524 .SetMethod("rowIndexRange", &WebAXObjectProxy::RowIndexRange) | |
525 .SetMethod("columnIndexRange", &WebAXObjectProxy::ColumnIndexRange) | |
526 .SetMethod("cellForColumnAndRow", &WebAXObjectProxy::CellForColumnAndRow) | |
527 .SetMethod("titleUIElement", &WebAXObjectProxy::TitleUIElement) | |
528 .SetMethod("setSelectedTextRange", | |
529 &WebAXObjectProxy::SetSelectedTextRange) | |
530 .SetMethod("isAttributeSettable", &WebAXObjectProxy::IsAttributeSettable) | |
531 .SetMethod("isPressActionSupported", | |
532 &WebAXObjectProxy::IsPressActionSupported) | |
533 .SetMethod("isIncrementActionSupported", | |
534 &WebAXObjectProxy::IsIncrementActionSupported) | |
535 .SetMethod("isDecrementActionSupported", | |
536 &WebAXObjectProxy::IsDecrementActionSupported) | |
537 .SetMethod("parentElement", &WebAXObjectProxy::ParentElement) | |
538 .SetMethod("increment", &WebAXObjectProxy::Increment) | |
539 .SetMethod("decrement", &WebAXObjectProxy::Decrement) | |
540 .SetMethod("showMenu", &WebAXObjectProxy::ShowMenu) | |
541 .SetMethod("press", &WebAXObjectProxy::Press) | |
542 .SetMethod("isEqual", &WebAXObjectProxy::IsEqual) | |
543 .SetMethod("setNotificationListener", | |
544 &WebAXObjectProxy::SetNotificationListener) | |
545 .SetMethod("unsetNotificationListener", | |
546 &WebAXObjectProxy::UnsetNotificationListener) | |
547 .SetMethod("takeFocus", &WebAXObjectProxy::TakeFocus) | |
548 .SetMethod("scrollToMakeVisible", &WebAXObjectProxy::ScrollToMakeVisible) | |
549 .SetMethod("scrollToMakeVisibleWithSubFocus", | |
550 &WebAXObjectProxy::ScrollToMakeVisibleWithSubFocus) | |
551 .SetMethod("scrollToGlobalPoint", &WebAXObjectProxy::ScrollToGlobalPoint) | |
552 .SetMethod("wordStart", &WebAXObjectProxy::WordStart) | |
553 .SetMethod("wordEnd", &WebAXObjectProxy::WordEnd) | |
554 // TODO(hajimehoshi): This is for backward compatibility. Remove them. | |
555 .SetMethod("addNotificationListener", | |
556 &WebAXObjectProxy::SetNotificationListener) | |
557 .SetMethod("removeNotificationListener", | |
558 &WebAXObjectProxy::UnsetNotificationListener); | |
559 } | |
560 | |
561 v8::Handle<v8::Object> WebAXObjectProxy::GetChildAtIndex(unsigned index) { | |
562 return factory_->GetOrCreate(accessibility_object().childAt(index)); | |
563 } | |
564 | |
565 bool WebAXObjectProxy::IsRoot() const { | |
566 return false; | |
567 } | |
568 | |
569 bool WebAXObjectProxy::IsEqualToObject(const blink::WebAXObject& other) { | |
570 return accessibility_object().equals(other); | |
571 } | |
572 | |
573 void WebAXObjectProxy::NotificationReceived( | |
574 blink::WebFrame* frame, | |
575 const std::string& notification_name) { | |
576 if (notification_callback_.IsEmpty()) | |
577 return; | |
578 | |
579 v8::Handle<v8::Context> context = frame->mainWorldScriptContext(); | |
580 if (context.IsEmpty()) | |
581 return; | |
582 | |
583 v8::Isolate* isolate = blink::mainThreadIsolate(); | |
584 | |
585 v8::Handle<v8::Value> argv[] = { | |
586 v8::String::NewFromUtf8(isolate, notification_name.data(), | |
587 v8::String::kNormalString, | |
588 notification_name.size()), | |
589 }; | |
590 frame->callFunctionEvenIfScriptDisabled( | |
591 v8::Local<v8::Function>::New(isolate, notification_callback_), | |
592 context->Global(), | |
593 arraysize(argv), | |
594 argv); | |
595 } | |
596 | |
597 std::string WebAXObjectProxy::Role() { | |
598 return GetRole(accessibility_object()); | |
599 } | |
600 | |
601 std::string WebAXObjectProxy::Title() { | |
602 return GetTitle(accessibility_object()); | |
603 } | |
604 | |
605 std::string WebAXObjectProxy::Description() { | |
606 return GetDescription(accessibility_object()); | |
607 } | |
608 | |
609 std::string WebAXObjectProxy::HelpText() { | |
610 return GetHelpText(accessibility_object()); | |
611 } | |
612 | |
613 std::string WebAXObjectProxy::StringValue() { | |
614 return GetStringValue(accessibility_object()); | |
615 } | |
616 | |
617 int WebAXObjectProxy::X() { | |
618 return accessibility_object().boundingBoxRect().x; | |
619 } | |
620 | |
621 int WebAXObjectProxy::Y() { | |
622 return accessibility_object().boundingBoxRect().y; | |
623 } | |
624 | |
625 int WebAXObjectProxy::Width() { | |
626 return accessibility_object().boundingBoxRect().width; | |
627 } | |
628 | |
629 int WebAXObjectProxy::Height() { | |
630 return accessibility_object().boundingBoxRect().height; | |
631 } | |
632 | |
633 int WebAXObjectProxy::IntValue() { | |
634 if (accessibility_object().supportsRangeValue()) | |
635 return accessibility_object().valueForRange(); | |
636 else if (accessibility_object().role() == blink::WebAXRoleHeading) | |
637 return accessibility_object().headingLevel(); | |
638 else | |
639 return atoi(accessibility_object().stringValue().utf8().data()); | |
640 } | |
641 | |
642 int WebAXObjectProxy::MinValue() { | |
643 return accessibility_object().minValueForRange(); | |
644 } | |
645 | |
646 int WebAXObjectProxy::MaxValue() { | |
647 return accessibility_object().maxValueForRange(); | |
648 } | |
649 | |
650 std::string WebAXObjectProxy::ValueDescription() { | |
651 return GetValueDescription(accessibility_object()); | |
652 } | |
653 | |
654 int WebAXObjectProxy::ChildrenCount() { | |
655 int count = 1; // Root object always has only one child, the WebView. | |
656 if (!IsRoot()) | |
657 count = accessibility_object().childCount(); | |
658 return count; | |
659 } | |
660 | |
661 int WebAXObjectProxy::InsertionPointLineNumber() { | |
662 if (!accessibility_object().isFocused()) | |
663 return -1; | |
664 return accessibility_object().selectionEndLineNumber(); | |
665 } | |
666 | |
667 std::string WebAXObjectProxy::SelectedTextRange() { | |
668 unsigned selection_start = accessibility_object().selectionStart(); | |
669 unsigned selection_end = accessibility_object().selectionEnd(); | |
670 return base::StringPrintf("{%d, %d}", | |
671 selection_start, selection_end - selection_start); | |
672 } | |
673 | |
674 bool WebAXObjectProxy::IsEnabled() { | |
675 return accessibility_object().isEnabled(); | |
676 } | |
677 | |
678 bool WebAXObjectProxy::IsRequired() { | |
679 return accessibility_object().isRequired(); | |
680 } | |
681 | |
682 bool WebAXObjectProxy::IsFocused() { | |
683 return accessibility_object().isFocused(); | |
684 } | |
685 | |
686 bool WebAXObjectProxy::IsFocusable() { | |
687 return accessibility_object().canSetFocusAttribute(); | |
688 } | |
689 | |
690 bool WebAXObjectProxy::IsSelected() { | |
691 return accessibility_object().isSelected(); | |
692 } | |
693 | |
694 bool WebAXObjectProxy::IsSelectable() { | |
695 return accessibility_object().canSetSelectedAttribute(); | |
696 } | |
697 | |
698 bool WebAXObjectProxy::IsMultiSelectable() { | |
699 return accessibility_object().isMultiSelectable(); | |
700 } | |
701 | |
702 bool WebAXObjectProxy::IsSelectedOptionActive() { | |
703 return accessibility_object().isSelectedOptionActive(); | |
704 } | |
705 | |
706 bool WebAXObjectProxy::IsExpanded() { | |
707 return !accessibility_object().isCollapsed(); | |
708 } | |
709 | |
710 bool WebAXObjectProxy::IsChecked() { | |
711 return accessibility_object().isChecked(); | |
712 } | |
713 | |
714 bool WebAXObjectProxy::IsVisible() { | |
715 return accessibility_object().isVisible(); | |
716 } | |
717 | |
718 bool WebAXObjectProxy::IsOffScreen() { | |
719 return accessibility_object().isOffScreen(); | |
720 } | |
721 | |
722 bool WebAXObjectProxy::IsCollapsed() { | |
723 return accessibility_object().isCollapsed(); | |
724 } | |
725 | |
726 bool WebAXObjectProxy::HasPopup() { | |
727 return accessibility_object().ariaHasPopup(); | |
728 } | |
729 | |
730 bool WebAXObjectProxy::IsValid() { | |
731 return !accessibility_object().isDetached(); | |
732 } | |
733 | |
734 bool WebAXObjectProxy::IsReadOnly() { | |
735 return accessibility_object().isReadOnly(); | |
736 } | |
737 | |
738 std::string WebAXObjectProxy::Orientation() { | |
739 return GetOrientation(accessibility_object()); | |
740 } | |
741 | |
742 int WebAXObjectProxy::ClickPointX() { | |
743 return accessibility_object().clickPoint().x; | |
744 } | |
745 | |
746 int WebAXObjectProxy::ClickPointY() { | |
747 return accessibility_object().clickPoint().y; | |
748 } | |
749 | |
750 int32_t WebAXObjectProxy::RowCount() { | |
751 return static_cast<int32_t>(accessibility_object().rowCount()); | |
752 } | |
753 | |
754 int32_t WebAXObjectProxy::ColumnCount() { | |
755 return static_cast<int32_t>(accessibility_object().columnCount()); | |
756 } | |
757 | |
758 bool WebAXObjectProxy::IsClickable() { | |
759 return accessibility_object().isClickable(); | |
760 } | |
761 | |
762 std::string WebAXObjectProxy::AllAttributes() { | |
763 return GetAttributes(accessibility_object()); | |
764 } | |
765 | |
766 std::string WebAXObjectProxy::AttributesOfChildren() { | |
767 AttributesCollector collector; | |
768 unsigned size = accessibility_object().childCount(); | |
769 for (unsigned i = 0; i < size; ++i) | |
770 collector.CollectAttributes(accessibility_object().childAt(i)); | |
771 return collector.attributes(); | |
772 } | |
773 | |
774 int WebAXObjectProxy::LineForIndex(int index) { | |
775 blink::WebVector<int> line_breaks; | |
776 accessibility_object().lineBreaks(line_breaks); | |
777 int line = 0; | |
778 int vector_size = static_cast<int>(line_breaks.size()); | |
779 while (line < vector_size && line_breaks[line] <= index) | |
780 line++; | |
781 return line; | |
782 } | |
783 | |
784 std::string WebAXObjectProxy::BoundsForRange(int start, int end) { | |
785 if (accessibility_object().role() != blink::WebAXRoleStaticText) | |
786 return std::string(); | |
787 | |
788 int len = end - start; | |
789 | |
790 // Get the bounds for each character and union them into one large rectangle. | |
791 // This is just for testing so it doesn't need to be efficient. | |
792 blink::WebRect bounds = BoundsForCharacter(accessibility_object(), start); | |
793 for (int i = 1; i < len; i++) { | |
794 blink::WebRect next = BoundsForCharacter(accessibility_object(), start + i); | |
795 int right = std::max(bounds.x + bounds.width, next.x + next.width); | |
796 int bottom = std::max(bounds.y + bounds.height, next.y + next.height); | |
797 bounds.x = std::min(bounds.x, next.x); | |
798 bounds.y = std::min(bounds.y, next.y); | |
799 bounds.width = right - bounds.x; | |
800 bounds.height = bottom - bounds.y; | |
801 } | |
802 | |
803 return base::StringPrintf("{x: %d, y: %d, width: %d, height: %d}", | |
804 bounds.x, bounds.y, bounds.width, bounds.height); | |
805 } | |
806 | |
807 v8::Handle<v8::Object> WebAXObjectProxy::ChildAtIndex(int index) { | |
808 return GetChildAtIndex(index); | |
809 } | |
810 | |
811 v8::Handle<v8::Object> WebAXObjectProxy::ElementAtPoint(int x, int y) { | |
812 blink::WebPoint point(x, y); | |
813 blink::WebAXObject obj = accessibility_object().hitTest(point); | |
814 if (obj.isNull()) | |
815 return v8::Handle<v8::Object>(); | |
816 | |
817 return factory_->GetOrCreate(obj); | |
818 } | |
819 | |
820 v8::Handle<v8::Object> WebAXObjectProxy::TableHeader() { | |
821 blink::WebAXObject obj = accessibility_object().headerContainerObject(); | |
822 if (obj.isNull()) | |
823 return v8::Handle<v8::Object>(); | |
824 | |
825 return factory_->GetOrCreate(obj); | |
826 } | |
827 | |
828 std::string WebAXObjectProxy::RowIndexRange() { | |
829 unsigned row_index = accessibility_object().cellRowIndex(); | |
830 unsigned row_span = accessibility_object().cellRowSpan(); | |
831 return base::StringPrintf("{%d, %d}", row_index, row_span); | |
832 } | |
833 | |
834 std::string WebAXObjectProxy::ColumnIndexRange() { | |
835 unsigned column_index = accessibility_object().cellColumnIndex(); | |
836 unsigned column_span = accessibility_object().cellColumnSpan(); | |
837 return base::StringPrintf("{%d, %d}", column_index, column_span); | |
838 } | |
839 | |
840 v8::Handle<v8::Object> WebAXObjectProxy::CellForColumnAndRow( | |
841 int column, int row) { | |
842 blink::WebAXObject obj = | |
843 accessibility_object().cellForColumnAndRow(column, row); | |
844 if (obj.isNull()) | |
845 return v8::Handle<v8::Object>(); | |
846 | |
847 return factory_->GetOrCreate(obj); | |
848 } | |
849 | |
850 v8::Handle<v8::Object> WebAXObjectProxy::TitleUIElement() { | |
851 blink::WebAXObject obj = accessibility_object().titleUIElement(); | |
852 if (obj.isNull()) | |
853 return v8::Handle<v8::Object>(); | |
854 | |
855 return factory_->GetOrCreate(obj); | |
856 } | |
857 | |
858 void WebAXObjectProxy::SetSelectedTextRange(int selection_start, | |
859 int length) { | |
860 accessibility_object().setSelectedTextRange(selection_start, | |
861 selection_start + length); | |
862 } | |
863 | |
864 bool WebAXObjectProxy::IsAttributeSettable(const std::string& attribute) { | |
865 bool settable = false; | |
866 if (attribute == "AXValue") | |
867 settable = accessibility_object().canSetValueAttribute(); | |
868 return settable; | |
869 } | |
870 | |
871 bool WebAXObjectProxy::IsPressActionSupported() { | |
872 return accessibility_object().canPress(); | |
873 } | |
874 | |
875 bool WebAXObjectProxy::IsIncrementActionSupported() { | |
876 return accessibility_object().canIncrement(); | |
877 } | |
878 | |
879 bool WebAXObjectProxy::IsDecrementActionSupported() { | |
880 return accessibility_object().canDecrement(); | |
881 } | |
882 | |
883 v8::Handle<v8::Object> WebAXObjectProxy::ParentElement() { | |
884 blink::WebAXObject parent_object = accessibility_object().parentObject(); | |
885 while (parent_object.accessibilityIsIgnored()) | |
886 parent_object = parent_object.parentObject(); | |
887 return factory_->GetOrCreate(parent_object); | |
888 } | |
889 | |
890 void WebAXObjectProxy::Increment() { | |
891 accessibility_object().increment(); | |
892 } | |
893 | |
894 void WebAXObjectProxy::Decrement() { | |
895 accessibility_object().decrement(); | |
896 } | |
897 | |
898 void WebAXObjectProxy::ShowMenu() { | |
899 } | |
900 | |
901 void WebAXObjectProxy::Press() { | |
902 accessibility_object().press(); | |
903 } | |
904 | |
905 bool WebAXObjectProxy::IsEqual(v8::Handle<v8::Object> proxy) { | |
906 WebAXObjectProxy* unwrapped_proxy = NULL; | |
907 if (!gin::ConvertFromV8(blink::mainThreadIsolate(), proxy, &unwrapped_proxy)) | |
908 return false; | |
909 return unwrapped_proxy->IsEqualToObject(accessibility_object_); | |
910 } | |
911 | |
912 void WebAXObjectProxy::SetNotificationListener( | |
913 v8::Handle<v8::Function> callback) { | |
914 v8::Isolate* isolate = blink::mainThreadIsolate(); | |
915 notification_callback_.Reset(isolate, callback); | |
916 } | |
917 | |
918 void WebAXObjectProxy::UnsetNotificationListener() { | |
919 notification_callback_.Reset(); | |
920 } | |
921 | |
922 void WebAXObjectProxy::TakeFocus() { | |
923 accessibility_object().setFocused(true); | |
924 } | |
925 | |
926 void WebAXObjectProxy::ScrollToMakeVisible() { | |
927 accessibility_object().scrollToMakeVisible(); | |
928 } | |
929 | |
930 void WebAXObjectProxy::ScrollToMakeVisibleWithSubFocus(int x, int y, | |
931 int width, int height) { | |
932 accessibility_object().scrollToMakeVisibleWithSubFocus( | |
933 blink::WebRect(x, y, width, height)); | |
934 } | |
935 | |
936 void WebAXObjectProxy::ScrollToGlobalPoint(int x, int y) { | |
937 accessibility_object().scrollToGlobalPoint(blink::WebPoint(x, y)); | |
938 } | |
939 | |
940 int WebAXObjectProxy::WordStart(int character_index) { | |
941 if (accessibility_object().role() != blink::WebAXRoleStaticText) | |
942 return -1; | |
943 | |
944 int word_start, word_end; | |
945 GetBoundariesForOneWord(accessibility_object(), character_index, | |
946 word_start, word_end); | |
947 return word_start; | |
948 } | |
949 | |
950 int WebAXObjectProxy::WordEnd(int character_index) { | |
951 if (accessibility_object().role() != blink::WebAXRoleStaticText) | |
952 return -1; | |
953 | |
954 int word_start, word_end; | |
955 GetBoundariesForOneWord(accessibility_object(), character_index, | |
956 word_start, word_end); | |
957 return word_end; | |
958 } | |
959 | |
960 RootWebAXObjectProxy::RootWebAXObjectProxy( | |
961 const blink::WebAXObject &object, Factory *factory) | |
962 : WebAXObjectProxy(object, factory) { | |
963 } | |
964 | |
965 v8::Handle<v8::Object> RootWebAXObjectProxy::GetChildAtIndex(unsigned index) { | |
966 if (index) | |
967 return v8::Handle<v8::Object>(); | |
968 | |
969 return factory()->GetOrCreate(accessibility_object()); | |
970 } | |
971 | |
972 bool RootWebAXObjectProxy::IsRoot() const { | |
973 return true; | |
974 } | |
975 | |
976 WebAXObjectProxyList::WebAXObjectProxyList() { | |
977 } | |
978 | |
979 WebAXObjectProxyList::~WebAXObjectProxyList() { | |
980 Clear(); | |
981 } | |
982 | |
983 void WebAXObjectProxyList::Clear() { | |
984 for (ElementList::iterator i = elements_.begin(); i != elements_.end(); ++i) | |
985 i->Dispose(); | |
986 elements_.clear(); | |
987 } | |
988 | |
989 v8::Handle<v8::Object> WebAXObjectProxyList::GetOrCreate( | |
990 const blink::WebAXObject& object) { | |
991 if (object.isNull()) | |
992 return v8::Handle<v8::Object>(); | |
993 | |
994 v8::Isolate* isolate = blink::mainThreadIsolate(); | |
995 | |
996 size_t elementCount = elements_.size(); | |
997 for (size_t i = 0; i < elementCount; i++) { | |
998 WebAXObjectProxy* unwrapped_object = NULL; | |
999 bool result = gin::ConvertFromV8(isolate, elements_[i].NewLocal(isolate), | |
1000 &unwrapped_object); | |
1001 DCHECK(result); | |
1002 DCHECK(unwrapped_object); | |
1003 if (unwrapped_object->IsEqualToObject(object)) | |
1004 return elements_[i].NewLocal(isolate); | |
1005 } | |
1006 | |
1007 v8::Handle<v8::Value> value_handle = gin::CreateHandle( | |
1008 isolate, new WebAXObjectProxy(object, this)).ToV8(); | |
1009 if (value_handle.IsEmpty()) | |
1010 return v8::Handle<v8::Object>(); | |
1011 v8::Handle<v8::Object> handle = value_handle->ToObject(); | |
1012 UnsafePersistent<v8::Object> unsafe_handle(isolate, handle); | |
1013 elements_.push_back(unsafe_handle); | |
1014 return unsafe_handle.NewLocal(isolate); | |
1015 } | |
1016 | |
1017 v8::Handle<v8::Object> WebAXObjectProxyList::CreateRoot( | |
1018 const blink::WebAXObject& object) { | |
1019 v8::Isolate* isolate = blink::mainThreadIsolate(); | |
1020 v8::Handle<v8::Value> value_handle = gin::CreateHandle( | |
1021 isolate, new RootWebAXObjectProxy(object, this)).ToV8(); | |
1022 if (value_handle.IsEmpty()) | |
1023 return v8::Handle<v8::Object>(); | |
1024 v8::Handle<v8::Object> handle = value_handle->ToObject(); | |
1025 UnsafePersistent<v8::Object> unsafe_handle(isolate, handle); | |
1026 elements_.push_back(unsafe_handle); | |
1027 return unsafe_handle.NewLocal(isolate); | |
1028 } | |
1029 | |
1030 } // namespace content | |
OLD | NEW |