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