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