Home | History | Annotate | Download | only in test_runner
      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
   1115