Home | History | Annotate | Download | only in chromium
      1 /*
      2  * Copyright (C) 2010 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "AccessibilityUIElement.h"
     33 
     34 #include "WebAccessibilityObject.h"
     35 #include "WebCString.h"
     36 #include "WebString.h"
     37 #include <wtf/Assertions.h>
     38 
     39 using namespace WebKit;
     40 using namespace std;
     41 
     42 // Map role value to string, matching Safari/Mac platform implementation to
     43 // avoid rebaselining layout tests.
     44 static string roleToString(WebAccessibilityRole role)
     45 {
     46     string result = "AXRole: AX";
     47     switch (role) {
     48     case WebAccessibilityRoleButton:
     49         return result.append("Button");
     50     case WebAccessibilityRoleRadioButton:
     51         return result.append("RadioButton");
     52     case WebAccessibilityRoleCheckBox:
     53         return result.append("CheckBox");
     54     case WebAccessibilityRoleSlider:
     55         return result.append("Slider");
     56     case WebAccessibilityRoleTabGroup:
     57         return result.append("TabGroup");
     58     case WebAccessibilityRoleTextField:
     59         return result.append("TextField");
     60     case WebAccessibilityRoleStaticText:
     61         return result.append("StaticText");
     62     case WebAccessibilityRoleTextArea:
     63         return result.append("TextArea");
     64     case WebAccessibilityRoleScrollArea:
     65         return result.append("ScrollArea");
     66     case WebAccessibilityRolePopUpButton:
     67         return result.append("PopUpButton");
     68     case WebAccessibilityRoleMenuButton:
     69         return result.append("MenuButton");
     70     case WebAccessibilityRoleTable:
     71         return result.append("Table");
     72     case WebAccessibilityRoleApplication:
     73         return result.append("Application");
     74     case WebAccessibilityRoleGroup:
     75         return result.append("Group");
     76     case WebAccessibilityRoleRadioGroup:
     77         return result.append("RadioGroup");
     78     case WebAccessibilityRoleList:
     79         return result.append("List");
     80     case WebAccessibilityRoleScrollBar:
     81         return result.append("ScrollBar");
     82     case WebAccessibilityRoleValueIndicator:
     83         return result.append("ValueIndicator");
     84     case WebAccessibilityRoleImage:
     85         return result.append("Image");
     86     case WebAccessibilityRoleMenuBar:
     87         return result.append("MenuBar");
     88     case WebAccessibilityRoleMenu:
     89         return result.append("Menu");
     90     case WebAccessibilityRoleMenuItem:
     91         return result.append("MenuItem");
     92     case WebAccessibilityRoleColumn:
     93         return result.append("Column");
     94     case WebAccessibilityRoleRow:
     95         return result.append("Row");
     96     case WebAccessibilityRoleToolbar:
     97         return result.append("Toolbar");
     98     case WebAccessibilityRoleBusyIndicator:
     99         return result.append("BusyIndicator");
    100     case WebAccessibilityRoleProgressIndicator:
    101         return result.append("ProgressIndicator");
    102     case WebAccessibilityRoleWindow:
    103         return result.append("Window");
    104     case WebAccessibilityRoleDrawer:
    105         return result.append("Drawer");
    106     case WebAccessibilityRoleSystemWide:
    107         return result.append("SystemWide");
    108     case WebAccessibilityRoleOutline:
    109         return result.append("Outline");
    110     case WebAccessibilityRoleIncrementor:
    111         return result.append("Incrementor");
    112     case WebAccessibilityRoleBrowser:
    113         return result.append("Browser");
    114     case WebAccessibilityRoleComboBox:
    115         return result.append("ComboBox");
    116     case WebAccessibilityRoleSplitGroup:
    117         return result.append("SplitGroup");
    118     case WebAccessibilityRoleSplitter:
    119         return result.append("Splitter");
    120     case WebAccessibilityRoleColorWell:
    121         return result.append("ColorWell");
    122     case WebAccessibilityRoleGrowArea:
    123         return result.append("GrowArea");
    124     case WebAccessibilityRoleSheet:
    125         return result.append("Sheet");
    126     case WebAccessibilityRoleHelpTag:
    127         return result.append("HelpTag");
    128     case WebAccessibilityRoleMatte:
    129         return result.append("Matte");
    130     case WebAccessibilityRoleRuler:
    131         return result.append("Ruler");
    132     case WebAccessibilityRoleRulerMarker:
    133         return result.append("RulerMarker");
    134     case WebAccessibilityRoleLink:
    135         return result.append("Link");
    136     case WebAccessibilityRoleDisclosureTriangle:
    137         return result.append("DisclosureTriangle");
    138     case WebAccessibilityRoleGrid:
    139         return result.append("Grid");
    140     case WebAccessibilityRoleCell:
    141         return result.append("Cell");
    142     case WebAccessibilityRoleColumnHeader:
    143         return result.append("ColumnHeader");
    144     case WebAccessibilityRoleRowHeader:
    145         return result.append("RowHeader");
    146     case WebAccessibilityRoleWebCoreLink:
    147         // Maps to Link role.
    148         return result.append("Link");
    149     case WebAccessibilityRoleImageMapLink:
    150         return result.append("ImageMapLink");
    151     case WebAccessibilityRoleImageMap:
    152         return result.append("ImageMap");
    153     case WebAccessibilityRoleListMarker:
    154         return result.append("ListMarker");
    155     case WebAccessibilityRoleWebArea:
    156         return result.append("WebArea");
    157     case WebAccessibilityRoleHeading:
    158         return result.append("Heading");
    159     case WebAccessibilityRoleListBox:
    160         return result.append("ListBox");
    161     case WebAccessibilityRoleListBoxOption:
    162         return result.append("ListBoxOption");
    163     case WebAccessibilityRoleTableHeaderContainer:
    164         return result.append("TableHeaderContainer");
    165     case WebAccessibilityRoleDefinitionListTerm:
    166         return result.append("DefinitionListTerm");
    167     case WebAccessibilityRoleDefinitionListDefinition:
    168         return result.append("DefinitionListDefinition");
    169     case WebAccessibilityRoleAnnotation:
    170         return result.append("Annotation");
    171     case WebAccessibilityRoleSliderThumb:
    172         return result.append("SliderThumb");
    173     case WebAccessibilityRoleLandmarkApplication:
    174         return result.append("LandmarkApplication");
    175     case WebAccessibilityRoleLandmarkBanner:
    176         return result.append("LandmarkBanner");
    177     case WebAccessibilityRoleLandmarkComplementary:
    178         return result.append("LandmarkComplementary");
    179     case WebAccessibilityRoleLandmarkContentInfo:
    180         return result.append("LandmarkContentInfo");
    181     case WebAccessibilityRoleLandmarkMain:
    182         return result.append("LandmarkMain");
    183     case WebAccessibilityRoleLandmarkNavigation:
    184         return result.append("LandmarkNavigation");
    185     case WebAccessibilityRoleLandmarkSearch:
    186         return result.append("LandmarkSearch");
    187     case WebAccessibilityRoleApplicationLog:
    188         return result.append("ApplicationLog");
    189     case WebAccessibilityRoleApplicationMarquee:
    190         return result.append("ApplicationMarquee");
    191     case WebAccessibilityRoleApplicationStatus:
    192         return result.append("ApplicationStatus");
    193     case WebAccessibilityRoleApplicationTimer:
    194         return result.append("ApplicationTimer");
    195     case WebAccessibilityRoleDocument:
    196         return result.append("Document");
    197     case WebAccessibilityRoleDocumentArticle:
    198         return result.append("DocumentArticle");
    199     case WebAccessibilityRoleDocumentNote:
    200         return result.append("DocumentNote");
    201     case WebAccessibilityRoleDocumentRegion:
    202         return result.append("DocumentRegion");
    203     case WebAccessibilityRoleUserInterfaceTooltip:
    204         return result.append("UserInterfaceTooltip");
    205     default:
    206         // Also matches WebAccessibilityRoleUnknown.
    207         return result.append("Unknown");
    208     }
    209 }
    210 
    211 string getDescription(const WebAccessibilityObject& object)
    212 {
    213     string description = object.accessibilityDescription().utf8();
    214     return description.insert(0, "AXDescription: ");
    215 }
    216 
    217 string getRole(const WebAccessibilityObject& object)
    218 {
    219     return roleToString(object.roleValue());
    220 }
    221 
    222 string getTitle(const WebAccessibilityObject& object)
    223 {
    224     string title = object.title().utf8();
    225     return title.insert(0, "AXTitle: ");
    226 }
    227 
    228 string getAttributes(const WebAccessibilityObject& object)
    229 {
    230     // FIXME: Concatenate all attributes of the AccessibilityObject.
    231     string attributes(getTitle(object));
    232     attributes.append("\n");
    233     attributes.append(getRole(object));
    234     attributes.append("\n");
    235     attributes.append(getDescription(object));
    236     return attributes;
    237 }
    238 
    239 
    240 // Collects attributes into a string, delimited by dashes. Used by all methods
    241 // that output lists of attributes: attributesOfLinkedUIElementsCallback,
    242 // AttributesOfChildrenCallback, etc.
    243 class AttributesCollector {
    244 public:
    245     void collectAttributes(const WebAccessibilityObject& object)
    246     {
    247         m_attributes.append("\n------------\n");
    248         m_attributes.append(getAttributes(object));
    249     }
    250 
    251     string attributes() const { return m_attributes; }
    252 
    253 private:
    254     string m_attributes;
    255 };
    256 
    257 AccessibilityUIElement::AccessibilityUIElement(const WebAccessibilityObject& object, Factory* factory)
    258     : m_accessibilityObject(object)
    259     , m_factory(factory)
    260 {
    261 
    262     ASSERT(factory);
    263 
    264     bindMethod("allAttributes", &AccessibilityUIElement::allAttributesCallback);
    265     bindMethod("attributesOfLinkedUIElements",
    266                &AccessibilityUIElement::attributesOfLinkedUIElementsCallback);
    267     bindMethod("attributesOfDocumentLinks",
    268                &AccessibilityUIElement::attributesOfDocumentLinksCallback);
    269     bindMethod("attributesOfChildren",
    270                &AccessibilityUIElement::attributesOfChildrenCallback);
    271     bindMethod("parameterizedAttributeNames",
    272                &AccessibilityUIElement::parametrizedAttributeNamesCallback);
    273     bindMethod("lineForIndex", &AccessibilityUIElement::lineForIndexCallback);
    274     bindMethod("boundsForRange", &AccessibilityUIElement::boundsForRangeCallback);
    275     bindMethod("stringForRange", &AccessibilityUIElement::stringForRangeCallback);
    276     bindMethod("childAtIndex", &AccessibilityUIElement::childAtIndexCallback);
    277     bindMethod("elementAtPoint", &AccessibilityUIElement::elementAtPointCallback);
    278     bindMethod("attributesOfColumnHeaders",
    279                &AccessibilityUIElement::attributesOfColumnHeadersCallback);
    280     bindMethod("attributesOfRowHeaders",
    281                &AccessibilityUIElement::attributesOfRowHeadersCallback);
    282     bindMethod("attributesOfColumns",
    283                &AccessibilityUIElement::attributesOfColumnsCallback);
    284     bindMethod("attributesOfRows",
    285                &AccessibilityUIElement::attributesOfRowsCallback);
    286     bindMethod("attributesOfVisibleCells",
    287                &AccessibilityUIElement::attributesOfVisibleCellsCallback);
    288     bindMethod("attributesOfHeader",
    289                &AccessibilityUIElement::attributesOfHeaderCallback);
    290     bindMethod("indexInTable", &AccessibilityUIElement::indexInTableCallback);
    291     bindMethod("rowIndexRange", &AccessibilityUIElement::rowIndexRangeCallback);
    292     bindMethod("columnIndexRange",
    293                &AccessibilityUIElement::columnIndexRangeCallback);
    294     bindMethod("cellForColumnAndRow",
    295                &AccessibilityUIElement::cellForColumnAndRowCallback);
    296     bindMethod("titleUIElement", &AccessibilityUIElement::titleUIElementCallback);
    297     bindMethod("setSelectedTextRange",
    298                &AccessibilityUIElement::setSelectedTextRangeCallback);
    299     bindMethod("attributeValue", &AccessibilityUIElement::attributeValueCallback);
    300     bindMethod("isAttributeSettable",
    301                &AccessibilityUIElement::isAttributeSettableCallback);
    302     bindMethod("isActionSupported",
    303                &AccessibilityUIElement::isActionSupportedCallback);
    304     bindMethod("parentElement", &AccessibilityUIElement::parentElementCallback);
    305     bindMethod("increment", &AccessibilityUIElement::incrementCallback);
    306     bindMethod("decrement", &AccessibilityUIElement::decrementCallback);
    307 
    308     bindProperty("role", &AccessibilityUIElement::roleGetterCallback);
    309     bindProperty("subrole", &m_subrole);
    310     bindProperty("title", &AccessibilityUIElement::titleGetterCallback);
    311     bindProperty("description",
    312                  &AccessibilityUIElement::descriptionGetterCallback);
    313     bindProperty("language", &m_language);
    314     bindProperty("x", &m_x);
    315     bindProperty("y", &m_y);
    316     bindProperty("width", &m_width);
    317     bindProperty("height", &m_height);
    318     bindProperty("clickPointX", &m_clickPointX);
    319     bindProperty("clickPointY", &m_clickPointY);
    320     bindProperty("intValue", &m_intValue);
    321     bindProperty("minValue", &m_minValue);
    322     bindProperty("maxValue", &m_maxValue);
    323     bindProperty("childrenCount",
    324                  &AccessibilityUIElement::childrenCountGetterCallback);
    325     bindProperty("insertionPointLineNumber", &m_insertionPointLineNumber);
    326     bindProperty("selectedTextRange", &m_selectedTextRange);
    327     bindProperty("isEnabled", &AccessibilityUIElement::isEnabledGetterCallback);
    328     bindProperty("isRequired", &m_isRequired);
    329     bindProperty("isSelected", &AccessibilityUIElement::isSelectedGetterCallback);
    330     bindProperty("valueDescription", &m_valueDescription);
    331 
    332     bindFallbackMethod(&AccessibilityUIElement::fallbackCallback);
    333 }
    334 
    335 AccessibilityUIElement* AccessibilityUIElement::getChildAtIndex(unsigned index)
    336 {
    337     return m_factory->create(accessibilityObject().childAt(index));
    338 }
    339 
    340 void AccessibilityUIElement::allAttributesCallback(const CppArgumentList&, CppVariant* result)
    341 {
    342     result->set(getAttributes(accessibilityObject()));
    343 }
    344 
    345 void AccessibilityUIElement::attributesOfLinkedUIElementsCallback(const CppArgumentList&, CppVariant* result)
    346 {
    347     result->setNull();
    348 }
    349 
    350 void AccessibilityUIElement::attributesOfDocumentLinksCallback(const CppArgumentList&, CppVariant* result)
    351 {
    352     result->setNull();
    353 }
    354 
    355 void AccessibilityUIElement::attributesOfChildrenCallback(const CppArgumentList& arguments, CppVariant* result)
    356 {
    357     AttributesCollector collector;
    358     unsigned size = accessibilityObject().childCount();
    359     for (unsigned i = 0; i < size; ++i)
    360         collector.collectAttributes(accessibilityObject().childAt(i));
    361     result->set(collector.attributes());
    362 }
    363 
    364 void AccessibilityUIElement::parametrizedAttributeNamesCallback(const CppArgumentList&, CppVariant* result)
    365 {
    366     result->setNull();
    367 }
    368 
    369 void AccessibilityUIElement::lineForIndexCallback(const CppArgumentList&, CppVariant* result)
    370 {
    371     result->setNull();
    372 }
    373 
    374 void AccessibilityUIElement::boundsForRangeCallback(const CppArgumentList&, CppVariant* result)
    375 {
    376     result->setNull();
    377 }
    378 
    379 void AccessibilityUIElement::stringForRangeCallback(const CppArgumentList&, CppVariant* result)
    380 {
    381     result->setNull();
    382 }
    383 
    384 void AccessibilityUIElement::childAtIndexCallback(const CppArgumentList& arguments, CppVariant* result)
    385 {
    386     if (!arguments.size() || !arguments[0].isNumber()) {
    387         result->setNull();
    388         return;
    389     }
    390 
    391     AccessibilityUIElement* child = getChildAtIndex(arguments[0].toInt32());
    392     if (!child) {
    393         result->setNull();
    394         return;
    395     }
    396 
    397     result->set(*(child->getAsCppVariant()));
    398 }
    399 
    400 void AccessibilityUIElement::elementAtPointCallback(const CppArgumentList&, CppVariant* result)
    401 {
    402     result->setNull();
    403 }
    404 
    405 void AccessibilityUIElement::attributesOfColumnHeadersCallback(const CppArgumentList&, CppVariant* result)
    406 {
    407     result->setNull();
    408 }
    409 
    410 void AccessibilityUIElement::attributesOfRowHeadersCallback(const CppArgumentList&, CppVariant* result)
    411 {
    412     result->setNull();
    413 }
    414 
    415 void AccessibilityUIElement::attributesOfColumnsCallback(const CppArgumentList&, CppVariant* result)
    416 {
    417     result->setNull();
    418 }
    419 
    420 void AccessibilityUIElement::attributesOfRowsCallback(const CppArgumentList&, CppVariant* result)
    421 {
    422     result->setNull();
    423 }
    424 
    425 void AccessibilityUIElement::attributesOfVisibleCellsCallback(const CppArgumentList&, CppVariant* result)
    426 {
    427     result->setNull();
    428 }
    429 
    430 void AccessibilityUIElement::attributesOfHeaderCallback(const CppArgumentList&, CppVariant* result)
    431 {
    432     result->setNull();
    433 }
    434 
    435 void AccessibilityUIElement::indexInTableCallback(const CppArgumentList&, CppVariant* result)
    436 {
    437     result->setNull();
    438 }
    439 
    440 void AccessibilityUIElement::rowIndexRangeCallback(const CppArgumentList&, CppVariant* result)
    441 {
    442     result->setNull();
    443 }
    444 
    445 void AccessibilityUIElement::columnIndexRangeCallback(const CppArgumentList&, CppVariant* result)
    446 {
    447     result->setNull();
    448 }
    449 
    450 void AccessibilityUIElement::cellForColumnAndRowCallback(const CppArgumentList&, CppVariant* result)
    451 {
    452     result->setNull();
    453 }
    454 
    455 void AccessibilityUIElement::titleUIElementCallback(const CppArgumentList&, CppVariant* result)
    456 {
    457     result->setNull();
    458 }
    459 
    460 void AccessibilityUIElement::setSelectedTextRangeCallback(const CppArgumentList&, CppVariant* result)
    461 {
    462     result->setNull();
    463 }
    464 
    465 void AccessibilityUIElement::attributeValueCallback(const CppArgumentList&, CppVariant* result)
    466 {
    467     result->setNull();
    468 }
    469 
    470 void AccessibilityUIElement::isAttributeSettableCallback(const CppArgumentList& arguments, CppVariant* result)
    471 {
    472     if (arguments.size() < 1 && !arguments[0].isString()) {
    473         result->setNull();
    474         return;
    475     }
    476 
    477     string attribute = arguments[0].toString();
    478     bool settable = false;
    479     if (attribute == "AXValue")
    480         settable = accessibilityObject().canSetValueAttribute();
    481     result->set(settable);
    482 }
    483 
    484 void AccessibilityUIElement::isActionSupportedCallback(const CppArgumentList&, CppVariant* result)
    485 {
    486     // This one may be really hard to implement.
    487     // Not exposed by AccessibilityObject.
    488     result->setNull();
    489 }
    490 
    491 void AccessibilityUIElement::parentElementCallback(const CppArgumentList&, CppVariant* result)
    492 {
    493     result->setNull();
    494 }
    495 
    496 void AccessibilityUIElement::incrementCallback(const CppArgumentList&, CppVariant* result)
    497 {
    498     result->setNull();
    499 }
    500 
    501 void AccessibilityUIElement::decrementCallback(const CppArgumentList&, CppVariant* result)
    502 {
    503     result->setNull();
    504 }
    505 
    506 void AccessibilityUIElement::fallbackCallback(const CppArgumentList &, CppVariant* result)
    507 {
    508     // FIXME: Implement this.
    509     result->setNull();
    510 }
    511 
    512 void AccessibilityUIElement::childrenCountGetterCallback(CppVariant* result)
    513 {
    514     int count = 1; // Root object always has only one child, the WebView.
    515     if (!isRoot())
    516         count = accessibilityObject().childCount();
    517     result->set(count);
    518 }
    519 
    520 void AccessibilityUIElement::descriptionGetterCallback(CppVariant* result)
    521 {
    522     result->set(getDescription(accessibilityObject()));
    523 }
    524 
    525 void AccessibilityUIElement::isEnabledGetterCallback(CppVariant* result)
    526 {
    527     result->set(accessibilityObject().isEnabled());
    528 }
    529 
    530 void AccessibilityUIElement::isSelectedGetterCallback(CppVariant* result)
    531 {
    532     result->setNull();
    533 }
    534 
    535 void AccessibilityUIElement::roleGetterCallback(CppVariant* result)
    536 {
    537     result->set(getRole(accessibilityObject()));
    538 }
    539 
    540 void AccessibilityUIElement::titleGetterCallback(CppVariant* result)
    541 {
    542     result->set(getTitle(accessibilityObject()));
    543 }
    544 
    545 
    546 RootAccessibilityUIElement::RootAccessibilityUIElement(const WebAccessibilityObject &object, Factory *factory)
    547     : AccessibilityUIElement(object, factory) { }
    548 
    549 AccessibilityUIElement* RootAccessibilityUIElement::getChildAtIndex(unsigned index)
    550 {
    551     if (index)
    552         return 0;
    553 
    554     return factory()->create(accessibilityObject());
    555 }
    556 
    557 
    558 AccessibilityUIElementList ::~AccessibilityUIElementList()
    559 {
    560     clear();
    561 }
    562 
    563 void AccessibilityUIElementList::clear()
    564 {
    565     for (ElementList::iterator i = m_elements.begin(); i != m_elements.end(); ++i)
    566         delete (*i);
    567     m_elements.clear();
    568 }
    569 
    570 AccessibilityUIElement* AccessibilityUIElementList::create(const WebAccessibilityObject& object)
    571 {
    572     if (object.isNull())
    573         return 0;
    574 
    575     AccessibilityUIElement* element = new AccessibilityUIElement(object, this);
    576     m_elements.append(element);
    577     return element;
    578 }
    579 
    580 AccessibilityUIElement* AccessibilityUIElementList::createRoot(const WebAccessibilityObject& object)
    581 {
    582     AccessibilityUIElement* element = new RootAccessibilityUIElement(object, this);
    583     m_elements.append(element);
    584     return element;
    585 }
    586