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