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