Home | History | Annotate | Download | only in accessibility
      1 /*
      2 * Copyright (C) 2012, 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
      6 * are met:
      7 *
      8 * 1.  Redistributions of source code must retain the above copyright
      9 *     notice, this list of conditions and the following disclaimer.
     10 * 2.  Redistributions in binary form must reproduce the above copyright
     11 *     notice, this list of conditions and the following disclaimer in the
     12 *     documentation and/or other materials provided with the distribution.
     13 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     14 *     its contributors may be used to endorse or promote products derived
     15 *     from this software without specific prior written permission.
     16 *
     17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 */
     28 
     29 #include "config.h"
     30 #include "core/accessibility/AXNodeObject.h"
     31 
     32 #include "core/accessibility/AXObjectCache.h"
     33 #include "core/dom/NodeTraversal.h"
     34 #include "core/dom/Text.h"
     35 #include "core/html/HTMLAnchorElement.h"
     36 #include "core/html/HTMLFieldSetElement.h"
     37 #include "core/html/HTMLFrameElementBase.h"
     38 #include "core/html/HTMLInputElement.h"
     39 #include "core/html/HTMLLabelElement.h"
     40 #include "core/html/HTMLLegendElement.h"
     41 #include "core/html/HTMLSelectElement.h"
     42 #include "core/html/HTMLTextAreaElement.h"
     43 #include "core/rendering/RenderObject.h"
     44 #include "platform/UserGestureIndicator.h"
     45 #include "wtf/text/StringBuilder.h"
     46 
     47 using namespace std;
     48 
     49 namespace WebCore {
     50 
     51 using namespace HTMLNames;
     52 
     53 AXNodeObject::AXNodeObject(Node* node)
     54     : AXObject()
     55     , m_ariaRole(UnknownRole)
     56     , m_childrenDirty(false)
     57 #ifndef NDEBUG
     58     , m_initialized(false)
     59 #endif
     60     , m_node(node)
     61 {
     62 }
     63 
     64 PassRefPtr<AXNodeObject> AXNodeObject::create(Node* node)
     65 {
     66     return adoptRef(new AXNodeObject(node));
     67 }
     68 
     69 AXNodeObject::~AXNodeObject()
     70 {
     71     ASSERT(isDetached());
     72 }
     73 
     74 // This function implements the ARIA accessible name as described by the Mozilla
     75 // ARIA Implementer's Guide.
     76 static String accessibleNameForNode(Node* node)
     77 {
     78     if (node->isTextNode())
     79         return toText(node)->data();
     80 
     81     if (node->hasTagName(inputTag))
     82         return toHTMLInputElement(node)->value();
     83 
     84     if (node->isHTMLElement()) {
     85         const AtomicString& alt = toHTMLElement(node)->getAttribute(altAttr);
     86         if (!alt.isEmpty())
     87             return alt;
     88     }
     89 
     90     return String();
     91 }
     92 
     93 String AXNodeObject::accessibilityDescriptionForElements(Vector<Element*> &elements) const
     94 {
     95     StringBuilder builder;
     96     unsigned size = elements.size();
     97     for (unsigned i = 0; i < size; ++i) {
     98         Element* idElement = elements[i];
     99 
    100         builder.append(accessibleNameForNode(idElement));
    101         for (Node* n = idElement->firstChild(); n; n = NodeTraversal::next(*n, idElement))
    102             builder.append(accessibleNameForNode(n));
    103 
    104         if (i != size - 1)
    105             builder.append(' ');
    106     }
    107     return builder.toString();
    108 }
    109 
    110 void AXNodeObject::alterSliderValue(bool increase)
    111 {
    112     if (roleValue() != SliderRole)
    113         return;
    114 
    115     if (!getAttribute(stepAttr).isEmpty())
    116         changeValueByStep(increase);
    117     else
    118         changeValueByPercent(increase ? 5 : -5);
    119 }
    120 
    121 String AXNodeObject::ariaAccessibilityDescription() const
    122 {
    123     String ariaLabeledBy = ariaLabeledByAttribute();
    124     if (!ariaLabeledBy.isEmpty())
    125         return ariaLabeledBy;
    126 
    127     const AtomicString& ariaLabel = getAttribute(aria_labelAttr);
    128     if (!ariaLabel.isEmpty())
    129         return ariaLabel;
    130 
    131     return String();
    132 }
    133 
    134 
    135 void AXNodeObject::ariaLabeledByElements(Vector<Element*>& elements) const
    136 {
    137     elementsFromAttribute(elements, aria_labeledbyAttr);
    138     if (!elements.size())
    139         elementsFromAttribute(elements, aria_labelledbyAttr);
    140 }
    141 
    142 void AXNodeObject::changeValueByStep(bool increase)
    143 {
    144     float step = stepValueForRange();
    145     float value = valueForRange();
    146 
    147     value += increase ? step : -step;
    148 
    149     setValue(String::number(value));
    150 
    151     axObjectCache()->postNotification(node(), AXObjectCache::AXValueChanged, true);
    152 }
    153 
    154 bool AXNodeObject::computeAccessibilityIsIgnored() const
    155 {
    156 #ifndef NDEBUG
    157     // Double-check that an AXObject is never accessed before
    158     // it's been initialized.
    159     ASSERT(m_initialized);
    160 #endif
    161 
    162     // If this element is within a parent that cannot have children, it should not be exposed.
    163     if (isDescendantOfBarrenParent())
    164         return true;
    165 
    166     // Ignore labels that are already referenced by a control's title UI element.
    167     AXObject* controlObject = correspondingControlForLabelElement();
    168     if (controlObject && !controlObject->exposesTitleUIElement() && controlObject->isCheckboxOrRadio())
    169         return true;
    170 
    171     return m_role == UnknownRole;
    172 }
    173 
    174 AccessibilityRole AXNodeObject::determineAccessibilityRole()
    175 {
    176     if (!node())
    177         return UnknownRole;
    178 
    179     m_ariaRole = determineAriaRoleAttribute();
    180 
    181     AccessibilityRole ariaRole = ariaRoleAttribute();
    182     if (ariaRole != UnknownRole)
    183         return ariaRole;
    184 
    185     if (node()->isLink())
    186         return LinkRole;
    187     if (node()->isTextNode())
    188         return StaticTextRole;
    189     if (node()->hasTagName(buttonTag))
    190         return buttonRoleType();
    191     if (node()->hasTagName(inputTag)) {
    192         HTMLInputElement* input = toHTMLInputElement(node());
    193         if (input->isCheckbox())
    194             return CheckBoxRole;
    195         if (input->isRadioButton())
    196             return RadioButtonRole;
    197         if (input->isTextButton())
    198             return buttonRoleType();
    199         if (input->isRangeControl())
    200             return SliderRole;
    201 
    202         const AtomicString& type = input->getAttribute(typeAttr);
    203         if (equalIgnoringCase(type, "color"))
    204             return ColorWellRole;
    205 
    206         return TextFieldRole;
    207     }
    208     if (node()->hasTagName(selectTag)) {
    209         HTMLSelectElement* selectElement = toHTMLSelectElement(node());
    210         return selectElement->multiple() ? ListBoxRole : PopUpButtonRole;
    211     }
    212     if (isHTMLTextAreaElement(node()))
    213         return TextAreaRole;
    214     if (headingLevel())
    215         return HeadingRole;
    216     if (node()->hasTagName(divTag))
    217         return DivRole;
    218     if (node()->hasTagName(pTag))
    219         return ParagraphRole;
    220     if (isHTMLLabelElement(node()))
    221         return LabelRole;
    222     if (node()->isElementNode() && toElement(node())->isFocusable())
    223         return GroupRole;
    224     if (node()->hasTagName(aTag) && isClickable())
    225         return LinkRole;
    226 
    227     return UnknownRole;
    228 }
    229 
    230 AccessibilityRole AXNodeObject::determineAriaRoleAttribute() const
    231 {
    232     const AtomicString& ariaRole = getAttribute(roleAttr);
    233     if (ariaRole.isNull() || ariaRole.isEmpty())
    234         return UnknownRole;
    235 
    236     AccessibilityRole role = ariaRoleToWebCoreRole(ariaRole);
    237 
    238     // ARIA states if an item can get focus, it should not be presentational.
    239     if (role == PresentationalRole && canSetFocusAttribute())
    240         return UnknownRole;
    241 
    242     if (role == ButtonRole)
    243         role = buttonRoleType();
    244 
    245     if (role == TextAreaRole && !ariaIsMultiline())
    246         role = TextFieldRole;
    247 
    248     role = remapAriaRoleDueToParent(role);
    249 
    250     if (role)
    251         return role;
    252 
    253     return UnknownRole;
    254 }
    255 
    256 void AXNodeObject::elementsFromAttribute(Vector<Element*>& elements, const QualifiedName& attribute) const
    257 {
    258     Node* node = this->node();
    259     if (!node || !node->isElementNode())
    260         return;
    261 
    262     TreeScope& scope = node->treeScope();
    263 
    264     String idList = getAttribute(attribute).string();
    265     if (idList.isEmpty())
    266         return;
    267 
    268     idList.replace('\n', ' ');
    269     Vector<String> idVector;
    270     idList.split(' ', idVector);
    271 
    272     unsigned size = idVector.size();
    273     for (unsigned i = 0; i < size; ++i) {
    274         AtomicString idName(idVector[i]);
    275         Element* idElement = scope.getElementById(idName);
    276         if (idElement)
    277             elements.append(idElement);
    278     }
    279 }
    280 
    281 // If you call node->rendererIsEditable() since that will return true if an ancestor is editable.
    282 // This only returns true if this is the element that actually has the contentEditable attribute set.
    283 bool AXNodeObject::hasContentEditableAttributeSet() const
    284 {
    285     if (!hasAttribute(contenteditableAttr))
    286         return false;
    287     const AtomicString& contentEditableValue = getAttribute(contenteditableAttr);
    288     // Both "true" (case-insensitive) and the empty string count as true.
    289     return contentEditableValue.isEmpty() || equalIgnoringCase(contentEditableValue, "true");
    290 }
    291 
    292 bool AXNodeObject::isDescendantOfBarrenParent() const
    293 {
    294     for (AXObject* object = parentObject(); object; object = object->parentObject()) {
    295         if (!object->canHaveChildren())
    296             return true;
    297     }
    298 
    299     return false;
    300 }
    301 
    302 bool AXNodeObject::isGenericFocusableElement() const
    303 {
    304     if (!canSetFocusAttribute())
    305         return false;
    306 
    307     // If it's a control, it's not generic.
    308     if (isControl())
    309         return false;
    310 
    311     // If it has an aria role, it's not generic.
    312     if (m_ariaRole != UnknownRole)
    313         return false;
    314 
    315     // If the content editable attribute is set on this element, that's the reason
    316     // it's focusable, and existing logic should handle this case already - so it's not a
    317     // generic focusable element.
    318 
    319     if (hasContentEditableAttributeSet())
    320         return false;
    321 
    322     // The web area and body element are both focusable, but existing logic handles these
    323     // cases already, so we don't need to include them here.
    324     if (roleValue() == WebAreaRole)
    325         return false;
    326     if (node() && node()->hasTagName(bodyTag))
    327         return false;
    328 
    329     // An SVG root is focusable by default, but it's probably not interactive, so don't
    330     // include it. It can still be made accessible by giving it an ARIA role.
    331     if (roleValue() == SVGRootRole)
    332         return false;
    333 
    334     return true;
    335 }
    336 
    337 HTMLLabelElement* AXNodeObject::labelForElement(Element* element) const
    338 {
    339     if (!element->isHTMLElement() || !toHTMLElement(element)->isLabelable())
    340         return 0;
    341 
    342     const AtomicString& id = element->getIdAttribute();
    343     if (!id.isEmpty()) {
    344         if (HTMLLabelElement* label = element->treeScope().labelElementForId(id))
    345             return label;
    346     }
    347 
    348     for (Element* parent = element->parentElement(); parent; parent = parent->parentElement()) {
    349         if (isHTMLLabelElement(parent))
    350             return toHTMLLabelElement(parent);
    351     }
    352 
    353     return 0;
    354 }
    355 
    356 AXObject* AXNodeObject::menuButtonForMenu() const
    357 {
    358     Element* menuItem = menuItemElementForMenu();
    359 
    360     if (menuItem) {
    361         // ARIA just has generic menu items. AppKit needs to know if this is a top level items like MenuBarButton or MenuBarItem
    362         AXObject* menuItemAX = axObjectCache()->getOrCreate(menuItem);
    363         if (menuItemAX && menuItemAX->isMenuButton())
    364             return menuItemAX;
    365     }
    366     return 0;
    367 }
    368 
    369 static Element* siblingWithAriaRole(String role, Node* node)
    370 {
    371     Node* parent = node->parentNode();
    372     if (!parent)
    373         return 0;
    374 
    375     for (Node* sibling = parent->firstChild(); sibling; sibling = sibling->nextSibling()) {
    376         if (sibling->isElementNode()) {
    377             const AtomicString& siblingAriaRole = toElement(sibling)->getAttribute(roleAttr);
    378             if (equalIgnoringCase(siblingAriaRole, role))
    379                 return toElement(sibling);
    380         }
    381     }
    382 
    383     return 0;
    384 }
    385 
    386 Element* AXNodeObject::menuItemElementForMenu() const
    387 {
    388     if (ariaRoleAttribute() != MenuRole)
    389         return 0;
    390 
    391     return siblingWithAriaRole("menuitem", node());
    392 }
    393 
    394 Element* AXNodeObject::mouseButtonListener() const
    395 {
    396     Node* node = this->node();
    397     if (!node)
    398         return 0;
    399 
    400     // check if our parent is a mouse button listener
    401     while (node && !node->isElementNode())
    402         node = node->parentNode();
    403 
    404     if (!node)
    405         return 0;
    406 
    407     // FIXME: Do the continuation search like anchorElement does
    408     for (Element* element = toElement(node); element; element = element->parentElement()) {
    409         if (element->getAttributeEventListener(EventTypeNames::click) || element->getAttributeEventListener(EventTypeNames::mousedown) || element->getAttributeEventListener(EventTypeNames::mouseup))
    410             return element;
    411     }
    412 
    413     return 0;
    414 }
    415 
    416 AccessibilityRole AXNodeObject::remapAriaRoleDueToParent(AccessibilityRole role) const
    417 {
    418     // Some objects change their role based on their parent.
    419     // However, asking for the unignoredParent calls accessibilityIsIgnored(), which can trigger a loop.
    420     // While inside the call stack of creating an element, we need to avoid accessibilityIsIgnored().
    421     // https://bugs.webkit.org/show_bug.cgi?id=65174
    422 
    423     if (role != ListBoxOptionRole && role != MenuItemRole)
    424         return role;
    425 
    426     for (AXObject* parent = parentObject(); parent && !parent->accessibilityIsIgnored(); parent = parent->parentObject()) {
    427         AccessibilityRole parentAriaRole = parent->ariaRoleAttribute();
    428 
    429         // Selects and listboxes both have options as child roles, but they map to different roles within WebCore.
    430         if (role == ListBoxOptionRole && parentAriaRole == MenuRole)
    431             return MenuItemRole;
    432         // An aria "menuitem" may map to MenuButton or MenuItem depending on its parent.
    433         if (role == MenuItemRole && parentAriaRole == GroupRole)
    434             return MenuButtonRole;
    435 
    436         // If the parent had a different role, then we don't need to continue searching up the chain.
    437         if (parentAriaRole)
    438             break;
    439     }
    440 
    441     return role;
    442 }
    443 
    444 void AXNodeObject::init()
    445 {
    446 #ifndef NDEBUG
    447     ASSERT(!m_initialized);
    448     m_initialized = true;
    449 #endif
    450     m_role = determineAccessibilityRole();
    451 }
    452 
    453 void AXNodeObject::detach()
    454 {
    455     clearChildren();
    456     AXObject::detach();
    457     m_node = 0;
    458 }
    459 
    460 bool AXNodeObject::isAnchor() const
    461 {
    462     return !isNativeImage() && isLink();
    463 }
    464 
    465 bool AXNodeObject::isControl() const
    466 {
    467     Node* node = this->node();
    468     if (!node)
    469         return false;
    470 
    471     return ((node->isElementNode() && toElement(node)->isFormControlElement())
    472         || AXObject::isARIAControl(ariaRoleAttribute()));
    473 }
    474 
    475 bool AXNodeObject::isFieldset() const
    476 {
    477     Node* node = this->node();
    478     if (!node)
    479         return false;
    480 
    481     return node->hasTagName(fieldsetTag);
    482 }
    483 
    484 bool AXNodeObject::isHeading() const
    485 {
    486     return roleValue() == HeadingRole;
    487 }
    488 
    489 bool AXNodeObject::isHovered() const
    490 {
    491     Node* node = this->node();
    492     if (!node)
    493         return false;
    494 
    495     return node->hovered();
    496 }
    497 
    498 bool AXNodeObject::isImage() const
    499 {
    500     return roleValue() == ImageRole;
    501 }
    502 
    503 bool AXNodeObject::isImageButton() const
    504 {
    505     return isNativeImage() && isButton();
    506 }
    507 
    508 bool AXNodeObject::isInputImage() const
    509 {
    510     Node* node = this->node();
    511     if (!node)
    512         return false;
    513 
    514     if (roleValue() == ButtonRole && node->hasTagName(inputTag))
    515         return toHTMLInputElement(node)->isImageButton();
    516 
    517     return false;
    518 }
    519 
    520 bool AXNodeObject::isLink() const
    521 {
    522     return roleValue() == LinkRole;
    523 }
    524 
    525 bool AXNodeObject::isMenu() const
    526 {
    527     return roleValue() == MenuRole;
    528 }
    529 
    530 bool AXNodeObject::isMenuButton() const
    531 {
    532     return roleValue() == MenuButtonRole;
    533 }
    534 
    535 bool AXNodeObject::isMultiSelectable() const
    536 {
    537     const AtomicString& ariaMultiSelectable = getAttribute(aria_multiselectableAttr);
    538     if (equalIgnoringCase(ariaMultiSelectable, "true"))
    539         return true;
    540     if (equalIgnoringCase(ariaMultiSelectable, "false"))
    541         return false;
    542 
    543     return node() && node()->hasTagName(selectTag) && toHTMLSelectElement(node())->multiple();
    544 }
    545 
    546 bool AXNodeObject::isNativeCheckboxOrRadio() const
    547 {
    548     Node* node = this->node();
    549     if (!node || !node->hasTagName(inputTag))
    550         return false;
    551 
    552     HTMLInputElement* input = toHTMLInputElement(node);
    553     return input->isCheckbox() || input->isRadioButton();
    554 }
    555 
    556 bool AXNodeObject::isNativeImage() const
    557 {
    558     Node* node = this->node();
    559     if (!node)
    560         return false;
    561 
    562     if (node->hasTagName(imgTag))
    563         return true;
    564 
    565     if (node->hasTagName(appletTag) || node->hasTagName(embedTag) || node->hasTagName(objectTag))
    566         return true;
    567 
    568     if (node->hasTagName(inputTag))
    569         return toHTMLInputElement(node)->isImageButton();
    570 
    571     return false;
    572 }
    573 
    574 bool AXNodeObject::isNativeTextControl() const
    575 {
    576     Node* node = this->node();
    577     if (!node)
    578         return false;
    579 
    580     if (isHTMLTextAreaElement(node))
    581         return true;
    582 
    583     if (node->hasTagName(inputTag)) {
    584         HTMLInputElement* input = toHTMLInputElement(node);
    585         return input->isText() || input->isNumberField();
    586     }
    587 
    588     return false;
    589 }
    590 
    591 bool AXNodeObject::isNonNativeTextControl() const
    592 {
    593     if (isNativeTextControl())
    594         return false;
    595 
    596     if (hasContentEditableAttributeSet())
    597         return true;
    598 
    599     if (isARIATextControl())
    600         return true;
    601 
    602     return false;
    603 }
    604 
    605 bool AXNodeObject::isPasswordField() const
    606 {
    607     Node* node = this->node();
    608     if (!node || !node->hasTagName(inputTag))
    609         return false;
    610 
    611     if (ariaRoleAttribute() != UnknownRole)
    612         return false;
    613 
    614     return toHTMLInputElement(node)->isPasswordField();
    615 }
    616 
    617 bool AXNodeObject::isProgressIndicator() const
    618 {
    619     return roleValue() == ProgressIndicatorRole;
    620 }
    621 
    622 bool AXNodeObject::isSlider() const
    623 {
    624     return roleValue() == SliderRole;
    625 }
    626 
    627 bool AXNodeObject::isChecked() const
    628 {
    629     Node* node = this->node();
    630     if (!node)
    631         return false;
    632 
    633     // First test for native checkedness semantics
    634     if (node->hasTagName(inputTag))
    635         return toHTMLInputElement(node)->shouldAppearChecked();
    636 
    637     // Else, if this is an ARIA checkbox or radio, respect the aria-checked attribute
    638     AccessibilityRole ariaRole = ariaRoleAttribute();
    639     if (ariaRole == RadioButtonRole || ariaRole == CheckBoxRole) {
    640         if (equalIgnoringCase(getAttribute(aria_checkedAttr), "true"))
    641             return true;
    642         return false;
    643     }
    644 
    645     // Otherwise it's not checked
    646     return false;
    647 }
    648 
    649 bool AXNodeObject::isClickable() const
    650 {
    651     if (node()) {
    652         if (node()->isElementNode() && toElement(node())->isDisabledFormControl())
    653             return false;
    654 
    655         // Note: we can't call node()->willRespondToMouseClickEvents() because that triggers a style recalc and can delete this.
    656         if (node()->hasEventListeners(EventTypeNames::mouseup) || node()->hasEventListeners(EventTypeNames::mousedown) || node()->hasEventListeners(EventTypeNames::click) || node()->hasEventListeners(EventTypeNames::DOMActivate))
    657             return true;
    658     }
    659 
    660     return AXObject::isClickable();
    661 }
    662 
    663 bool AXNodeObject::isEnabled() const
    664 {
    665     if (equalIgnoringCase(getAttribute(aria_disabledAttr), "true"))
    666         return false;
    667 
    668     Node* node = this->node();
    669     if (!node || !node->isElementNode())
    670         return true;
    671 
    672     return !toElement(node)->isDisabledFormControl();
    673 }
    674 
    675 bool AXNodeObject::isIndeterminate() const
    676 {
    677     Node* node = this->node();
    678     if (!node || !node->hasTagName(inputTag))
    679         return false;
    680 
    681     return toHTMLInputElement(node)->shouldAppearIndeterminate();
    682 }
    683 
    684 bool AXNodeObject::isPressed() const
    685 {
    686     if (!isButton())
    687         return false;
    688 
    689     Node* node = this->node();
    690     if (!node)
    691         return false;
    692 
    693     // If this is an ARIA button, check the aria-pressed attribute rather than node()->active()
    694     if (ariaRoleAttribute() == ButtonRole) {
    695         if (equalIgnoringCase(getAttribute(aria_pressedAttr), "true"))
    696             return true;
    697         return false;
    698     }
    699 
    700     return node->active();
    701 }
    702 
    703 bool AXNodeObject::isReadOnly() const
    704 {
    705     Node* node = this->node();
    706     if (!node)
    707         return true;
    708 
    709     if (isHTMLTextAreaElement(node))
    710         return toHTMLFormControlElement(node)->isReadOnly();
    711 
    712     if (node->hasTagName(inputTag)) {
    713         HTMLInputElement* input = toHTMLInputElement(node);
    714         if (input->isTextField())
    715             return input->isReadOnly();
    716     }
    717 
    718     return !node->rendererIsEditable();
    719 }
    720 
    721 bool AXNodeObject::isRequired() const
    722 {
    723     if (equalIgnoringCase(getAttribute(aria_requiredAttr), "true"))
    724         return true;
    725 
    726     Node* n = this->node();
    727     if (n && (n->isElementNode() && toElement(n)->isFormControlElement()))
    728         return toHTMLFormControlElement(n)->isRequired();
    729 
    730     return false;
    731 }
    732 
    733 bool AXNodeObject::canSetFocusAttribute() const
    734 {
    735     Node* node = this->node();
    736     if (!node)
    737         return false;
    738 
    739     if (isWebArea())
    740         return true;
    741 
    742     // NOTE: It would be more accurate to ask the document whether setFocusedNode() would
    743     // do anything. For example, setFocusedNode() will do nothing if the current focused
    744     // node will not relinquish the focus.
    745     if (!node)
    746         return false;
    747 
    748     if (isDisabledFormControl(node))
    749         return false;
    750 
    751     return node->isElementNode() && toElement(node)->supportsFocus();
    752 }
    753 
    754 bool AXNodeObject::canSetValueAttribute() const
    755 {
    756     if (equalIgnoringCase(getAttribute(aria_readonlyAttr), "true"))
    757         return false;
    758 
    759     if (isProgressIndicator() || isSlider())
    760         return true;
    761 
    762     if (isTextControl() && !isNativeTextControl())
    763         return true;
    764 
    765     // Any node could be contenteditable, so isReadOnly should be relied upon
    766     // for this information for all elements.
    767     return !isReadOnly();
    768 }
    769 
    770 bool AXNodeObject::canvasHasFallbackContent() const
    771 {
    772     Node* node = this->node();
    773     if (!node || !node->hasTagName(canvasTag))
    774         return false;
    775 
    776     // If it has any children that are elements, we'll assume it might be fallback
    777     // content. If it has no children or its only children are not elements
    778     // (e.g. just text nodes), it doesn't have fallback content.
    779     for (Node* child = node->firstChild(); child; child = child->nextSibling()) {
    780         if (child->isElementNode())
    781             return true;
    782     }
    783 
    784     return false;
    785 }
    786 
    787 bool AXNodeObject::exposesTitleUIElement() const
    788 {
    789     if (!isControl())
    790         return false;
    791 
    792     // If this control is ignored (because it's invisible),
    793     // then the label needs to be exposed so it can be visible to accessibility.
    794     if (accessibilityIsIgnored())
    795         return true;
    796 
    797     // ARIA: section 2A, bullet #3 says if aria-labeledby or aria-label appears, it should
    798     // override the "label" element association.
    799     bool hasTextAlternative = (!ariaLabeledByAttribute().isEmpty() || !getAttribute(aria_labelAttr).isEmpty());
    800 
    801     // Checkboxes and radio buttons use the text of their title ui element as their own AXTitle.
    802     // This code controls whether the title ui element should appear in the AX tree (usually, no).
    803     // It should appear if the control already has a label (which will be used as the AXTitle instead).
    804     if (isCheckboxOrRadio())
    805         return hasTextAlternative;
    806 
    807     // When controls have their own descriptions, the title element should be ignored.
    808     if (hasTextAlternative)
    809         return false;
    810 
    811     return true;
    812 }
    813 
    814 int AXNodeObject::headingLevel() const
    815 {
    816     // headings can be in block flow and non-block flow
    817     Node* node = this->node();
    818     if (!node)
    819         return false;
    820 
    821     if (ariaRoleAttribute() == HeadingRole)
    822         return getAttribute(aria_levelAttr).toInt();
    823 
    824     if (node->hasTagName(h1Tag))
    825         return 1;
    826 
    827     if (node->hasTagName(h2Tag))
    828         return 2;
    829 
    830     if (node->hasTagName(h3Tag))
    831         return 3;
    832 
    833     if (node->hasTagName(h4Tag))
    834         return 4;
    835 
    836     if (node->hasTagName(h5Tag))
    837         return 5;
    838 
    839     if (node->hasTagName(h6Tag))
    840         return 6;
    841 
    842     return 0;
    843 }
    844 
    845 unsigned AXNodeObject::hierarchicalLevel() const
    846 {
    847     Node* node = this->node();
    848     if (!node || !node->isElementNode())
    849         return 0;
    850     Element* element = toElement(node);
    851     String ariaLevel = element->getAttribute(aria_levelAttr);
    852     if (!ariaLevel.isEmpty())
    853         return ariaLevel.toInt();
    854 
    855     // Only tree item will calculate its level through the DOM currently.
    856     if (roleValue() != TreeItemRole)
    857         return 0;
    858 
    859     // Hierarchy leveling starts at 1, to match the aria-level spec.
    860     // We measure tree hierarchy by the number of groups that the item is within.
    861     unsigned level = 1;
    862     for (AXObject* parent = parentObject(); parent; parent = parent->parentObject()) {
    863         AccessibilityRole parentRole = parent->roleValue();
    864         if (parentRole == GroupRole)
    865             level++;
    866         else if (parentRole == TreeRole)
    867             break;
    868     }
    869 
    870     return level;
    871 }
    872 
    873 String AXNodeObject::text() const
    874 {
    875     // If this is a user defined static text, use the accessible name computation.
    876     if (ariaRoleAttribute() == StaticTextRole)
    877         return ariaAccessibilityDescription();
    878 
    879     if (!isTextControl())
    880         return String();
    881 
    882     Node* node = this->node();
    883     if (!node)
    884         return String();
    885 
    886     if (isNativeTextControl() && (isHTMLTextAreaElement(node) || node->hasTagName(inputTag)))
    887         return toHTMLTextFormControlElement(node)->value();
    888 
    889     if (!node->isElementNode())
    890         return String();
    891 
    892     return toElement(node)->innerText();
    893 }
    894 
    895 AXObject* AXNodeObject::titleUIElement() const
    896 {
    897     if (!node() || !node()->isElementNode())
    898         return 0;
    899 
    900     if (isFieldset())
    901         return axObjectCache()->getOrCreate(toHTMLFieldSetElement(node())->legend());
    902 
    903     HTMLLabelElement* label = labelForElement(toElement(node()));
    904     if (label)
    905         return axObjectCache()->getOrCreate(label);
    906 
    907     return 0;
    908 }
    909 
    910 AccessibilityButtonState AXNodeObject::checkboxOrRadioValue() const
    911 {
    912     if (isNativeCheckboxOrRadio())
    913         return isChecked() ? ButtonStateOn : ButtonStateOff;
    914 
    915     return AXObject::checkboxOrRadioValue();
    916 }
    917 
    918 void AXNodeObject::colorValue(int& r, int& g, int& b) const
    919 {
    920     r = 0;
    921     g = 0;
    922     b = 0;
    923 
    924     if (!isColorWell())
    925         return;
    926 
    927     if (!node() || !node()->hasTagName(inputTag))
    928         return;
    929 
    930     HTMLInputElement* input = toHTMLInputElement(node());
    931     const AtomicString& type = input->getAttribute(typeAttr);
    932     if (!equalIgnoringCase(type, "color"))
    933         return;
    934 
    935     // HTMLInputElement::value always returns a string parseable by Color().
    936     Color color(input->value());
    937     r = color.red();
    938     g = color.green();
    939     b = color.blue();
    940 }
    941 
    942 String AXNodeObject::valueDescription() const
    943 {
    944     if (!supportsRangeValue())
    945         return String();
    946 
    947     return getAttribute(aria_valuetextAttr).string();
    948 }
    949 
    950 float AXNodeObject::valueForRange() const
    951 {
    952     if (hasAttribute(aria_valuenowAttr))
    953         return getAttribute(aria_valuenowAttr).toFloat();
    954 
    955     if (node() && node()->hasTagName(inputTag)) {
    956         HTMLInputElement* input = toHTMLInputElement(node());
    957         if (input->isRangeControl())
    958             return input->valueAsNumber();
    959     }
    960 
    961     return 0.0;
    962 }
    963 
    964 float AXNodeObject::maxValueForRange() const
    965 {
    966     if (hasAttribute(aria_valuemaxAttr))
    967         return getAttribute(aria_valuemaxAttr).toFloat();
    968 
    969     if (node() && node()->hasTagName(inputTag)) {
    970         HTMLInputElement* input = toHTMLInputElement(node());
    971         if (input->isRangeControl())
    972             return input->maximum();
    973     }
    974 
    975     return 0.0;
    976 }
    977 
    978 float AXNodeObject::minValueForRange() const
    979 {
    980     if (hasAttribute(aria_valueminAttr))
    981         return getAttribute(aria_valueminAttr).toFloat();
    982 
    983     if (node() && node()->hasTagName(inputTag)) {
    984         HTMLInputElement* input = toHTMLInputElement(node());
    985         if (input->isRangeControl())
    986             return input->minimum();
    987     }
    988 
    989     return 0.0;
    990 }
    991 
    992 float AXNodeObject::stepValueForRange() const
    993 {
    994     return getAttribute(stepAttr).toFloat();
    995 }
    996 
    997 String AXNodeObject::stringValue() const
    998 {
    999     Node* node = this->node();
   1000     if (!node)
   1001         return String();
   1002 
   1003     if (ariaRoleAttribute() == StaticTextRole) {
   1004         String staticText = text();
   1005         if (!staticText.length())
   1006             staticText = textUnderElement();
   1007         return staticText;
   1008     }
   1009 
   1010     if (node->isTextNode())
   1011         return textUnderElement();
   1012 
   1013     if (node->hasTagName(selectTag)) {
   1014         HTMLSelectElement* selectElement = toHTMLSelectElement(node);
   1015         int selectedIndex = selectElement->selectedIndex();
   1016         const Vector<HTMLElement*> listItems = selectElement->listItems();
   1017         if (selectedIndex >= 0 && static_cast<size_t>(selectedIndex) < listItems.size()) {
   1018             const AtomicString& overriddenDescription = listItems[selectedIndex]->fastGetAttribute(aria_labelAttr);
   1019             if (!overriddenDescription.isNull())
   1020                 return overriddenDescription;
   1021         }
   1022         if (!selectElement->multiple())
   1023             return selectElement->value();
   1024         return String();
   1025     }
   1026 
   1027     if (isTextControl())
   1028         return text();
   1029 
   1030     // FIXME: We might need to implement a value here for more types
   1031     // FIXME: It would be better not to advertise a value at all for the types for which we don't implement one;
   1032     // this would require subclassing or making accessibilityAttributeNames do something other than return a
   1033     // single static array.
   1034     return String();
   1035 }
   1036 
   1037 String AXNodeObject::ariaDescribedByAttribute() const
   1038 {
   1039     Vector<Element*> elements;
   1040     elementsFromAttribute(elements, aria_describedbyAttr);
   1041 
   1042     return accessibilityDescriptionForElements(elements);
   1043 }
   1044 
   1045 
   1046 String AXNodeObject::ariaLabeledByAttribute() const
   1047 {
   1048     Vector<Element*> elements;
   1049     ariaLabeledByElements(elements);
   1050 
   1051     return accessibilityDescriptionForElements(elements);
   1052 }
   1053 
   1054 AccessibilityRole AXNodeObject::ariaRoleAttribute() const
   1055 {
   1056     return m_ariaRole;
   1057 }
   1058 
   1059 void AXNodeObject::accessibilityText(Vector<AccessibilityText>& textOrder)
   1060 {
   1061     titleElementText(textOrder);
   1062     alternativeText(textOrder);
   1063     visibleText(textOrder);
   1064     helpText(textOrder);
   1065 
   1066     String placeholder = placeholderValue();
   1067     if (!placeholder.isEmpty())
   1068         textOrder.append(AccessibilityText(placeholder, PlaceholderText));
   1069 }
   1070 
   1071 // When building the textUnderElement for an object, determine whether or not
   1072 // we should include the inner text of this given descendant object or skip it.
   1073 static bool shouldUseAccessiblityObjectInnerText(AXObject* obj)
   1074 {
   1075     // Consider this hypothetical example:
   1076     // <div tabindex=0>
   1077     //   <h2>
   1078     //     Table of contents
   1079     //   </h2>
   1080     //   <a href="#start">Jump to start of book</a>
   1081     //   <ul>
   1082     //     <li><a href="#1">Chapter 1</a></li>
   1083     //     <li><a href="#1">Chapter 2</a></li>
   1084     //   </ul>
   1085     // </div>
   1086     //
   1087     // The goal is to return a reasonable title for the outer container div, because
   1088     // it's focusable - but without making its title be the full inner text, which is
   1089     // quite long. As a heuristic, skip links, controls, and elements that are usually
   1090     // containers with lots of children.
   1091 
   1092     // Skip hidden children
   1093     if (obj->isInertOrAriaHidden())
   1094         return false;
   1095 
   1096     // Skip focusable children, so we don't include the text of links and controls.
   1097     if (obj->canSetFocusAttribute())
   1098         return false;
   1099 
   1100     // Skip big container elements like lists, tables, etc.
   1101     if (obj->isList() || obj->isAXTable() || obj->isTree() || obj->isCanvas())
   1102         return false;
   1103 
   1104     return true;
   1105 }
   1106 
   1107 String AXNodeObject::textUnderElement() const
   1108 {
   1109     Node* node = this->node();
   1110     if (node && node->isTextNode())
   1111         return toText(node)->wholeText();
   1112 
   1113     StringBuilder builder;
   1114     for (AXObject* child = firstChild(); child; child = child->nextSibling()) {
   1115         if (!shouldUseAccessiblityObjectInnerText(child))
   1116             continue;
   1117 
   1118         if (child->isAXNodeObject()) {
   1119             Vector<AccessibilityText> textOrder;
   1120             toAXNodeObject(child)->alternativeText(textOrder);
   1121             if (textOrder.size() > 0) {
   1122                 builder.append(textOrder[0].text);
   1123                 continue;
   1124             }
   1125         }
   1126 
   1127         builder.append(child->textUnderElement());
   1128     }
   1129 
   1130     return builder.toString();
   1131 }
   1132 
   1133 String AXNodeObject::accessibilityDescription() const
   1134 {
   1135     // Static text should not have a description, it should only have a stringValue.
   1136     if (roleValue() == StaticTextRole)
   1137         return String();
   1138 
   1139     String ariaDescription = ariaAccessibilityDescription();
   1140     if (!ariaDescription.isEmpty())
   1141         return ariaDescription;
   1142 
   1143     if (isImage() || isInputImage() || isNativeImage() || isCanvas()) {
   1144         // Images should use alt as long as the attribute is present, even if empty.
   1145         // Otherwise, it should fallback to other methods, like the title attribute.
   1146         const AtomicString& alt = getAttribute(altAttr);
   1147         if (!alt.isNull())
   1148             return alt;
   1149     }
   1150 
   1151     // An element's descriptive text is comprised of title() (what's visible on the screen) and accessibilityDescription() (other descriptive text).
   1152     // Both are used to generate what a screen reader speaks.
   1153     // If this point is reached (i.e. there's no accessibilityDescription) and there's no title(), we should fallback to using the title attribute.
   1154     // The title attribute is normally used as help text (because it is a tooltip), but if there is nothing else available, this should be used (according to ARIA).
   1155     if (title().isEmpty())
   1156         return getAttribute(titleAttr);
   1157 
   1158     return String();
   1159 }
   1160 
   1161 String AXNodeObject::title() const
   1162 {
   1163     Node* node = this->node();
   1164     if (!node)
   1165         return String();
   1166 
   1167     bool isInputTag = node->hasTagName(inputTag);
   1168     if (isInputTag) {
   1169         HTMLInputElement* input = toHTMLInputElement(node);
   1170         if (input->isTextButton())
   1171             return input->valueWithDefault();
   1172     }
   1173 
   1174     if (isInputTag || AXObject::isARIAInput(ariaRoleAttribute()) || isControl()) {
   1175         HTMLLabelElement* label = labelForElement(toElement(node));
   1176         if (label && !exposesTitleUIElement())
   1177             return label->innerText();
   1178     }
   1179 
   1180     // If this node isn't rendered, there's no inner text we can extract from a select element.
   1181     if (!isAXRenderObject() && node->hasTagName(selectTag))
   1182         return String();
   1183 
   1184     switch (roleValue()) {
   1185     case PopUpButtonRole:
   1186         // Native popup buttons should not use their button children's text as a title. That value is retrieved through stringValue().
   1187         if (node->hasTagName(selectTag))
   1188             return String();
   1189     case ButtonRole:
   1190     case ToggleButtonRole:
   1191     case CheckBoxRole:
   1192     case ListBoxOptionRole:
   1193     case MenuButtonRole:
   1194     case MenuItemRole:
   1195     case RadioButtonRole:
   1196     case TabRole:
   1197         return textUnderElement();
   1198     // SVGRoots should not use the text under itself as a title. That could include the text of objects like <text>.
   1199     case SVGRootRole:
   1200         return String();
   1201     default:
   1202         break;
   1203     }
   1204 
   1205     if (isHeading() || isLink())
   1206         return textUnderElement();
   1207 
   1208     // If it's focusable but it's not content editable or a known control type, then it will appear to
   1209     // the user as a single atomic object, so we should use its text as the default title.
   1210     if (isGenericFocusableElement())
   1211         return textUnderElement();
   1212 
   1213     return String();
   1214 }
   1215 
   1216 String AXNodeObject::helpText() const
   1217 {
   1218     Node* node = this->node();
   1219     if (!node)
   1220         return String();
   1221 
   1222     const AtomicString& ariaHelp = getAttribute(aria_helpAttr);
   1223     if (!ariaHelp.isEmpty())
   1224         return ariaHelp;
   1225 
   1226     String describedBy = ariaDescribedByAttribute();
   1227     if (!describedBy.isEmpty())
   1228         return describedBy;
   1229 
   1230     String description = accessibilityDescription();
   1231     for (Node* curr = node; curr; curr = curr->parentNode()) {
   1232         if (curr->isHTMLElement()) {
   1233             const AtomicString& summary = toElement(curr)->getAttribute(summaryAttr);
   1234             if (!summary.isEmpty())
   1235                 return summary;
   1236 
   1237             // The title attribute should be used as help text unless it is already being used as descriptive text.
   1238             const AtomicString& title = toElement(curr)->getAttribute(titleAttr);
   1239             if (!title.isEmpty() && description != title)
   1240                 return title;
   1241         }
   1242 
   1243         // Only take help text from an ancestor element if its a group or an unknown role. If help was
   1244         // added to those kinds of elements, it is likely it was meant for a child element.
   1245         AXObject* axObj = axObjectCache()->getOrCreate(curr);
   1246         if (axObj) {
   1247             AccessibilityRole role = axObj->roleValue();
   1248             if (role != GroupRole && role != UnknownRole)
   1249                 break;
   1250         }
   1251     }
   1252 
   1253     return String();
   1254 }
   1255 
   1256 LayoutRect AXNodeObject::elementRect() const
   1257 {
   1258     // First check if it has a custom rect, for example if this element is tied to a canvas path.
   1259     if (!m_explicitElementRect.isEmpty())
   1260         return m_explicitElementRect;
   1261 
   1262     // AXNodeObjects have no mechanism yet to return a size or position.
   1263     // For now, let's return the position of the ancestor that does have a position,
   1264     // and make it the width of that parent, and about the height of a line of text, so that it's clear the object is a child of the parent.
   1265 
   1266     LayoutRect boundingBox;
   1267 
   1268     for (AXObject* positionProvider = parentObject(); positionProvider; positionProvider = positionProvider->parentObject()) {
   1269         if (positionProvider->isAXRenderObject()) {
   1270             LayoutRect parentRect = positionProvider->elementRect();
   1271             boundingBox.setSize(LayoutSize(parentRect.width(), LayoutUnit(std::min(10.0f, parentRect.height().toFloat()))));
   1272             boundingBox.setLocation(parentRect.location());
   1273             break;
   1274         }
   1275     }
   1276 
   1277     return boundingBox;
   1278 }
   1279 
   1280 AXObject* AXNodeObject::parentObject() const
   1281 {
   1282     if (!node())
   1283         return 0;
   1284 
   1285     Node* parentObj = node()->parentNode();
   1286     if (parentObj)
   1287         return axObjectCache()->getOrCreate(parentObj);
   1288 
   1289     return 0;
   1290 }
   1291 
   1292 AXObject* AXNodeObject::parentObjectIfExists() const
   1293 {
   1294     return parentObject();
   1295 }
   1296 
   1297 AXObject* AXNodeObject::firstChild() const
   1298 {
   1299     if (!node())
   1300         return 0;
   1301 
   1302     Node* firstChild = node()->firstChild();
   1303 
   1304     if (!firstChild)
   1305         return 0;
   1306 
   1307     return axObjectCache()->getOrCreate(firstChild);
   1308 }
   1309 
   1310 AXObject* AXNodeObject::nextSibling() const
   1311 {
   1312     if (!node())
   1313         return 0;
   1314 
   1315     Node* nextSibling = node()->nextSibling();
   1316     if (!nextSibling)
   1317         return 0;
   1318 
   1319     return axObjectCache()->getOrCreate(nextSibling);
   1320 }
   1321 
   1322 void AXNodeObject::addChildren()
   1323 {
   1324     // If the need to add more children in addition to existing children arises,
   1325     // childrenChanged should have been called, leaving the object with no children.
   1326     ASSERT(!m_haveChildren);
   1327 
   1328     if (!m_node)
   1329         return;
   1330 
   1331     m_haveChildren = true;
   1332 
   1333     // The only time we add children from the DOM tree to a node with a renderer is when it's a canvas.
   1334     if (renderer() && !m_node->hasTagName(canvasTag))
   1335         return;
   1336 
   1337     for (Node* child = m_node->firstChild(); child; child = child->nextSibling())
   1338         addChild(axObjectCache()->getOrCreate(child));
   1339 }
   1340 
   1341 void AXNodeObject::addChild(AXObject* child)
   1342 {
   1343     insertChild(child, m_children.size());
   1344 }
   1345 
   1346 void AXNodeObject::insertChild(AXObject* child, unsigned index)
   1347 {
   1348     if (!child)
   1349         return;
   1350 
   1351     // If the parent is asking for this child's children, then either it's the first time (and clearing is a no-op),
   1352     // or its visibility has changed. In the latter case, this child may have a stale child cached.
   1353     // This can prevent aria-hidden changes from working correctly. Hence, whenever a parent is getting children, ensure data is not stale.
   1354     child->clearChildren();
   1355 
   1356     if (child->accessibilityIsIgnored()) {
   1357         AccessibilityChildrenVector children = child->children();
   1358         size_t length = children.size();
   1359         for (size_t i = 0; i < length; ++i)
   1360             m_children.insert(index + i, children[i]);
   1361     } else {
   1362         ASSERT(child->parentObject() == this);
   1363         m_children.insert(index, child);
   1364     }
   1365 }
   1366 
   1367 bool AXNodeObject::canHaveChildren() const
   1368 {
   1369     // If this is an AXRenderObject, then it's okay if this object
   1370     // doesn't have a node - there are some renderers that don't have associated
   1371     // nodes, like scroll areas and css-generated text.
   1372     if (!node() && !isAXRenderObject())
   1373         return false;
   1374 
   1375     // Elements that should not have children
   1376     switch (roleValue()) {
   1377     case ImageRole:
   1378     case ButtonRole:
   1379     case PopUpButtonRole:
   1380     case CheckBoxRole:
   1381     case RadioButtonRole:
   1382     case TabRole:
   1383     case ToggleButtonRole:
   1384     case ListBoxOptionRole:
   1385     case ScrollBarRole:
   1386         return false;
   1387     case StaticTextRole:
   1388         if (!axObjectCache()->inlineTextBoxAccessibility())
   1389             return false;
   1390     default:
   1391         return true;
   1392     }
   1393 }
   1394 
   1395 Element* AXNodeObject::actionElement() const
   1396 {
   1397     Node* node = this->node();
   1398     if (!node)
   1399         return 0;
   1400 
   1401     if (node->hasTagName(inputTag)) {
   1402         HTMLInputElement* input = toHTMLInputElement(node);
   1403         if (!input->isDisabledFormControl() && (isCheckboxOrRadio() || input->isTextButton()))
   1404             return input;
   1405     } else if (node->hasTagName(buttonTag)) {
   1406         return toElement(node);
   1407     }
   1408 
   1409     if (isFileUploadButton())
   1410         return toElement(node);
   1411 
   1412     if (AXObject::isARIAInput(ariaRoleAttribute()))
   1413         return toElement(node);
   1414 
   1415     if (isImageButton())
   1416         return toElement(node);
   1417 
   1418     if (node->hasTagName(selectTag))
   1419         return toElement(node);
   1420 
   1421     switch (roleValue()) {
   1422     case ButtonRole:
   1423     case PopUpButtonRole:
   1424     case ToggleButtonRole:
   1425     case TabRole:
   1426     case MenuItemRole:
   1427     case ListItemRole:
   1428         return toElement(node);
   1429     default:
   1430         break;
   1431     }
   1432 
   1433     Element* elt = anchorElement();
   1434     if (!elt)
   1435         elt = mouseButtonListener();
   1436     return elt;
   1437 }
   1438 
   1439 Element* AXNodeObject::anchorElement() const
   1440 {
   1441     Node* node = this->node();
   1442     if (!node)
   1443         return 0;
   1444 
   1445     AXObjectCache* cache = axObjectCache();
   1446 
   1447     // search up the DOM tree for an anchor element
   1448     // NOTE: this assumes that any non-image with an anchor is an HTMLAnchorElement
   1449     for ( ; node; node = node->parentNode()) {
   1450         if (isHTMLAnchorElement(node) || (node->renderer() && cache->getOrCreate(node->renderer())->isAnchor()))
   1451             return toElement(node);
   1452     }
   1453 
   1454     return 0;
   1455 }
   1456 
   1457 Document* AXNodeObject::document() const
   1458 {
   1459     if (!node())
   1460         return 0;
   1461     return &node()->document();
   1462 }
   1463 
   1464 void AXNodeObject::setNode(Node* node)
   1465 {
   1466     m_node = node;
   1467 }
   1468 
   1469 AXObject* AXNodeObject::correspondingControlForLabelElement() const
   1470 {
   1471     HTMLLabelElement* labelElement = labelElementContainer();
   1472     if (!labelElement)
   1473         return 0;
   1474 
   1475     HTMLElement* correspondingControl = labelElement->control();
   1476     if (!correspondingControl)
   1477         return 0;
   1478 
   1479     // Make sure the corresponding control isn't a descendant of this label
   1480     // that's in the middle of being destroyed.
   1481     if (correspondingControl->renderer() && !correspondingControl->renderer()->parent())
   1482         return 0;
   1483 
   1484     return axObjectCache()->getOrCreate(correspondingControl);
   1485 }
   1486 
   1487 HTMLLabelElement* AXNodeObject::labelElementContainer() const
   1488 {
   1489     if (!node())
   1490         return 0;
   1491 
   1492     // the control element should not be considered part of the label
   1493     if (isControl())
   1494         return 0;
   1495 
   1496     // find if this has a parent that is a label
   1497     for (Node* parentNode = node(); parentNode; parentNode = parentNode->parentNode()) {
   1498         if (isHTMLLabelElement(parentNode))
   1499             return toHTMLLabelElement(parentNode);
   1500     }
   1501 
   1502     return 0;
   1503 }
   1504 
   1505 void AXNodeObject::setFocused(bool on)
   1506 {
   1507     if (!canSetFocusAttribute())
   1508         return;
   1509 
   1510     Document* document = this->document();
   1511     if (!on) {
   1512         document->setFocusedElement(0);
   1513     } else {
   1514         Node* node = this->node();
   1515         if (node && node->isElementNode()) {
   1516             // If this node is already the currently focused node, then calling focus() won't do anything.
   1517             // That is a problem when focus is removed from the webpage to chrome, and then returns.
   1518             // In these cases, we need to do what keyboard and mouse focus do, which is reset focus first.
   1519             if (document->focusedElement() == node)
   1520                 document->setFocusedElement(0);
   1521 
   1522             toElement(node)->focus();
   1523         } else {
   1524             document->setFocusedElement(0);
   1525         }
   1526     }
   1527 }
   1528 
   1529 void AXNodeObject::increment()
   1530 {
   1531     UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture);
   1532     alterSliderValue(true);
   1533 }
   1534 
   1535 void AXNodeObject::decrement()
   1536 {
   1537     UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture);
   1538     alterSliderValue(false);
   1539 }
   1540 
   1541 void AXNodeObject::childrenChanged()
   1542 {
   1543     // This method is meant as a quick way of marking a portion of the accessibility tree dirty.
   1544     if (!node() && !renderer())
   1545         return;
   1546 
   1547     axObjectCache()->postNotification(this, document(), AXObjectCache::AXChildrenChanged, true);
   1548 
   1549     // Go up the accessibility parent chain, but only if the element already exists. This method is
   1550     // called during render layouts, minimal work should be done.
   1551     // If AX elements are created now, they could interrogate the render tree while it's in a funky state.
   1552     // At the same time, process ARIA live region changes.
   1553     for (AXObject* parent = this; parent; parent = parent->parentObjectIfExists()) {
   1554         parent->setNeedsToUpdateChildren();
   1555 
   1556         // These notifications always need to be sent because screenreaders are reliant on them to perform.
   1557         // In other words, they need to be sent even when the screen reader has not accessed this live region since the last update.
   1558 
   1559         // If this element supports ARIA live regions, then notify the AT of changes.
   1560         if (parent->supportsARIALiveRegion())
   1561             axObjectCache()->postNotification(parent, parent->document(), AXObjectCache::AXLiveRegionChanged, true);
   1562 
   1563         // If this element is an ARIA text box or content editable, post a "value changed" notification on it
   1564         // so that it behaves just like a native input element or textarea.
   1565         if (isNonNativeTextControl())
   1566             axObjectCache()->postNotification(parent, parent->document(), AXObjectCache::AXValueChanged, true);
   1567     }
   1568 }
   1569 
   1570 void AXNodeObject::selectionChanged()
   1571 {
   1572     // When the selection changes, post the notification on the first ancestor that's an
   1573     // ARIA text box, or that's marked as contentEditable, otherwise post the notification
   1574     // on the web area.
   1575     if (isNonNativeTextControl() || isWebArea())
   1576         axObjectCache()->postNotification(this, document(), AXObjectCache::AXSelectedTextChanged, true);
   1577     else
   1578         AXObject::selectionChanged(); // Calls selectionChanged on parent.
   1579 }
   1580 
   1581 void AXNodeObject::textChanged()
   1582 {
   1583     // If this element supports ARIA live regions, or is part of a region with an ARIA editable role,
   1584     // then notify the AT of changes.
   1585     AXObjectCache* cache = axObjectCache();
   1586     for (Node* parentNode = node(); parentNode; parentNode = parentNode->parentNode()) {
   1587         AXObject* parent = cache->get(parentNode);
   1588         if (!parent)
   1589             continue;
   1590 
   1591         if (parent->supportsARIALiveRegion())
   1592             cache->postNotification(parentNode, AXObjectCache::AXLiveRegionChanged, true);
   1593 
   1594         // If this element is an ARIA text box or content editable, post a "value changed" notification on it
   1595         // so that it behaves just like a native input element or textarea.
   1596         if (parent->isNonNativeTextControl())
   1597             cache->postNotification(parentNode, AXObjectCache::AXValueChanged, true);
   1598     }
   1599 }
   1600 
   1601 void AXNodeObject::updateAccessibilityRole()
   1602 {
   1603     bool ignoredStatus = accessibilityIsIgnored();
   1604     m_role = determineAccessibilityRole();
   1605 
   1606     // The AX hierarchy only needs to be updated if the ignored status of an element has changed.
   1607     if (ignoredStatus != accessibilityIsIgnored())
   1608         childrenChanged();
   1609 }
   1610 
   1611 String AXNodeObject::alternativeTextForWebArea() const
   1612 {
   1613     // The WebArea description should follow this order:
   1614     //     aria-label on the <html>
   1615     //     title on the <html>
   1616     //     <title> inside the <head> (of it was set through JS)
   1617     //     name on the <html>
   1618     // For iframes:
   1619     //     aria-label on the <iframe>
   1620     //     title on the <iframe>
   1621     //     name on the <iframe>
   1622 
   1623     Document* document = this->document();
   1624     if (!document)
   1625         return String();
   1626 
   1627     // Check if the HTML element has an aria-label for the webpage.
   1628     if (Element* documentElement = document->documentElement()) {
   1629         const AtomicString& ariaLabel = documentElement->getAttribute(aria_labelAttr);
   1630         if (!ariaLabel.isEmpty())
   1631             return ariaLabel;
   1632     }
   1633 
   1634     Node* owner = document->ownerElement();
   1635     if (owner) {
   1636         if (owner->hasTagName(frameTag) || owner->hasTagName(iframeTag)) {
   1637             const AtomicString& title = toElement(owner)->getAttribute(titleAttr);
   1638             if (!title.isEmpty())
   1639                 return title;
   1640             return toElement(owner)->getNameAttribute();
   1641         }
   1642         if (owner->isHTMLElement())
   1643             return toHTMLElement(owner)->getNameAttribute();
   1644     }
   1645 
   1646     String documentTitle = document->title();
   1647     if (!documentTitle.isEmpty())
   1648         return documentTitle;
   1649 
   1650     owner = document->body();
   1651     if (owner && owner->isHTMLElement())
   1652         return toHTMLElement(owner)->getNameAttribute();
   1653 
   1654     return String();
   1655 }
   1656 
   1657 void AXNodeObject::alternativeText(Vector<AccessibilityText>& textOrder) const
   1658 {
   1659     if (isWebArea()) {
   1660         String webAreaText = alternativeTextForWebArea();
   1661         if (!webAreaText.isEmpty())
   1662             textOrder.append(AccessibilityText(webAreaText, AlternativeText));
   1663         return;
   1664     }
   1665 
   1666     ariaLabeledByText(textOrder);
   1667 
   1668     const AtomicString& ariaLabel = getAttribute(aria_labelAttr);
   1669     if (!ariaLabel.isEmpty())
   1670         textOrder.append(AccessibilityText(ariaLabel, AlternativeText));
   1671 
   1672     if (isImage() || isInputImage() || isNativeImage() || isCanvas()) {
   1673         // Images should use alt as long as the attribute is present, even if empty.
   1674         // Otherwise, it should fallback to other methods, like the title attribute.
   1675         const AtomicString& alt = getAttribute(altAttr);
   1676         if (!alt.isNull())
   1677             textOrder.append(AccessibilityText(alt, AlternativeText));
   1678     }
   1679 }
   1680 
   1681 void AXNodeObject::ariaLabeledByText(Vector<AccessibilityText>& textOrder) const
   1682 {
   1683     String ariaLabeledBy = ariaLabeledByAttribute();
   1684     if (!ariaLabeledBy.isEmpty()) {
   1685         Vector<Element*> elements;
   1686         ariaLabeledByElements(elements);
   1687 
   1688         unsigned length = elements.size();
   1689         for (unsigned k = 0; k < length; k++) {
   1690             RefPtr<AXObject> axElement = axObjectCache()->getOrCreate(elements[k]);
   1691             textOrder.append(AccessibilityText(ariaLabeledBy, AlternativeText, axElement));
   1692         }
   1693     }
   1694 }
   1695 
   1696 void AXNodeObject::changeValueByPercent(float percentChange)
   1697 {
   1698     float range = maxValueForRange() - minValueForRange();
   1699     float value = valueForRange();
   1700 
   1701     value += range * (percentChange / 100);
   1702     setValue(String::number(value));
   1703 
   1704     axObjectCache()->postNotification(node(), AXObjectCache::AXValueChanged, true);
   1705 }
   1706 
   1707 void AXNodeObject::helpText(Vector<AccessibilityText>& textOrder) const
   1708 {
   1709     const AtomicString& ariaHelp = getAttribute(aria_helpAttr);
   1710     if (!ariaHelp.isEmpty())
   1711         textOrder.append(AccessibilityText(ariaHelp, HelpText));
   1712 
   1713     String describedBy = ariaDescribedByAttribute();
   1714     if (!describedBy.isEmpty())
   1715         textOrder.append(AccessibilityText(describedBy, SummaryText));
   1716 
   1717     // Add help type text that is derived from ancestors.
   1718     for (Node* curr = node(); curr; curr = curr->parentNode()) {
   1719         const AtomicString& summary = getAttribute(summaryAttr);
   1720         if (!summary.isEmpty())
   1721             textOrder.append(AccessibilityText(summary, SummaryText));
   1722 
   1723         // The title attribute should be used as help text unless it is already being used as descriptive text.
   1724         const AtomicString& title = getAttribute(titleAttr);
   1725         if (!title.isEmpty())
   1726             textOrder.append(AccessibilityText(title, TitleTagText));
   1727 
   1728         // Only take help text from an ancestor element if its a group or an unknown role. If help was
   1729         // added to those kinds of elements, it is likely it was meant for a child element.
   1730         AXObject* axObj = axObjectCache()->getOrCreate(curr);
   1731         if (!axObj)
   1732             return;
   1733 
   1734         AccessibilityRole role = axObj->roleValue();
   1735         if (role != GroupRole && role != UnknownRole)
   1736             break;
   1737     }
   1738 }
   1739 
   1740 void AXNodeObject::titleElementText(Vector<AccessibilityText>& textOrder)
   1741 {
   1742     Node* node = this->node();
   1743     if (!node)
   1744         return;
   1745 
   1746     bool isInputTag = node->hasTagName(inputTag);
   1747     if (isInputTag || AXObject::isARIAInput(ariaRoleAttribute()) || isControl()) {
   1748         HTMLLabelElement* label = labelForElement(toElement(node));
   1749         if (label) {
   1750             AXObject* labelObject = axObjectCache()->getOrCreate(label);
   1751             textOrder.append(AccessibilityText(label->innerText(), LabelByElementText, labelObject));
   1752             return;
   1753         }
   1754     }
   1755 
   1756     AXObject* titleUIElement = this->titleUIElement();
   1757     if (titleUIElement)
   1758         textOrder.append(AccessibilityText(String(), LabelByElementText, titleUIElement));
   1759 }
   1760 
   1761 void AXNodeObject::visibleText(Vector<AccessibilityText>& textOrder) const
   1762 {
   1763     Node* node = this->node();
   1764     if (!node)
   1765         return;
   1766 
   1767     bool isInputTag = node->hasTagName(inputTag);
   1768     if (isInputTag) {
   1769         HTMLInputElement* input = toHTMLInputElement(node);
   1770         if (input->isTextButton()) {
   1771             textOrder.append(AccessibilityText(input->valueWithDefault(), VisibleText));
   1772             return;
   1773         }
   1774     }
   1775 
   1776     // If this node isn't rendered, there's no inner text we can extract from a select element.
   1777     if (!isAXRenderObject() && node->hasTagName(selectTag))
   1778         return;
   1779 
   1780     bool useTextUnderElement = false;
   1781 
   1782     switch (roleValue()) {
   1783     case PopUpButtonRole:
   1784         // Native popup buttons should not use their button children's text as a title. That value is retrieved through stringValue().
   1785         if (node->hasTagName(selectTag))
   1786             break;
   1787     case ButtonRole:
   1788     case ToggleButtonRole:
   1789     case CheckBoxRole:
   1790     case ListBoxOptionRole:
   1791     case MenuButtonRole:
   1792     case MenuItemRole:
   1793     case RadioButtonRole:
   1794     case TabRole:
   1795         useTextUnderElement = true;
   1796         break;
   1797     default:
   1798         break;
   1799     }
   1800 
   1801     // If it's focusable but it's not content editable or a known control type, then it will appear to
   1802     // the user as a single atomic object, so we should use its text as the default title.
   1803     if (isHeading() || isLink() || isGenericFocusableElement())
   1804         useTextUnderElement = true;
   1805 
   1806     if (useTextUnderElement) {
   1807         String text = textUnderElement();
   1808         if (!text.isEmpty())
   1809             textOrder.append(AccessibilityText(text, ChildrenText));
   1810     }
   1811 }
   1812 
   1813 } // namespace WebCore
   1814