Upstream version 6.35.121.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 // 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 (characterIndex < start || characterIndex >= end)
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