Changeset 128353 in webkit


Ignore:
Timestamp:
Sep 12, 2012 1:13:47 PM (12 years ago)
Author:
commit-queue@webkit.org
Message:

Unreviewed, rolling out r128318 and r128332.
http://trac.webkit.org/changeset/128318
http://trac.webkit.org/changeset/128332
https://bugs.webkit.org/show_bug.cgi?id=96547

Caused accessibility test failures on snow leopard (Requested
by jamesr_ on #webkit).

Patch by Sheriff Bot <webkit.review.bot@gmail.com> on 2012-09-12

Source/WebCore:

  • accessibility/AccessibilityNodeObject.cpp:

(WebCore::AccessibilityNodeObject::determineAccessibilityRole):
(WebCore::AccessibilityNodeObject::accessibilityIsIgnored):
(WebCore::AccessibilityNodeObject::canSetFocusAttribute):

  • accessibility/AccessibilityNodeObject.h:

(AccessibilityNodeObject):
(WebCore::AccessibilityNodeObject::node):

  • accessibility/AccessibilityRenderObject.cpp:

(WebCore):
(WebCore::AccessibilityRenderObject::isWebArea):
(WebCore::AccessibilityRenderObject::isImageButton):
(WebCore::AccessibilityRenderObject::isAnchor):
(WebCore::AccessibilityRenderObject::isNativeTextControl):
(WebCore::AccessibilityRenderObject::isSearchField):
(WebCore::AccessibilityRenderObject::isNativeImage):
(WebCore::AccessibilityRenderObject::isImage):
(WebCore::AccessibilityRenderObject::isPasswordField):
(WebCore::AccessibilityRenderObject::isInputImage):
(WebCore::AccessibilityRenderObject::isProgressIndicator):
(WebCore::AccessibilityRenderObject::isSlider):
(WebCore::AccessibilityRenderObject::isMenuRelated):
(WebCore::AccessibilityRenderObject::isMenu):
(WebCore::AccessibilityRenderObject::isMenuBar):
(WebCore::AccessibilityRenderObject::isMenuButton):
(WebCore::AccessibilityRenderObject::isMenuItem):
(WebCore::AccessibilityRenderObject::isPressed):
(WebCore::AccessibilityRenderObject::isIndeterminate):
(WebCore::AccessibilityRenderObject::isNativeCheckboxOrRadio):
(WebCore::AccessibilityRenderObject::isChecked):
(WebCore::AccessibilityRenderObject::isHovered):
(WebCore::AccessibilityRenderObject::isMultiSelectable):
(WebCore::AccessibilityRenderObject::isReadOnly):
(WebCore::AccessibilityRenderObject::headingLevel):
(WebCore::AccessibilityRenderObject::isHeading):
(WebCore::AccessibilityRenderObject::isLink):
(WebCore::AccessibilityRenderObject::isControl):
(WebCore::AccessibilityRenderObject::isFieldset):
(WebCore::AccessibilityRenderObject::isGroup):
(WebCore::AccessibilityRenderObject::selectedRadioButton):
(WebCore::AccessibilityRenderObject::selectedTabItem):
(WebCore::AccessibilityRenderObject::actionElement):
(WebCore::AccessibilityRenderObject::mouseButtonListener):
(WebCore::AccessibilityRenderObject::alterSliderValue):
(WebCore::AccessibilityRenderObject::increment):
(WebCore::AccessibilityRenderObject::decrement):
(WebCore::siblingWithAriaRole):
(WebCore::AccessibilityRenderObject::menuElementForMenuButton):
(WebCore::AccessibilityRenderObject::menuForMenuButton):
(WebCore::AccessibilityRenderObject::menuItemElementForMenu):
(WebCore::AccessibilityRenderObject::menuButtonForMenu):
(WebCore::AccessibilityRenderObject::hierarchicalLevel):
(WebCore::AccessibilityRenderObject::checkboxOrRadioValue):
(WebCore::AccessibilityRenderObject::valueDescription):
(WebCore::AccessibilityRenderObject::stepValueForRange):
(WebCore::AccessibilityRenderObject::isARIARange):
(WebCore::AccessibilityRenderObject::valueForRange):
(WebCore::AccessibilityRenderObject::maxValueForRange):
(WebCore::AccessibilityRenderObject::minValueForRange):
(WebCore::accessibleNameForNode):
(WebCore::AccessibilityRenderObject::accessibilityDescriptionForElements):
(WebCore::AccessibilityRenderObject::elementsFromAttribute):
(WebCore::AccessibilityRenderObject::ariaLabeledByElements):
(WebCore::AccessibilityRenderObject::ariaLabeledByAttribute):
(WebCore::labelForElement):
(WebCore::AccessibilityRenderObject::title):
(WebCore::AccessibilityRenderObject::ariaAccessibilityDescription):
(WebCore::AccessibilityRenderObject::accessibilityDescription):
(WebCore::AccessibilityRenderObject::isDescendantOfBarrenParent):
(WebCore::AccessibilityRenderObject::text):
(WebCore::AccessibilityRenderObject::isRequired):
(WebCore::AccessibilityRenderObject::changeValueByStep):
(WebCore::AccessibilityRenderObject::changeValueByPercent):
(WebCore::AccessibilityRenderObject::isEnabled):
(WebCore::AccessibilityRenderObject::isGenericFocusableElement):
(WebCore::AccessibilityRenderObject::canHaveChildren):

  • accessibility/AccessibilityRenderObject.h:

(AccessibilityRenderObject):

LayoutTests:

  • accessibility/canvas-fallback-content-2-expected.txt: Removed.
  • accessibility/canvas-fallback-content-2.html: Removed.
Location:
trunk
Files:
2 deleted
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r128348 r128353  
     12012-09-12  Sheriff Bot  <webkit.review.bot@gmail.com>
     2
     3        Unreviewed, rolling out r128318 and r128332.
     4        http://trac.webkit.org/changeset/128318
     5        http://trac.webkit.org/changeset/128332
     6        https://bugs.webkit.org/show_bug.cgi?id=96547
     7
     8        Caused accessibility test failures on snow leopard (Requested
     9        by jamesr_ on #webkit).
     10
     11        * accessibility/canvas-fallback-content-2-expected.txt: Removed.
     12        * accessibility/canvas-fallback-content-2.html: Removed.
     13
    1142012-09-12  Alex Sakhartchouk  <alexst@chromium.org>
    215
  • trunk/Source/WebCore/ChangeLog

    r128350 r128353  
     12012-09-12  Sheriff Bot  <webkit.review.bot@gmail.com>
     2
     3        Unreviewed, rolling out r128318 and r128332.
     4        http://trac.webkit.org/changeset/128318
     5        http://trac.webkit.org/changeset/128332
     6        https://bugs.webkit.org/show_bug.cgi?id=96547
     7
     8        Caused accessibility test failures on snow leopard (Requested
     9        by jamesr_ on #webkit).
     10
     11        * accessibility/AccessibilityNodeObject.cpp:
     12        (WebCore::AccessibilityNodeObject::determineAccessibilityRole):
     13        (WebCore::AccessibilityNodeObject::accessibilityIsIgnored):
     14        (WebCore::AccessibilityNodeObject::canSetFocusAttribute):
     15        * accessibility/AccessibilityNodeObject.h:
     16        (AccessibilityNodeObject):
     17        (WebCore::AccessibilityNodeObject::node):
     18        * accessibility/AccessibilityRenderObject.cpp:
     19        (WebCore):
     20        (WebCore::AccessibilityRenderObject::isWebArea):
     21        (WebCore::AccessibilityRenderObject::isImageButton):
     22        (WebCore::AccessibilityRenderObject::isAnchor):
     23        (WebCore::AccessibilityRenderObject::isNativeTextControl):
     24        (WebCore::AccessibilityRenderObject::isSearchField):
     25        (WebCore::AccessibilityRenderObject::isNativeImage):
     26        (WebCore::AccessibilityRenderObject::isImage):
     27        (WebCore::AccessibilityRenderObject::isPasswordField):
     28        (WebCore::AccessibilityRenderObject::isInputImage):
     29        (WebCore::AccessibilityRenderObject::isProgressIndicator):
     30        (WebCore::AccessibilityRenderObject::isSlider):
     31        (WebCore::AccessibilityRenderObject::isMenuRelated):
     32        (WebCore::AccessibilityRenderObject::isMenu):
     33        (WebCore::AccessibilityRenderObject::isMenuBar):
     34        (WebCore::AccessibilityRenderObject::isMenuButton):
     35        (WebCore::AccessibilityRenderObject::isMenuItem):
     36        (WebCore::AccessibilityRenderObject::isPressed):
     37        (WebCore::AccessibilityRenderObject::isIndeterminate):
     38        (WebCore::AccessibilityRenderObject::isNativeCheckboxOrRadio):
     39        (WebCore::AccessibilityRenderObject::isChecked):
     40        (WebCore::AccessibilityRenderObject::isHovered):
     41        (WebCore::AccessibilityRenderObject::isMultiSelectable):
     42        (WebCore::AccessibilityRenderObject::isReadOnly):
     43        (WebCore::AccessibilityRenderObject::headingLevel):
     44        (WebCore::AccessibilityRenderObject::isHeading):
     45        (WebCore::AccessibilityRenderObject::isLink):
     46        (WebCore::AccessibilityRenderObject::isControl):
     47        (WebCore::AccessibilityRenderObject::isFieldset):
     48        (WebCore::AccessibilityRenderObject::isGroup):
     49        (WebCore::AccessibilityRenderObject::selectedRadioButton):
     50        (WebCore::AccessibilityRenderObject::selectedTabItem):
     51        (WebCore::AccessibilityRenderObject::actionElement):
     52        (WebCore::AccessibilityRenderObject::mouseButtonListener):
     53        (WebCore::AccessibilityRenderObject::alterSliderValue):
     54        (WebCore::AccessibilityRenderObject::increment):
     55        (WebCore::AccessibilityRenderObject::decrement):
     56        (WebCore::siblingWithAriaRole):
     57        (WebCore::AccessibilityRenderObject::menuElementForMenuButton):
     58        (WebCore::AccessibilityRenderObject::menuForMenuButton):
     59        (WebCore::AccessibilityRenderObject::menuItemElementForMenu):
     60        (WebCore::AccessibilityRenderObject::menuButtonForMenu):
     61        (WebCore::AccessibilityRenderObject::hierarchicalLevel):
     62        (WebCore::AccessibilityRenderObject::checkboxOrRadioValue):
     63        (WebCore::AccessibilityRenderObject::valueDescription):
     64        (WebCore::AccessibilityRenderObject::stepValueForRange):
     65        (WebCore::AccessibilityRenderObject::isARIARange):
     66        (WebCore::AccessibilityRenderObject::valueForRange):
     67        (WebCore::AccessibilityRenderObject::maxValueForRange):
     68        (WebCore::AccessibilityRenderObject::minValueForRange):
     69        (WebCore::accessibleNameForNode):
     70        (WebCore::AccessibilityRenderObject::accessibilityDescriptionForElements):
     71        (WebCore::AccessibilityRenderObject::elementsFromAttribute):
     72        (WebCore::AccessibilityRenderObject::ariaLabeledByElements):
     73        (WebCore::AccessibilityRenderObject::ariaLabeledByAttribute):
     74        (WebCore::labelForElement):
     75        (WebCore::AccessibilityRenderObject::title):
     76        (WebCore::AccessibilityRenderObject::ariaAccessibilityDescription):
     77        (WebCore::AccessibilityRenderObject::accessibilityDescription):
     78        (WebCore::AccessibilityRenderObject::isDescendantOfBarrenParent):
     79        (WebCore::AccessibilityRenderObject::text):
     80        (WebCore::AccessibilityRenderObject::isRequired):
     81        (WebCore::AccessibilityRenderObject::changeValueByStep):
     82        (WebCore::AccessibilityRenderObject::changeValueByPercent):
     83        (WebCore::AccessibilityRenderObject::isEnabled):
     84        (WebCore::AccessibilityRenderObject::isGenericFocusableElement):
     85        (WebCore::AccessibilityRenderObject::canHaveChildren):
     86        * accessibility/AccessibilityRenderObject.h:
     87        (AccessibilityRenderObject):
     88
    1892012-09-12  Christophe Dumez  <christophe.dumez@intel.com>
    290
  • trunk/Source/WebCore/accessibility/AccessibilityNodeObject.cpp

    r128332 r128353  
    260260        if (input->isTextButton())
    261261            return buttonRoleType();
    262         if (input->isRangeControl())
    263             return SliderRole;
    264262        return TextFieldRole;
    265263    }
    266264    if (node()->hasTagName(selectTag)) {
    267265        HTMLSelectElement* selectElement = toHTMLSelectElement(node());
    268         return selectElement->multiple() ? ListBoxRole : PopUpButtonRole;
    269     }
    270     if (node()->hasTagName(textareaTag))
    271         return TextAreaRole;
    272     if (headingLevel())
    273         return HeadingRole;
    274     if (node()->hasTagName(divTag))
    275         return DivRole;
    276     if (node()->hasTagName(pTag))
    277         return ParagraphRole;
    278     if (node()->hasTagName(labelTag))
    279         return LabelRole;
     266        return selectElement->multiple() ? ListRole : PopUpButtonRole;
     267    }
    280268    if (node()->isFocusable())
    281269        return GroupRole;
     
    314302}
    315303
    316 bool AccessibilityNodeObject::canHaveChildren() const
    317 {
    318     // If this is an AccessibilityRenderObject, then it's okay if this object
    319     // doesn't have a node - there are some renderers that don't have associated
    320     // nodes, like scroll areas and css-generated text.
    321     if (!node() && !isAccessibilityRenderObject())
    322         return false;
    323 
    324     // Elements that should not have children
    325     switch (roleValue()) {
    326     case ImageRole:
    327     case ButtonRole:
    328     case PopUpButtonRole:
    329     case CheckBoxRole:
    330     case RadioButtonRole:
    331     case TabRole:
    332     case ToggleButtonRole:
    333     case StaticTextRole:
    334     case ListBoxOptionRole:
    335     case ScrollBarRole:
    336         return false;
    337     default:
    338         return true;
    339     }
    340 }
    341 
    342304bool AccessibilityNodeObject::accessibilityIsIgnored() const
    343305{
    344     // If this element is within a parent that cannot have children, it should not be exposed.
    345     if (isDescendantOfBarrenParent())
    346         return true;
    347 
    348306    return m_role == UnknownRole;
    349307}
     
    366324}
    367325
    368 bool AccessibilityNodeObject::isWebArea() const
    369 {
    370     return roleValue() == WebAreaRole;
    371 }
    372 
    373 bool AccessibilityNodeObject::isImageButton() const
    374 {
    375     return isNativeImage() && roleValue() == ButtonRole;
    376 }
    377 
    378 bool AccessibilityNodeObject::isAnchor() const
    379 {
    380     return !isNativeImage() && isLink();
    381 }
    382 
    383 bool AccessibilityNodeObject::isNativeTextControl() const
     326bool AccessibilityNodeObject::canSetFocusAttribute() const
    384327{
    385328    Node* node = this->node();
    386     if (!node)
    387         return false;
    388 
    389     if (node->hasTagName(textareaTag))
    390         return true;
    391 
    392     if (node->hasTagName(inputTag)) {
    393         HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
    394         return input->isText() || input->isNumberField();
    395     }
    396 
    397     return false;
    398 }
    399 
    400 bool AccessibilityNodeObject::isSearchField() const
    401 {
    402     Node* node = this->node();
    403     if (!node)
    404         return false;
    405 
    406     HTMLInputElement* inputElement = node->toInputElement();
    407     if (!inputElement)
    408         return false;
    409 
    410     if (inputElement->isSearchField())
    411         return true;
    412 
    413     // Some websites don't label their search fields as such. However, they will
    414     // use the word "search" in either the form or input type. This won't catch every case,
    415     // but it will catch google.com for example.
    416 
    417     // Check the node name of the input type, sometimes it's "search".
    418     const AtomicString& nameAttribute = getAttribute(nameAttr);
    419     if (nameAttribute.contains("search", false))
    420         return true;
    421 
    422     // Check the form action and the name, which will sometimes be "search".
    423     HTMLFormElement* form = inputElement->form();
    424     if (form && (form->name().contains("search", false) || form->action().contains("search", false)))
    425         return true;
    426 
    427     return false;
    428 }
    429 
    430 bool AccessibilityNodeObject::isNativeImage() const
    431 {
    432     Node* node = this->node();
    433     if (!node)
    434         return false;
    435 
    436     if (node->hasTagName(imgTag))
    437         return true;
    438 
    439     if (node->hasTagName(appletTag) || node->hasTagName(embedTag) || node->hasTagName(objectTag))
    440         return true;
    441 
    442     if (node->hasTagName(inputTag)) {
    443         HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
    444         return input->isImageButton();
    445     }
    446 
    447     return false;
    448 }
    449 
    450 bool AccessibilityNodeObject::isImage() const
    451 {
    452     return roleValue() == ImageRole;
    453 }
    454 
    455 bool AccessibilityNodeObject::isPasswordField() const
    456 {
    457     Node* node = this->node();
    458     if (!node || !node->isHTMLElement())
    459         return false;
    460 
    461     if (ariaRoleAttribute() != UnknownRole)
    462         return false;
    463 
    464     HTMLInputElement* inputElement = node->toInputElement();
    465     if (!inputElement)
    466         return false;
    467 
    468     return inputElement->isPasswordField();
    469 }
    470 
    471 bool AccessibilityNodeObject::isInputImage() const
    472 {
    473     Node* node = this->node();
    474     if (!node)
    475         return false;
    476  
    477     if (roleValue() == ButtonRole && node->hasTagName(inputTag)) {
    478         HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
    479         return input->isImageButton();
    480     }
    481 
    482     return false;
    483 }
    484 
    485 bool AccessibilityNodeObject::isProgressIndicator() const
    486 {
    487     return roleValue() == ProgressIndicatorRole;
    488 }
    489 
    490 bool AccessibilityNodeObject::isSlider() const
    491 {
    492     return roleValue() == SliderRole;
    493 }
    494 
    495 bool AccessibilityNodeObject::isMenuRelated() const
    496 {
    497     switch (roleValue()) {
    498     case MenuRole:
    499     case MenuBarRole:
    500     case MenuButtonRole:
    501     case MenuItemRole:
    502         return true;
    503     default:
    504         return false;
    505     }
    506 }
    507 
    508 bool AccessibilityNodeObject::isMenu() const
    509 {
    510     return roleValue() == MenuRole;
    511 }
    512 
    513 bool AccessibilityNodeObject::isMenuBar() const
    514 {
    515     return roleValue() == MenuBarRole;
    516 }
    517 
    518 bool AccessibilityNodeObject::isMenuButton() const
    519 {
    520     return roleValue() == MenuButtonRole;
    521 }
    522 
    523 bool AccessibilityNodeObject::isMenuItem() const
    524 {
    525     return roleValue() == MenuItemRole;
    526 }
    527 
    528 bool AccessibilityNodeObject::isNativeCheckboxOrRadio() const
    529 {
    530     Node* node = this->node();
    531     if (!node)
    532         return false;
    533 
    534     HTMLInputElement* input = node->toInputElement();
    535     if (input)
    536         return input->isCheckbox() || input->isRadioButton();
    537 
    538     return false;
    539 }
    540 
    541 bool AccessibilityNodeObject::isEnabled() const
    542 {
    543     if (equalIgnoringCase(getAttribute(aria_disabledAttr), "true"))
    544         return false;
    545 
    546     Node* node = this->node();
    547     if (!node || !node->isElementNode())
    548         return true;
    549 
    550     return toElement(node)->isEnabledFormControl();
    551 }
    552 
    553 bool AccessibilityNodeObject::isIndeterminate() const
    554 {
    555     Node* node = this->node();
    556     if (!node)
    557         return false;
    558 
    559     HTMLInputElement* inputElement = node->toInputElement();
    560     if (!inputElement)
    561         return false;
    562 
    563     return inputElement->isIndeterminate();
    564 }
    565 
    566 bool AccessibilityNodeObject::isPressed() const
    567 {
    568     if (roleValue() != ButtonRole)
    569         return false;
    570 
    571     Node* node = this->node();
    572     if (!node)
    573         return false;
    574 
    575     // If this is an ARIA button, check the aria-pressed attribute rather than node()->active()
    576     if (ariaRoleAttribute() == ButtonRole) {
    577         if (equalIgnoringCase(getAttribute(aria_pressedAttr), "true"))
    578             return true;
    579         return false;
    580     }
    581 
    582     return node->active();
    583 }
    584 
    585 bool AccessibilityNodeObject::isChecked() const
    586 {
    587     Node* node = this->node();
    588     if (!node)
    589         return false;
    590 
    591     // First test for native checkedness semantics
    592     HTMLInputElement* inputElement = node->toInputElement();
    593     if (inputElement)
    594         return inputElement->shouldAppearChecked();
    595 
    596     // Else, if this is an ARIA checkbox or radio, respect the aria-checked attribute
    597     AccessibilityRole ariaRole = ariaRoleAttribute();
    598     if (ariaRole == RadioButtonRole || ariaRole == CheckBoxRole) {
    599         if (equalIgnoringCase(getAttribute(aria_checkedAttr), "true"))
    600             return true;
    601         return false;
    602     }
    603 
    604     // Otherwise it's not checked
    605     return false;
    606 }
    607 
    608 bool AccessibilityNodeObject::isHovered() const
    609 {
    610     Node* node = this->node();
    611     if (!node)
    612         return false;
    613 
    614     return node->hovered();
    615 }
    616 
    617 bool AccessibilityNodeObject::isMultiSelectable() const
    618 {
    619     const AtomicString& ariaMultiSelectable = getAttribute(aria_multiselectableAttr);
    620     if (equalIgnoringCase(ariaMultiSelectable, "true"))
    621         return true;
    622     if (equalIgnoringCase(ariaMultiSelectable, "false"))
    623         return false;
    624    
    625     return node() && node()->hasTagName(selectTag) && toHTMLSelectElement(node())->multiple();
    626 }
    627 
    628 bool AccessibilityNodeObject::isReadOnly() const
    629 {
    630     Node* node = this->node();
    631     if (!node)
    632         return true;
    633 
    634     if (node->hasTagName(textareaTag))
    635         return static_cast<HTMLTextAreaElement*>(node)->readOnly();
    636 
    637     if (node->hasTagName(inputTag))
    638         return static_cast<HTMLInputElement*>(node)->readOnly();
    639 
    640     return !node->rendererIsEditable();
    641 }
    642 
    643 bool AccessibilityNodeObject::isRequired() const
    644 {
    645     if (equalIgnoringCase(getAttribute(aria_requiredAttr), "true"))
    646         return true;
    647 
    648     Node* n = this->node();
    649     if (n && (n->isElementNode() && toElement(n)->isFormControlElement()))
    650         return static_cast<HTMLFormControlElement*>(n)->required();
    651 
    652     return false;
    653 }
    654 
    655 int AccessibilityNodeObject::headingLevel() const
    656 {
    657     // headings can be in block flow and non-block flow
    658     Node* node = this->node();
    659     if (!node)
    660         return false;
    661 
    662     if (ariaRoleAttribute() == HeadingRole)
    663         return getAttribute(aria_levelAttr).toInt();
    664 
    665     if (node->hasTagName(h1Tag))
    666         return 1;
    667 
    668     if (node->hasTagName(h2Tag))
    669         return 2;
    670 
    671     if (node->hasTagName(h3Tag))
    672         return 3;
    673 
    674     if (node->hasTagName(h4Tag))
    675         return 4;
    676 
    677     if (node->hasTagName(h5Tag))
    678         return 5;
    679 
    680     if (node->hasTagName(h6Tag))
    681         return 6;
    682 
    683     return 0;
    684 }
    685 
    686 String AccessibilityNodeObject::valueDescription() const
    687 {
    688     if (!isARIARange())
    689         return String();
    690 
    691     return getAttribute(aria_valuetextAttr).string();
    692 }
    693 
    694 bool AccessibilityNodeObject::isARIARange() const
    695 {
    696     switch (m_ariaRole) {
    697     case ProgressIndicatorRole:
    698     case SliderRole:
    699     case ScrollBarRole:
    700     case SpinButtonRole:
    701         return true;
    702     default:
    703         return false;
    704     }
    705 }
    706 
    707 float AccessibilityNodeObject::valueForRange() const
    708 {
    709     if (node() && node()->hasTagName(inputTag)) {
    710         HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
    711         if (input->isRangeControl())
    712             return input->valueAsNumber();
    713     }
    714 
    715     if (!isARIARange())
    716         return 0.0f;
    717 
    718     return getAttribute(aria_valuenowAttr).toFloat();
    719 }
    720 
    721 float AccessibilityNodeObject::maxValueForRange() const
    722 {
    723     if (node() && node()->hasTagName(inputTag)) {
    724         HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
    725         if (input->isRangeControl())
    726             return input->maximum();
    727     }
    728 
    729     if (!isARIARange())
    730         return 0.0f;
    731 
    732     return getAttribute(aria_valuemaxAttr).toFloat();
    733 }
    734 
    735 float AccessibilityNodeObject::minValueForRange() const
    736 {
    737     if (node() && node()->hasTagName(inputTag)) {
    738         HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
    739         if (input->isRangeControl())
    740             return input->minimum();
    741     }
    742 
    743     if (!isARIARange())
    744         return 0.0f;
    745 
    746     return getAttribute(aria_valueminAttr).toFloat();
    747 }
    748 
    749 float AccessibilityNodeObject::stepValueForRange() const
    750 {
    751     return getAttribute(stepAttr).toFloat();
    752 }
    753 
    754 bool AccessibilityNodeObject::isHeading() const
    755 {
    756     return roleValue() == HeadingRole;
    757 }
    758 
    759 bool AccessibilityNodeObject::isLink() const
    760 {
    761     return roleValue() == WebCoreLinkRole;
    762 }
    763 
    764 bool AccessibilityNodeObject::isControl() const
    765 {
    766     Node* node = this->node();
    767     if (!node)
    768         return false;
    769 
    770     return ((node->isElementNode() && toElement(node)->isFormControlElement())
    771         || AccessibilityObject::isARIAControl(ariaRoleAttribute()));
    772 }
    773 
    774 bool AccessibilityNodeObject::isFieldset() const
    775 {
    776     Node* node = this->node();
    777     if (!node)
    778         return false;
    779 
    780     return node->hasTagName(fieldsetTag);
    781 }
    782 
    783 bool AccessibilityNodeObject::isGroup() const
    784 {
    785     return roleValue() == GroupRole;
    786 }
    787 
    788 AccessibilityObject* AccessibilityNodeObject::selectedRadioButton()
    789 {
    790     if (!isRadioGroup())
    791         return 0;
    792 
    793     AccessibilityObject::AccessibilityChildrenVector children = this->children();
    794 
    795     // Find the child radio button that is selected (ie. the intValue == 1).
    796     size_t size = children.size();
    797     for (size_t i = 0; i < size; ++i) {
    798         AccessibilityObject* object = children[i].get();
    799         if (object->roleValue() == RadioButtonRole && object->checkboxOrRadioValue() == ButtonStateOn)
    800             return object;
    801     }
    802     return 0;
    803 }
    804 
    805 AccessibilityObject* AccessibilityNodeObject::selectedTabItem()
    806 {
    807     if (!isTabList())
    808         return 0;
    809 
    810     // Find the child tab item that is selected (ie. the intValue == 1).
    811     AccessibilityObject::AccessibilityChildrenVector tabs;
    812     tabChildren(tabs);
    813 
    814     AccessibilityObject::AccessibilityChildrenVector children = this->children();
    815     size_t size = tabs.size();
    816     for (size_t i = 0; i < size; ++i) {
    817         AccessibilityObject* object = children[i].get();
    818         if (object->isTabItem() && object->isChecked())
    819             return object;
    820     }
    821     return 0;
    822 }
    823 
    824 AccessibilityButtonState AccessibilityNodeObject::checkboxOrRadioValue() const
    825 {
    826     if (isNativeCheckboxOrRadio())
    827         return isChecked() ? ButtonStateOn : ButtonStateOff;
    828 
    829     return AccessibilityObject::checkboxOrRadioValue();
    830 }
    831 
    832 Element* AccessibilityNodeObject::anchorElement() const
    833 {
    834     Node* node = this->node();
    835     if (!node)
    836         return 0;
    837 
    838     AXObjectCache* cache = axObjectCache();
    839 
    840     // search up the DOM tree for an anchor element
    841     // NOTE: this assumes that any non-image with an anchor is an HTMLAnchorElement
    842     for ( ; node; node = node->parentNode()) {
    843         if (node->hasTagName(aTag) || (node->renderer() && cache->getOrCreate(node->renderer())->isAnchor()))
    844             return toElement(node);
    845     }
    846 
    847     return 0;
    848 }
    849 
    850 Element* AccessibilityNodeObject::actionElement() const
    851 {
    852     Node* node = this->node();
    853     if (!node)
    854         return 0;
    855 
    856     if (node->hasTagName(inputTag)) {
    857         HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
    858         if (!input->disabled() && (isCheckboxOrRadio() || input->isTextButton()))
    859             return input;
    860     } else if (node->hasTagName(buttonTag))
    861         return toElement(node);
    862 
    863     if (isFileUploadButton())
    864         return toElement(node);
    865            
    866     if (AccessibilityObject::isARIAInput(ariaRoleAttribute()))
    867         return toElement(node);
    868 
    869     if (isImageButton())
    870         return toElement(node);
    871    
    872     if (node->hasTagName(selectTag))
    873         return toElement(node);
    874 
    875     switch (roleValue()) {
    876     case ButtonRole:
    877     case PopUpButtonRole:
    878     case TabRole:
    879     case MenuItemRole:
    880     case ListItemRole:
    881         return toElement(node);
    882     default:
    883         break;
    884     }
    885    
    886     Element* elt = anchorElement();
    887     if (!elt)
    888         elt = mouseButtonListener();
    889     return elt;
    890 }
    891 
    892 Element* AccessibilityNodeObject::mouseButtonListener() const
    893 {
    894     Node* node = this->node();
    895     if (!node)
    896         return 0;
    897 
    898     // check if our parent is a mouse button listener
    899     while (node && !node->isElementNode())
    900         node = node->parentNode();
    901 
    902     if (!node)
    903         return 0;
    904 
    905     // FIXME: Do the continuation search like anchorElement does
    906     for (Element* element = toElement(node); element; element = element->parentElement()) {
    907         if (element->getAttributeEventListener(eventNames().clickEvent) || element->getAttributeEventListener(eventNames().mousedownEvent) || element->getAttributeEventListener(eventNames().mouseupEvent))
    908             return element;
    909     }
    910 
    911     return 0;
    912 }
    913 
    914 bool AccessibilityNodeObject::isDescendantOfBarrenParent() const
    915 {
    916     for (AccessibilityObject* object = parentObject(); object; object = object->parentObject()) {
    917         if (!object->canHaveChildren())
    918             return true;
    919     }
    920 
    921     return false;
    922 }
    923 
    924 void AccessibilityNodeObject::alterSliderValue(bool increase)
    925 {
    926     if (roleValue() != SliderRole)
    927         return;
    928 
    929     if (!getAttribute(stepAttr).isEmpty())
    930         changeValueByStep(increase);
    931     else
    932         changeValueByPercent(increase ? 5 : -5);
    933 }
    934    
    935 void AccessibilityNodeObject::increment()
    936 {
    937     alterSliderValue(true);
    938 }
    939 
    940 void AccessibilityNodeObject::decrement()
    941 {
    942     alterSliderValue(false);
    943 }
    944 
    945 void AccessibilityNodeObject::changeValueByStep(bool increase)
    946 {
    947     float step = stepValueForRange();
    948     float value = valueForRange();
    949 
    950     value += increase ? step : -step;
    951 
    952     setValue(String::number(value));
    953 
    954     axObjectCache()->postNotification(node(), AXObjectCache::AXValueChanged, true);
    955 }
    956 
    957 void AccessibilityNodeObject::changeValueByPercent(float percentChange)
    958 {
    959     float range = maxValueForRange() - minValueForRange();
    960     float value = valueForRange();
    961 
    962     value += range * (percentChange / 100);
    963     setValue(String::number(value));
    964 
    965     axObjectCache()->postNotification(node(), AXObjectCache::AXValueChanged, true);
    966 }
    967 
    968 bool AccessibilityNodeObject::isGenericFocusableElement() const
    969 {
    970     if (!canSetFocusAttribute())
    971         return false;
    972 
    973      // If it's a control, it's not generic.
    974      if (isControl())
    975         return false;
    976 
    977     // If it has an aria role, it's not generic.
    978     if (m_ariaRole != UnknownRole)
    979         return false;
    980 
    981     // If the content editable attribute is set on this element, that's the reason
    982     // it's focusable, and existing logic should handle this case already - so it's not a
    983     // generic focusable element.
    984 
    985     if (hasContentEditableAttributeSet())
    986         return false;
    987 
    988     // The web area and body element are both focusable, but existing logic handles these
    989     // cases already, so we don't need to include them here.
    990     if (roleValue() == WebAreaRole)
    991         return false;
    992     if (node() && node()->hasTagName(bodyTag))
    993         return false;
    994 
    995     return true;
    996 }
    997 
    998 HTMLLabelElement* AccessibilityNodeObject::labelForElement(Element* element) const
    999 {
    1000     RefPtr<NodeList> list = element->document()->getElementsByTagName("label");
    1001     unsigned len = list->length();
    1002     for (unsigned i = 0; i < len; i++) {
    1003         if (list->item(i)->hasTagName(labelTag)) {
    1004             HTMLLabelElement* label = static_cast<HTMLLabelElement*>(list->item(i));
    1005             if (label->control() == element)
    1006                 return label;
    1007         }
    1008     }
    1009 
    1010     return 0;
    1011 }
    1012 
    1013 String AccessibilityNodeObject::ariaAccessibilityDescription() const
    1014 {
    1015     String ariaLabeledBy = ariaLabeledByAttribute();
    1016     if (!ariaLabeledBy.isEmpty())
    1017         return ariaLabeledBy;
    1018 
    1019     const AtomicString& ariaLabel = getAttribute(aria_labelAttr);
    1020     if (!ariaLabel.isEmpty())
    1021         return ariaLabel;
    1022 
    1023     return String();
    1024 }
    1025 
    1026 static Element* siblingWithAriaRole(String role, Node* node)
    1027 {
    1028     for (Node* sibling = node->parentNode()->firstChild(); sibling; sibling = sibling->nextSibling()) {
    1029         if (sibling->isElementNode()) {
    1030             const AtomicString& siblingAriaRole = toElement(sibling)->getAttribute(roleAttr);
    1031             if (equalIgnoringCase(siblingAriaRole, role))
    1032                 return toElement(sibling);
    1033         }
    1034     }
    1035    
    1036     return 0;
    1037 }
    1038 
    1039 Element* AccessibilityNodeObject::menuElementForMenuButton() const
    1040 {
    1041     if (ariaRoleAttribute() != MenuButtonRole)
    1042         return 0;
    1043 
    1044     return siblingWithAriaRole("menu", node());
    1045 }
    1046 
    1047 AccessibilityObject* AccessibilityNodeObject::menuForMenuButton() const
    1048 {
    1049     return axObjectCache()->getOrCreate(menuElementForMenuButton());
    1050 }
    1051 
    1052 Element* AccessibilityNodeObject::menuItemElementForMenu() const
    1053 {
    1054     if (ariaRoleAttribute() != MenuRole)
    1055         return 0;
    1056    
    1057     return siblingWithAriaRole("menuitem", node());   
    1058 }
    1059 
    1060 AccessibilityObject* AccessibilityNodeObject::menuButtonForMenu() const
    1061 {
    1062     Element* menuItem = menuItemElementForMenu();
    1063 
    1064     if (menuItem) {
    1065         // ARIA just has generic menu items. AppKit needs to know if this is a top level items like MenuBarButton or MenuBarItem
    1066         AccessibilityObject* menuItemAX = axObjectCache()->getOrCreate(menuItem);
    1067         if (menuItemAX->isMenuButton())
    1068             return menuItemAX;
    1069     }
    1070     return 0;
    1071 }
    1072 
    1073 String AccessibilityNodeObject::accessibilityDescription() const
    1074 {
    1075     // Static text should not have a description, it should only have a stringValue.
    1076     if (roleValue() == StaticTextRole)
    1077         return String();
    1078 
    1079     String ariaDescription = ariaAccessibilityDescription();
    1080     if (!ariaDescription.isEmpty())
    1081         return ariaDescription;
    1082 
    1083     if (isImage() || isInputImage() || isNativeImage() || isCanvas()) {
    1084         // Images should use alt as long as the attribute is present, even if empty.                   
    1085         // Otherwise, it should fallback to other methods, like the title attribute.                   
    1086         const AtomicString& alt = getAttribute(altAttr);
    1087         if (!alt.isNull())
    1088             return alt;
    1089     }
    1090 
    1091 #if ENABLE(MATHML)
    1092     Node* node = this->node();
    1093     if (node && node->isElementNode() && toElement(node)->isMathMLElement())
    1094         return getAttribute(MathMLNames::alttextAttr);
    1095 #endif
    1096 
    1097     // An element's descriptive text is comprised of title() (what's visible on the screen) and accessibilityDescription() (other descriptive text).
    1098     // Both are used to generate what a screen reader speaks.                                                           
    1099     // If this point is reached (i.e. there's no accessibilityDescription) and there's no title(), we should fallback to using the title attribute.
    1100     // 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).
    1101     if (title().isEmpty())
    1102         return getAttribute(titleAttr);
    1103 
    1104     return String();
    1105 }
    1106 
    1107 String AccessibilityNodeObject::helpText() const
    1108 {
    1109     Node* node = this->node();
    1110     if (!node)
    1111         return String();
    1112    
    1113     const AtomicString& ariaHelp = getAttribute(aria_helpAttr);
    1114     if (!ariaHelp.isEmpty())
    1115         return ariaHelp;
    1116    
    1117     String describedBy = ariaDescribedByAttribute();
    1118     if (!describedBy.isEmpty())
    1119         return describedBy;
    1120    
    1121     String description = accessibilityDescription();
    1122     for (Node* curr = node; curr; curr = curr->parentNode()) {
    1123         if (curr->isHTMLElement()) {
    1124             const AtomicString& summary = toElement(curr)->getAttribute(summaryAttr);
    1125             if (!summary.isEmpty())
    1126                 return summary;
    1127            
    1128             // The title attribute should be used as help text unless it is already being used as descriptive text.
    1129             const AtomicString& title = toElement(curr)->getAttribute(titleAttr);
    1130             if (!title.isEmpty() && description != title)
    1131                 return title;
    1132         }
    1133        
    1134         // Only take help text from an ancestor element if its a group or an unknown role. If help was
    1135         // added to those kinds of elements, it is likely it was meant for a child element.
    1136         AccessibilityObject* axObj = axObjectCache()->getOrCreate(curr);
    1137         if (axObj) {
    1138             AccessibilityRole role = axObj->roleValue();
    1139             if (role != GroupRole && role != UnknownRole)
    1140                 break;
    1141         }
    1142     }
    1143    
    1144     return String();
    1145 }
    1146    
    1147 unsigned AccessibilityNodeObject::hierarchicalLevel() const
    1148 {
    1149     Node* node = this->node();
    1150     if (!node || !node->isElementNode())
    1151         return 0;
    1152     Element* element = toElement(node);
    1153     String ariaLevel = element->getAttribute(aria_levelAttr);
    1154     if (!ariaLevel.isEmpty())
    1155         return ariaLevel.toInt();
    1156    
    1157     // Only tree item will calculate its level through the DOM currently.
    1158     if (roleValue() != TreeItemRole)
    1159         return 0;
    1160    
    1161     // Hierarchy leveling starts at 0.
    1162     // We measure tree hierarchy by the number of groups that the item is within.
    1163     unsigned level = 0;
    1164     for (AccessibilityObject* parent = parentObject(); parent; parent = parent->parentObject()) {
    1165         AccessibilityRole parentRole = parent->roleValue();
    1166         if (parentRole == GroupRole)
    1167             level++;
    1168         else if (parentRole == TreeRole)
    1169             break;
    1170     }
    1171    
    1172     return level;
    1173 }
    1174 
    1175 String AccessibilityNodeObject::textUnderElement() const
    1176 {
    1177     Node* node = this->node();
    1178     if (!node)
    1179         return String();
    1180 
    1181     // Note: TextIterator doesn't return any text for nodes that don't have renderers.
    1182     // If this could be fixed, it'd be more accurate use TextIterator here.
    1183     if (node->isElementNode())
    1184         return toElement(node)->innerText();
    1185 
    1186     return String();
    1187 }
    1188 
    1189 String AccessibilityNodeObject::title() const
    1190 {
    1191     Node* node = this->node();
    1192     if (!node)
    1193         return String();
    1194 
    1195     bool isInputTag = node->hasTagName(inputTag);
    1196     if (isInputTag) {
    1197         HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
    1198         if (input->isTextButton())
    1199             return input->valueWithDefault();
    1200     }
    1201 
    1202     if (isInputTag || AccessibilityObject::isARIAInput(ariaRoleAttribute()) || isControl()) {
    1203         HTMLLabelElement* label = labelForElement(toElement(node));
    1204         if (label && !exposesTitleUIElement())
    1205             return label->innerText();
    1206     }
    1207 
    1208     // If this node isn't rendered, there's no inner text we can extract from a select element.
    1209     if (!isAccessibilityRenderObject() && node->hasTagName(selectTag))
    1210         return String();
    1211 
    1212     switch (roleValue()) {
    1213     case PopUpButtonRole:
    1214     case ButtonRole:
    1215     case CheckBoxRole:
    1216     case ListBoxOptionRole:
    1217     case MenuButtonRole:
    1218     case MenuItemRole:
    1219     case RadioButtonRole:
    1220     case TabRole:
    1221         return textUnderElement();
    1222     default:
    1223         break;
    1224     }
    1225 
    1226     if (isHeading() || isLink())
    1227         return textUnderElement();
    1228 
    1229     // If it's focusable but it's not content editable or a known control type, then it will appear to                 
    1230     // the user as a single atomic object, so we should use its text as the default title.                             
    1231     if (isGenericFocusableElement())
    1232         return textUnderElement();
    1233 
    1234     return String();
    1235 }
    1236 
    1237 String AccessibilityNodeObject::text() const
    1238 {
    1239     // If this is a user defined static text, use the accessible name computation.                                     
    1240     if (ariaRoleAttribute() == StaticTextRole)
    1241         return ariaAccessibilityDescription();
    1242 
    1243     if (!isTextControl())
    1244         return String();
    1245 
    1246     Node* node = this->node();
    1247     if (!node)
    1248         return String();
    1249 
    1250     if (isNativeTextControl()) {
    1251         if (node->hasTagName(textareaTag))
    1252             return static_cast<HTMLTextAreaElement*>(node)->value();
    1253         if (node->hasTagName(inputTag))
    1254             return node->toInputElement()->value();
    1255     }
    1256 
    1257     if (!node->isElementNode())
    1258         return String();
    1259 
    1260     return toElement(node)->innerText();
    1261 }
    1262 
    1263 String AccessibilityNodeObject::stringValue() const
    1264 {
    1265     Node* node = this->node();
    1266     if (!node)
    1267         return String();
    1268 
    1269     if (ariaRoleAttribute() == StaticTextRole) {
    1270         String staticText = text();
    1271         if (!staticText.length())
    1272             staticText = textUnderElement();
    1273         return staticText;
    1274     }
    1275 
    1276     if (node->isTextNode())
    1277         return textUnderElement();
    1278 
    1279     if (node->hasTagName(selectTag)) {
    1280         HTMLSelectElement* selectElement = toHTMLSelectElement(node);
    1281         int selectedIndex = selectElement->selectedIndex();
    1282         const Vector<HTMLElement*> listItems = selectElement->listItems();
    1283         if (selectedIndex >= 0 && static_cast<size_t>(selectedIndex) < listItems.size()) {
    1284             const AtomicString& overriddenDescription = listItems[selectedIndex]->fastGetAttribute(aria_labelAttr);
    1285             if (!overriddenDescription.isNull())
    1286                 return overriddenDescription;
    1287         }
    1288         if (!selectElement->multiple())
    1289             return selectElement->value();
    1290         return String();
    1291     }
    1292 
    1293     if (isTextControl())
    1294         return text();
    1295 
    1296     // FIXME: We might need to implement a value here for more types
    1297     // FIXME: It would be better not to advertise a value at all for the types for which we don't implement one;
    1298     // this would require subclassing or making accessibilityAttributeNames do something other than return a
    1299     // single static array.
    1300     return String();
    1301 }
    1302 
    1303 // This function implements the ARIA accessible name as described by the Mozilla                                       
    1304 // ARIA Implementer's Guide.                                                                                           
    1305 static String accessibleNameForNode(Node* node)
    1306 {
    1307     if (node->isTextNode())
    1308         return toText(node)->data();
    1309 
    1310     if (node->hasTagName(inputTag))
    1311         return static_cast<HTMLInputElement*>(node)->value();
    1312 
    1313     if (node->isHTMLElement()) {
    1314         const AtomicString& alt = toHTMLElement(node)->getAttribute(altAttr);
    1315         if (!alt.isEmpty())
    1316             return alt;
    1317     }
    1318 
    1319     return String();
    1320 }
    1321 
    1322 String AccessibilityNodeObject::accessibilityDescriptionForElements(Vector<Element*> &elements) const
    1323 {
    1324     StringBuilder builder;
    1325     unsigned size = elements.size();
    1326     for (unsigned i = 0; i < size; ++i) {
    1327         Element* idElement = elements[i];
    1328 
    1329         builder.append(accessibleNameForNode(idElement));
    1330         for (Node* n = idElement->firstChild(); n; n = n->traverseNextNode(idElement))
    1331             builder.append(accessibleNameForNode(n));
    1332 
    1333         if (i != size - 1)
    1334             builder.append(' ');
    1335     }
    1336     return builder.toString();
    1337 }
    1338 
    1339 void AccessibilityNodeObject::elementsFromAttribute(Vector<Element*>& elements, const QualifiedName& attribute) const
    1340 {
    1341     Node* node = this->node();
    1342     if (!node || !node->isElementNode())
    1343         return;
    1344 
    1345     TreeScope* scope = node->treeScope();
    1346     if (!scope)
    1347         return;
    1348 
    1349     String idList = getAttribute(attribute).string();
    1350     if (idList.isEmpty())
    1351         return;
    1352 
    1353     idList.replace('\n', ' ');
    1354     Vector<String> idVector;
    1355     idList.split(' ', idVector);
    1356 
    1357     unsigned size = idVector.size();
    1358     for (unsigned i = 0; i < size; ++i) {
    1359         AtomicString idName(idVector[i]);
    1360         Element* idElement = scope->getElementById(idName);
    1361         if (idElement)
    1362             elements.append(idElement);
    1363     }
    1364 }
    1365 
    1366 
    1367 void AccessibilityNodeObject::ariaLabeledByElements(Vector<Element*>& elements) const
    1368 {
    1369     elementsFromAttribute(elements, aria_labeledbyAttr);
    1370     if (!elements.size())
    1371         elementsFromAttribute(elements, aria_labelledbyAttr);
    1372 }
    1373 
    1374 
    1375 String AccessibilityNodeObject::ariaLabeledByAttribute() const
    1376 {
    1377     Vector<Element*> elements;
    1378     ariaLabeledByElements(elements);
    1379 
    1380     return accessibilityDescriptionForElements(elements);
    1381 }
    1382 
    1383 bool AccessibilityNodeObject::canSetFocusAttribute() const
    1384 {
    1385     Node* node = this->node();
    1386     if (!node)
    1387         return false;
    1388329
    1389330    if (isWebArea())
     
    1396337        return false;
    1397338
    1398     if (node->isElementNode() && !toElement(node)->isEnabledFormControl())
     339    if (node->isElementNode() && !static_cast<Element*>(node)->isEnabledFormControl())
    1399340        return false;
    1400341
  • trunk/Source/WebCore/accessibility/AccessibilityNodeObject.h

    r128318 r128353  
    6969    virtual bool canvasHasFallbackContent() const;
    7070
    71     virtual bool isAnchor() const;
    72     virtual bool isControl() const;
    73     virtual bool isFieldset() const;
    74     virtual bool isGroup() const;
    75     virtual bool isHeading() const;
    76     virtual bool isHovered() const;
    77     virtual bool isImage() const;
    78     virtual bool isImageButton() const;
    79     virtual bool isInputImage() const;
    80     virtual bool isLink() const;
    81     virtual bool isMenu() const;
    82     virtual bool isMenuBar() const;
    83     virtual bool isMenuButton() const;
    84     virtual bool isMenuItem() const;
    85     virtual bool isMenuRelated() const;
    86     virtual bool isMultiSelectable() const;
    87     virtual bool isNativeCheckboxOrRadio() const;
    88     virtual bool isNativeImage() const;
    89     virtual bool isNativeTextControl() const;
    90     virtual bool isPasswordField() const;
    91     virtual bool isProgressIndicator() const;
    92     virtual bool isSearchField() const;
    93     virtual bool isSlider() const;
    94     virtual bool isWebArea() const;
    95 
    96     virtual bool isChecked() const;
    97     virtual bool isEnabled() const;
    98     virtual bool isIndeterminate() const;
    99     virtual bool isPressed() const;
    100     virtual bool isReadOnly() const;
    101     virtual bool isRequired() const;
    102 
    103     void setNode(Node*);
    104     virtual Node* node() const { return m_node; }
    105     virtual Document* document() const;
    106 
    10771    virtual bool canSetFocusAttribute() const;
    108     virtual int headingLevel() const;
    109 
    110     virtual String valueDescription() const;
    111     virtual float valueForRange() const;
    112     virtual float maxValueForRange() const;
    113     virtual float minValueForRange() const;
    114     virtual float stepValueForRange() const;
    115 
    116     virtual AccessibilityObject* selectedRadioButton();
    117     virtual AccessibilityObject* selectedTabItem();
    118     virtual AccessibilityButtonState checkboxOrRadioValue() const;
    119 
    120     virtual unsigned hierarchicalLevel() const;
    121     virtual String textUnderElement() const;
    122     virtual String accessibilityDescription() const;
    123     virtual String helpText() const;
    124     virtual String title() const;
    125     virtual String text() const;
    126     virtual String stringValue() const;
    127     virtual String ariaLabeledByAttribute() const;
    128 
    129     virtual Element* actionElement() const;
    130     Element* mouseButtonListener() const;
    131     virtual Element* anchorElement() const;
    132     AccessibilityObject* menuForMenuButton() const;
    133    
    134     virtual void changeValueByPercent(float percentChange);
    135  
     72   
    13673    virtual AccessibilityObject* firstChild() const;
    13774    virtual AccessibilityObject* lastChild() const;
     
    14178    virtual AccessibilityObject* parentObjectIfExists() const;
    14279
     80    void setNode(Node*);
     81    virtual Node* node() const { return m_node; }
     82    virtual Document* document() const;
     83
    14384    virtual void detach();
    14485    virtual void childrenChanged();
    14586    virtual void updateAccessibilityRole();
    146 
    147     virtual void increment();
    148     virtual void decrement();
    14987
    15088    virtual LayoutRect elementRect() const;
     
    15997    virtual AccessibilityRole determineAccessibilityRole();
    16098    virtual void addChildren();
    161     virtual bool canHaveChildren() const;
    16299    virtual bool accessibilityIsIgnored() const;
    163100    AccessibilityRole ariaRoleAttribute() const;
     
    165102    AccessibilityRole remapAriaRoleDueToParent(AccessibilityRole) const;
    166103    bool hasContentEditableAttributeSet() const;
    167     bool isDescendantOfBarrenParent() const;
    168     void alterSliderValue(bool increase);
    169     void changeValueByStep(bool increase);
    170     bool isARIARange() const;
    171     bool isGenericFocusableElement() const;
    172     HTMLLabelElement* labelForElement(Element*) const;
    173     String ariaAccessibilityDescription() const;
    174     void ariaLabeledByElements(Vector<Element*>& elements) const;
    175     String accessibilityDescriptionForElements(Vector<Element*> &elements) const;
    176     void elementsFromAttribute(Vector<Element*>& elements, const QualifiedName&) const;
    177 
    178     Element* menuElementForMenuButton() const;
    179     Element* menuItemElementForMenu() const;
    180     AccessibilityObject* menuButtonForMenu() const;
    181104
    182105private:
  • trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp

    r128318 r128353  
    478478    return 0;
    479479}
    480    
     480
     481bool AccessibilityRenderObject::isWebArea() const
     482{
     483    return roleValue() == WebAreaRole;
     484}
     485
     486bool AccessibilityRenderObject::isImageButton() const
     487{
     488    return isNativeImage() && roleValue() == ButtonRole;
     489}
     490
     491bool AccessibilityRenderObject::isAnchor() const
     492{
     493    return !isNativeImage() && isLink();
     494}
     495
     496bool AccessibilityRenderObject::isNativeTextControl() const
     497{
     498    return m_renderer->isTextControl();
     499}
     500   
     501bool AccessibilityRenderObject::isSearchField() const
     502{
     503    if (!node())
     504        return false;
     505   
     506    HTMLInputElement* inputElement = node()->toInputElement();
     507    if (!inputElement)
     508        return false;
     509
     510    if (inputElement->isSearchField())
     511        return true;
     512
     513    // Some websites don't label their search fields as such. However, they will
     514    // use the word "search" in either the form or input type. This won't catch every case,
     515    // but it will catch google.com for example.
     516   
     517    // Check the node name of the input type, sometimes it's "search".
     518    const AtomicString& nameAttribute = getAttribute(nameAttr);
     519    if (nameAttribute.contains("search", false))
     520        return true;
     521   
     522    // Check the form action and the name, which will sometimes be "search".
     523    HTMLFormElement* form = inputElement->form();
     524    if (form && (form->name().contains("search", false) || form->action().contains("search", false)))
     525        return true;
     526   
     527    return false;
     528}
     529   
     530bool AccessibilityRenderObject::isNativeImage() const
     531{
     532    return m_renderer->isBoxModelObject() && toRenderBoxModelObject(m_renderer)->isImage();
     533}   
     534   
     535bool AccessibilityRenderObject::isImage() const
     536{
     537    return roleValue() == ImageRole;
     538}
     539
    481540bool AccessibilityRenderObject::isAttachment() const
    482541{
     
    490549}
    491550
     551bool AccessibilityRenderObject::isPasswordField() const
     552{
     553    ASSERT(m_renderer);
     554    if (!m_renderer->node() || !m_renderer->node()->isHTMLElement())
     555        return false;
     556    if (ariaRoleAttribute() != UnknownRole)
     557        return false;
     558
     559    HTMLInputElement* inputElement = m_renderer->node()->toInputElement();
     560    if (!inputElement)
     561        return false;
     562
     563    return inputElement->isPasswordField();
     564}
     565   
    492566bool AccessibilityRenderObject::isFileUploadButton() const
    493567{
     
    500574}
    501575   
     576bool AccessibilityRenderObject::isInputImage() const
     577{
     578    Node* elementNode = node();
     579    if (roleValue() == ButtonRole && elementNode && elementNode->hasTagName(inputTag)) {
     580        HTMLInputElement* input = static_cast<HTMLInputElement*>(elementNode);
     581        return input->isImageButton();
     582    }
     583   
     584    return false;
     585}
     586
     587bool AccessibilityRenderObject::isProgressIndicator() const
     588{
     589    return roleValue() == ProgressIndicatorRole;
     590}
     591
     592bool AccessibilityRenderObject::isSlider() const
     593{
     594    return roleValue() == SliderRole;
     595}
     596
     597bool AccessibilityRenderObject::isMenuRelated() const
     598{
     599    AccessibilityRole role = roleValue();
     600    return role == MenuRole
     601        || role == MenuBarRole
     602        || role == MenuButtonRole
     603        || role == MenuItemRole;
     604}   
     605
     606bool AccessibilityRenderObject::isMenu() const
     607{
     608    return roleValue() == MenuRole;
     609}
     610
     611bool AccessibilityRenderObject::isMenuBar() const
     612{
     613    return roleValue() == MenuBarRole;
     614}
     615
     616bool AccessibilityRenderObject::isMenuButton() const
     617{
     618    return roleValue() == MenuButtonRole;
     619}
     620
     621bool AccessibilityRenderObject::isMenuItem() const
     622{
     623    return roleValue() == MenuItemRole;
     624}
     625     
     626bool AccessibilityRenderObject::isPressed() const
     627{
     628    ASSERT(m_renderer);
     629    if (roleValue() != ButtonRole)
     630        return false;
     631
     632    Node* node = m_renderer->node();
     633    if (!node)
     634        return false;
     635
     636    // If this is an ARIA button, check the aria-pressed attribute rather than node()->active()
     637    if (ariaRoleAttribute() == ButtonRole) {
     638        if (equalIgnoringCase(getAttribute(aria_pressedAttr), "true"))
     639            return true;
     640        return false;
     641    }
     642
     643    return node->active();
     644}
     645
     646bool AccessibilityRenderObject::isIndeterminate() const
     647{
     648    ASSERT(m_renderer);
     649    if (!m_renderer->node())
     650        return false;
     651
     652    HTMLInputElement* inputElement = m_renderer->node()->toInputElement();
     653    if (!inputElement)
     654        return false;
     655
     656    return inputElement->isIndeterminate();
     657}
     658
     659bool AccessibilityRenderObject::isNativeCheckboxOrRadio() const
     660{
     661    Node* elementNode = node();
     662    if (elementNode) {
     663        HTMLInputElement* input = elementNode->toInputElement();
     664        if (input)
     665            return input->isCheckbox() || input->isRadioButton();
     666    }
     667   
     668    return false;
     669}
     670   
     671bool AccessibilityRenderObject::isChecked() const
     672{
     673    ASSERT(m_renderer);
     674   
     675    Node* node = this->node();
     676    if (!node)
     677        return false;
     678
     679    // First test for native checkedness semantics
     680    HTMLInputElement* inputElement = node->toInputElement();
     681    if (inputElement)
     682        return inputElement->shouldAppearChecked();
     683
     684    // Else, if this is an ARIA checkbox or radio, respect the aria-checked attribute
     685    AccessibilityRole ariaRole = ariaRoleAttribute();
     686    if (ariaRole == RadioButtonRole || ariaRole == CheckBoxRole) {
     687        if (equalIgnoringCase(getAttribute(aria_checkedAttr), "true"))
     688            return true;
     689        return false;
     690    }
     691
     692    // Otherwise it's not checked
     693    return false;
     694}
     695
     696bool AccessibilityRenderObject::isHovered() const
     697{
     698    ASSERT(m_renderer);
     699    return m_renderer->node() && m_renderer->node()->hovered();
     700}
     701
     702bool AccessibilityRenderObject::isMultiSelectable() const
     703{
     704    ASSERT(m_renderer);
     705   
     706    const AtomicString& ariaMultiSelectable = getAttribute(aria_multiselectableAttr);
     707    if (equalIgnoringCase(ariaMultiSelectable, "true"))
     708        return true;
     709    if (equalIgnoringCase(ariaMultiSelectable, "false"))
     710        return false;
     711   
     712    if (!m_renderer->isBoxModelObject() || !toRenderBoxModelObject(m_renderer)->isListBox())
     713        return false;
     714    return m_renderer->node() && toHTMLSelectElement(m_renderer->node())->multiple();
     715}
     716
    502717bool AccessibilityRenderObject::isReadOnly() const
    503718{
     
    516731    }
    517732
    518     return AccessibilityNodeObject::isReadOnly();
     733    if (m_renderer->isBoxModelObject()) {
     734        RenderBoxModelObject* box = toRenderBoxModelObject(m_renderer);
     735        if (box->isTextField())
     736            return static_cast<HTMLInputElement*>(box->node())->readOnly();
     737        if (box->isTextArea())
     738            return static_cast<HTMLTextAreaElement*>(box->node())->readOnly();
     739    }
     740
     741    return !m_renderer->node() || !m_renderer->node()->rendererIsEditable();
    519742}
    520743
     
    527750    viewRect.intersect(contentRect);
    528751    return viewRect.isEmpty();
     752}
     753
     754int AccessibilityRenderObject::headingLevel() const
     755{
     756    // headings can be in block flow and non-block flow
     757    Node* element = node();
     758    if (!element)
     759        return 0;
     760
     761    if (ariaRoleAttribute() == HeadingRole)
     762        return getAttribute(aria_levelAttr).toInt();
     763
     764    if (element->hasTagName(h1Tag))
     765        return 1;
     766   
     767    if (element->hasTagName(h2Tag))
     768        return 2;
     769   
     770    if (element->hasTagName(h3Tag))
     771        return 3;
     772   
     773    if (element->hasTagName(h4Tag))
     774        return 4;
     775   
     776    if (element->hasTagName(h5Tag))
     777        return 5;
     778   
     779    if (element->hasTagName(h6Tag))
     780        return 6;
     781   
     782    return 0;
     783}
     784
     785bool AccessibilityRenderObject::isHeading() const
     786{
     787    return roleValue() == HeadingRole;
     788}
     789   
     790bool AccessibilityRenderObject::isLink() const
     791{
     792    return roleValue() == WebCoreLinkRole;
     793}   
     794   
     795bool AccessibilityRenderObject::isControl() const
     796{
     797    if (!m_renderer)
     798        return false;
     799   
     800    Node* node = m_renderer->node();
     801    return node && ((node->isElementNode() && static_cast<Element*>(node)->isFormControlElement())
     802                    || AccessibilityObject::isARIAControl(ariaRoleAttribute()));
     803}
     804
     805bool AccessibilityRenderObject::isFieldset() const
     806{
     807    RenderBoxModelObject* renderer = renderBoxModelObject();
     808    if (!renderer)
     809        return false;
     810    return renderer->isFieldset();
     811}
     812 
     813bool AccessibilityRenderObject::isGroup() const
     814{
     815    return roleValue() == GroupRole;
     816}
     817
     818AccessibilityObject* AccessibilityRenderObject::selectedRadioButton()
     819{
     820    if (!isRadioGroup())
     821        return 0;
     822   
     823    AccessibilityObject::AccessibilityChildrenVector children = this->children();
     824
     825    // Find the child radio button that is selected (ie. the intValue == 1).
     826    size_t size = children.size();
     827    for (size_t i = 0; i < size; ++i) {
     828        AccessibilityObject* object = children[i].get();
     829        if (object->roleValue() == RadioButtonRole && object->checkboxOrRadioValue() == ButtonStateOn)
     830            return object;
     831    }
     832    return 0;
     833}
     834
     835AccessibilityObject* AccessibilityRenderObject::selectedTabItem()
     836{
     837    if (!isTabList())
     838        return 0;
     839   
     840    // Find the child tab item that is selected (ie. the intValue == 1).
     841    AccessibilityObject::AccessibilityChildrenVector tabs;
     842    tabChildren(tabs);
     843   
     844    AccessibilityObject::AccessibilityChildrenVector children = this->children();
     845   
     846    size_t size = tabs.size();
     847    for (size_t i = 0; i < size; ++i) {
     848        AccessibilityObject* object = children[i].get();
     849        if (object->isTabItem() && object->isChecked())
     850            return object;
     851    }
     852    return 0;
    529853}
    530854
     
    558882    }
    559883   
     884    return 0;
     885}
     886
     887Element* AccessibilityRenderObject::actionElement() const
     888{
     889    if (!m_renderer)
     890        return 0;
     891   
     892    Node* node = m_renderer->node();
     893    if (node) {
     894        if (node->hasTagName(inputTag)) {
     895            HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
     896            if (!input->disabled() && (isCheckboxOrRadio() || input->isTextButton()))
     897                return input;
     898        } else if (node->hasTagName(buttonTag))
     899            return toElement(node);
     900    }
     901
     902    if (isFileUploadButton())
     903        return toElement(m_renderer->node());
     904           
     905    if (AccessibilityObject::isARIAInput(ariaRoleAttribute()))
     906        return toElement(m_renderer->node());
     907
     908    if (isImageButton())
     909        return toElement(m_renderer->node());
     910   
     911    if (m_renderer->isBoxModelObject() && toRenderBoxModelObject(m_renderer)->isMenuList())
     912        return toElement(m_renderer->node());
     913
     914    switch (roleValue()) {
     915    case ButtonRole:
     916    case PopUpButtonRole:
     917    case TabRole:
     918    case MenuItemRole:
     919    case ListItemRole:
     920        return toElement(m_renderer->node());
     921    default:
     922        break;
     923    }
     924   
     925    Element* elt = anchorElement();
     926    if (!elt)
     927        elt = mouseButtonListener();
     928    return elt;
     929}
     930
     931Element* AccessibilityRenderObject::mouseButtonListener() const
     932{
     933    Node* node = m_renderer->node();
     934    if (!node)
     935        return 0;
     936   
     937    // check if our parent is a mouse button listener
     938    while (node && !node->isElementNode())
     939        node = node->parentNode();
     940
     941    if (!node)
     942        return 0;
     943
     944    // FIXME: Do the continuation search like anchorElement does
     945    for (Element* element = static_cast<Element*>(node); element; element = element->parentElement()) {
     946        if (element->getAttributeEventListener(eventNames().clickEvent) || element->getAttributeEventListener(eventNames().mousedownEvent) || element->getAttributeEventListener(eventNames().mouseupEvent))
     947            return element;
     948    }
     949
     950    return 0;
     951}
     952
     953void AccessibilityRenderObject::alterSliderValue(bool increase)
     954{
     955    if (roleValue() != SliderRole)
     956        return;
     957
     958    if (!getAttribute(stepAttr).isEmpty())
     959        changeValueByStep(increase);
     960    else
     961        changeValueByPercent(increase ? 5 : -5);
     962}
     963   
     964void AccessibilityRenderObject::increment()
     965{
     966    alterSliderValue(true);
     967}
     968
     969void AccessibilityRenderObject::decrement()
     970{
     971    alterSliderValue(false);
     972}
     973
     974static Element* siblingWithAriaRole(String role, Node* node)
     975{
     976    Node* sibling = node->parentNode()->firstChild();
     977    while (sibling) {
     978        if (sibling->isElementNode()) {
     979            const AtomicString& siblingAriaRole = static_cast<Element*>(sibling)->getAttribute(roleAttr);
     980            if (equalIgnoringCase(siblingAriaRole, role))
     981                return static_cast<Element*>(sibling);
     982        }
     983        sibling = sibling->nextSibling();
     984    }
     985   
     986    return 0;
     987}
     988
     989Element* AccessibilityRenderObject::menuElementForMenuButton() const
     990{
     991    if (ariaRoleAttribute() != MenuButtonRole)
     992        return 0;
     993
     994    return siblingWithAriaRole("menu", renderer()->node());
     995}
     996
     997AccessibilityObject* AccessibilityRenderObject::menuForMenuButton() const
     998{
     999    Element* menu = menuElementForMenuButton();
     1000    if (menu && menu->renderer())
     1001        return axObjectCache()->getOrCreate(menu);
     1002    return 0;
     1003}
     1004
     1005Element* AccessibilityRenderObject::menuItemElementForMenu() const
     1006{
     1007    if (ariaRoleAttribute() != MenuRole)
     1008        return 0;
     1009   
     1010    return siblingWithAriaRole("menuitem", renderer()->node());   
     1011}
     1012
     1013AccessibilityObject* AccessibilityRenderObject::menuButtonForMenu() const
     1014{
     1015    Element* menuItem = menuItemElementForMenu();
     1016
     1017    if (menuItem && menuItem->renderer()) {
     1018        // ARIA just has generic menu items.  AppKit needs to know if this is a top level items like MenuBarButton or MenuBarItem
     1019        AccessibilityObject* menuItemAX = axObjectCache()->getOrCreate(menuItem);
     1020        if (menuItemAX->isMenuButton())
     1021            return menuItemAX;
     1022    }
    5601023    return 0;
    5611024}
     
    5991062    return String();
    6001063}
     1064   
     1065unsigned AccessibilityRenderObject::hierarchicalLevel() const
     1066{
     1067    if (!m_renderer)
     1068        return 0;
     1069
     1070    Node* node = m_renderer->node();
     1071    if (!node || !node->isElementNode())
     1072        return 0;
     1073    Element* element = static_cast<Element*>(node);
     1074    String ariaLevel = element->getAttribute(aria_levelAttr);
     1075    if (!ariaLevel.isEmpty())
     1076        return ariaLevel.toInt();
     1077   
     1078    // Only tree item will calculate its level through the DOM currently.
     1079    if (roleValue() != TreeItemRole)
     1080        return 0;
     1081   
     1082    // Hierarchy leveling starts at 0.
     1083    // We measure tree hierarchy by the number of groups that the item is within.
     1084    unsigned level = 0;
     1085    AccessibilityObject* parent = parentObject();
     1086    while (parent) {
     1087        AccessibilityRole parentRole = parent->roleValue();
     1088        if (parentRole == GroupRole)
     1089            level++;
     1090        else if (parentRole == TreeRole)
     1091            break;
     1092       
     1093        parent = parent->parentObject();
     1094    }
     1095   
     1096    return level;
     1097}
    6011098
    6021099static TextIteratorBehavior textIteratorBehaviorForTextRange()
     
    6501147}   
    6511148   
     1149AccessibilityButtonState AccessibilityRenderObject::checkboxOrRadioValue() const
     1150{
     1151    if (isNativeCheckboxOrRadio())
     1152        return isChecked() ? ButtonStateOn : ButtonStateOff;
     1153   
     1154    return AccessibilityObject::checkboxOrRadioValue();
     1155}
     1156
     1157String AccessibilityRenderObject::valueDescription() const
     1158{
     1159    if (!isARIARange())
     1160        return String();
     1161   
     1162    return getAttribute(aria_valuetextAttr).string();
     1163}
     1164   
     1165float AccessibilityRenderObject::stepValueForRange() const
     1166{
     1167    return getAttribute(stepAttr).toFloat();
     1168}
     1169
     1170bool AccessibilityRenderObject::isARIARange() const
     1171{
     1172    return m_ariaRole == ProgressIndicatorRole
     1173        || m_ariaRole == SliderRole
     1174        || m_ariaRole == ScrollBarRole
     1175        || m_ariaRole == SpinButtonRole;
     1176}
     1177   
     1178float AccessibilityRenderObject::valueForRange() const
     1179{
     1180    if (!isARIARange())
     1181        return 0.0f;
     1182
     1183    return getAttribute(aria_valuenowAttr).toFloat();
     1184}
     1185
     1186float AccessibilityRenderObject::maxValueForRange() const
     1187{
     1188    if (!isARIARange())
     1189        return 0.0f;
     1190
     1191    return getAttribute(aria_valuemaxAttr).toFloat();
     1192}
     1193
     1194float AccessibilityRenderObject::minValueForRange() const
     1195{
     1196    if (!isARIARange())
     1197        return 0.0f;
     1198
     1199    return getAttribute(aria_valueminAttr).toFloat();
     1200}
     1201
    6521202String AccessibilityRenderObject::stringValue() const
    6531203{
     
    7081258}
    7091259
     1260// This function implements the ARIA accessible name as described by the Mozilla
     1261// ARIA Implementer's Guide.
     1262static String accessibleNameForNode(Node* node)
     1263{
     1264    if (node->isTextNode())
     1265        return toText(node)->data();
     1266
     1267    if (node->hasTagName(inputTag))
     1268        return static_cast<HTMLInputElement*>(node)->value();
     1269
     1270    if (node->isHTMLElement()) {
     1271        const AtomicString& alt = toHTMLElement(node)->getAttribute(altAttr);
     1272        if (!alt.isEmpty())
     1273            return alt;
     1274    }
     1275
     1276    return String();
     1277}
     1278
     1279String AccessibilityRenderObject::accessibilityDescriptionForElements(Vector<Element*> &elements) const
     1280{
     1281    StringBuilder builder;
     1282    unsigned size = elements.size();
     1283    for (unsigned i = 0; i < size; ++i) {
     1284        Element* idElement = elements[i];
     1285
     1286        builder.append(accessibleNameForNode(idElement));
     1287        for (Node* n = idElement->firstChild(); n; n = n->traverseNextNode(idElement))
     1288            builder.append(accessibleNameForNode(n));
     1289
     1290        if (i != size - 1)
     1291            builder.append(' ');
     1292    }
     1293    return builder.toString();
     1294}
     1295
     1296void AccessibilityRenderObject::elementsFromAttribute(Vector<Element*>& elements, const QualifiedName& attribute) const
     1297{
     1298    Node* node = m_renderer->node();
     1299    if (!node || !node->isElementNode())
     1300        return;
     1301
     1302    TreeScope* scope = node->treeScope();
     1303    if (!scope)
     1304        return;
     1305   
     1306    String idList = getAttribute(attribute).string();
     1307    if (idList.isEmpty())
     1308        return;
     1309   
     1310    idList.replace('\n', ' ');
     1311    Vector<String> idVector;
     1312    idList.split(' ', idVector);
     1313   
     1314    unsigned size = idVector.size();
     1315    for (unsigned i = 0; i < size; ++i) {
     1316        AtomicString idName(idVector[i]);
     1317        Element* idElement = scope->getElementById(idName);
     1318        if (idElement)
     1319            elements.append(idElement);
     1320    }
     1321}
     1322   
     1323void AccessibilityRenderObject::ariaLabeledByElements(Vector<Element*>& elements) const
     1324{
     1325    elementsFromAttribute(elements, aria_labeledbyAttr);
     1326    if (!elements.size())
     1327        elementsFromAttribute(elements, aria_labelledbyAttr);
     1328}
     1329   
     1330String AccessibilityRenderObject::ariaLabeledByAttribute() const
     1331{
     1332    Vector<Element*> elements;
     1333    ariaLabeledByElements(elements);
     1334   
     1335    return accessibilityDescriptionForElements(elements);
     1336}
     1337
     1338static HTMLLabelElement* labelForElement(Element* element)
     1339{
     1340    RefPtr<NodeList> list = element->document()->getElementsByTagName("label");
     1341    unsigned len = list->length();
     1342    for (unsigned i = 0; i < len; i++) {
     1343        if (list->item(i)->hasTagName(labelTag)) {
     1344            HTMLLabelElement* label = static_cast<HTMLLabelElement*>(list->item(i));
     1345            if (label->control() == element)
     1346                return label;
     1347        }
     1348    }
     1349   
     1350    return 0;
     1351}
     1352   
    7101353HTMLLabelElement* AccessibilityRenderObject::labelElementContainer() const
    7111354{
     
    7261369}
    7271370
     1371String AccessibilityRenderObject::title() const
     1372{
     1373    AccessibilityRole role = roleValue();
     1374   
     1375    if (!m_renderer)
     1376        return String();
     1377
     1378    Node* node = m_renderer->node();
     1379    if (!node)
     1380        return String();
     1381   
     1382    bool isInputTag = node->hasTagName(inputTag);
     1383    if (isInputTag) {
     1384        HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
     1385        if (input->isTextButton())
     1386            return input->valueWithDefault();
     1387    }
     1388   
     1389    if (isInputTag || AccessibilityObject::isARIAInput(ariaRoleAttribute()) || isControl()) {
     1390        HTMLLabelElement* label = labelForElement(static_cast<Element*>(node));
     1391        if (label && !exposesTitleUIElement())
     1392            return label->innerText();
     1393    }
     1394   
     1395    switch (role) {
     1396    case ButtonRole:
     1397    case ListBoxOptionRole:
     1398    case MenuItemRole:
     1399    case MenuButtonRole:
     1400    case RadioButtonRole:
     1401    case CheckBoxRole:
     1402    case TabRole:
     1403    case PopUpButtonRole:
     1404        return textUnderElement();
     1405    default:
     1406        break;
     1407    }
     1408   
     1409    if (isHeading() || isLink())
     1410        return textUnderElement();
     1411
     1412    // If it's focusable but it's not content editable or a known control type, then it will appear to
     1413    // the user as a single atomic object, so we should use its text as the default title.
     1414    if (isGenericFocusableElement())
     1415        return textUnderElement();
     1416
     1417    return String();
     1418}
     1419
    7281420String AccessibilityRenderObject::ariaDescribedByAttribute() const
    7291421{
     
    7341426}
    7351427   
     1428String AccessibilityRenderObject::ariaAccessibilityDescription() const
     1429{
     1430    String ariaLabeledBy = ariaLabeledByAttribute();
     1431    if (!ariaLabeledBy.isEmpty())
     1432        return ariaLabeledBy;
     1433
     1434    const AtomicString& ariaLabel = getAttribute(aria_labelAttr);
     1435    if (!ariaLabel.isEmpty())
     1436        return ariaLabel;
     1437   
     1438    return String();
     1439}
     1440
    7361441String AccessibilityRenderObject::webAreaAccessibilityDescription() const
    7371442{
     
    7861491        return String();
    7871492
     1493    // Static text should not have a description, it should only have a stringValue.
     1494    if (roleValue() == StaticTextRole)
     1495        return String();
     1496   
     1497    String ariaDescription = ariaAccessibilityDescription();
     1498    if (!ariaDescription.isEmpty())
     1499        return ariaDescription;
     1500   
     1501    if (isImage() || isInputImage() || isNativeImage() || isCanvas()) {
     1502
     1503        // Images should use alt as long as the attribute is present, even if empty.
     1504        // Otherwise, it should fallback to other methods, like the title attribute.
     1505        const AtomicString& alt = getAttribute(altAttr);
     1506        if (!alt.isNull())
     1507            return alt;
     1508    }
     1509   
     1510#if ENABLE(MATHML)
     1511    Node* node = m_renderer->node();
     1512    if (node && node->isElementNode() && static_cast<Element*>(node)->isMathMLElement())
     1513        return getAttribute(MathMLNames::alttextAttr);
     1514#endif
     1515   
    7881516    if (isWebArea())
    7891517        return webAreaAccessibilityDescription();
    790 
    791     return AccessibilityNodeObject::accessibilityDescription();
     1518   
     1519    // An element's descriptive text is comprised of title() (what's visible on the screen) and accessibilityDescription() (other descriptive text).
     1520    // Both are used to generate what a screen reader speaks.
     1521    // If this point is reached (i.e. there's no accessibilityDescription) and there's no title(), we should fallback to using the title attribute.
     1522    // 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).
     1523    if (title().isEmpty())
     1524        return getAttribute(titleAttr);
     1525   
     1526    return String();
    7921527}
    7931528
     
    10761811}
    10771812
     1813bool AccessibilityRenderObject::isDescendantOfBarrenParent() const
     1814{
     1815    for (AccessibilityObject* object = parentObject(); object; object = object->parentObject()) {
     1816        if (!object->canHaveChildren())
     1817            return true;
     1818    }
     1819   
     1820    return false;
     1821}
     1822   
    10781823bool AccessibilityRenderObject::isAllowedChildOfTree() const
    10791824{
     
    13152060String AccessibilityRenderObject::text() const
    13162061{
     2062    // If this is a user defined static text, use the accessible name computation.
     2063    if (ariaRoleAttribute() == StaticTextRole)
     2064        return ariaAccessibilityDescription();
     2065   
     2066    if (!isTextControl())
     2067        return String();
     2068
    13172069    if (isPasswordField())
    13182070        return passwordFieldValue();
    13192071
    1320     return AccessibilityNodeObject::text();
     2072    Node* node = m_renderer->node();
     2073    if (!node)
     2074        return String();
     2075
     2076    if (isNativeTextControl())
     2077        return toRenderTextControl(m_renderer)->textFormControlElement()->value();
     2078
     2079    if (!node->isElementNode())
     2080        return String();
     2081   
     2082    return static_cast<Element*>(node)->innerText();
    13212083}
    13222084   
     
    14762238}
    14772239   
     2240bool AccessibilityRenderObject::isRequired() const
     2241{
     2242    if (equalIgnoringCase(getAttribute(aria_requiredAttr), "true"))
     2243        return true;
     2244   
     2245    Node* n = node();
     2246    if (n && (n->isElementNode() && static_cast<Element*>(n)->isFormControlElement()))
     2247        return static_cast<HTMLFormControlElement*>(n)->required();
     2248   
     2249    return false;
     2250}
     2251
    14782252bool AccessibilityRenderObject::isSelected() const
    14792253{
     
    15722346}
    15732347
     2348void AccessibilityRenderObject::changeValueByStep(bool increase)
     2349{
     2350    float step = stepValueForRange();
     2351    float value = valueForRange();
     2352   
     2353    value += increase ? step : -step;
     2354
     2355    setValue(String::number(value));
     2356   
     2357    axObjectCache()->postNotification(m_renderer, AXObjectCache::AXValueChanged, true);
     2358}
     2359   
     2360void AccessibilityRenderObject::changeValueByPercent(float percentChange)
     2361{
     2362    float range = maxValueForRange() - minValueForRange();
     2363    float value = valueForRange();
     2364   
     2365    value += range * (percentChange / 100);
     2366    setValue(String::number(value));
     2367   
     2368    axObjectCache()->postNotification(m_renderer, AXObjectCache::AXValueChanged, true);
     2369}
     2370
    15742371void AccessibilityRenderObject::setSelectedRows(AccessibilityChildrenVector& selectedRows)
    15752372{
     
    16312428}
    16322429   
     2430bool AccessibilityRenderObject::isEnabled() const
     2431{
     2432    ASSERT(m_renderer);
     2433   
     2434    if (equalIgnoringCase(getAttribute(aria_disabledAttr), "true"))
     2435        return false;
     2436   
     2437    Node* node = m_renderer->node();
     2438    if (!node || !node->isElementNode())
     2439        return true;
     2440
     2441    return static_cast<Element*>(node)->isEnabledFormControl();
     2442}
     2443
    16332444RenderView* AccessibilityRenderObject::topRenderer() const
    16342445{
     
    23283139}
    23293140
     3141bool AccessibilityRenderObject::isGenericFocusableElement() const
     3142{
     3143    if (!canSetFocusAttribute())
     3144        return false;
     3145
     3146    // If it's a control, it's not generic.
     3147    if (isControl())
     3148        return false;
     3149
     3150    // If it has an aria role, it's not generic.
     3151    if (m_ariaRole != UnknownRole)
     3152        return false;
     3153
     3154    // If the content editable attribute is set on this element, that's the reason
     3155    // it's focusable, and existing logic should handle this case already - so it's not a
     3156    // generic focusable element.
     3157    if (hasContentEditableAttributeSet())
     3158        return false;
     3159
     3160    // The web area and body element are both focusable, but existing logic handles these
     3161    // cases already, so we don't need to include them here.
     3162    if (roleValue() == WebAreaRole)
     3163        return false;
     3164    if (node() && node()->hasTagName(bodyTag))
     3165        return false;
     3166
     3167    return true;
     3168}
     3169   
    23303170AccessibilityRole AccessibilityRenderObject::determineAccessibilityRole()
    23313171{
     
    25983438    }
    25993439}
     3440   
     3441bool AccessibilityRenderObject::canHaveChildren() const
     3442{
     3443    if (!m_renderer)
     3444        return false;
     3445   
     3446    // Elements that should not have children
     3447    switch (roleValue()) {
     3448    case ImageRole:
     3449    case ButtonRole:
     3450    case PopUpButtonRole:
     3451    case CheckBoxRole:
     3452    case RadioButtonRole:
     3453    case TabRole:
     3454    case StaticTextRole:
     3455    case ListBoxOptionRole:
     3456    case ScrollBarRole:
     3457        return false;
     3458    default:
     3459        return true;
     3460    }
     3461}
    26003462
    26013463void AccessibilityRenderObject::clearChildren()
     
    27353597#endif
    27363598}
    2737 
    2738 bool AccessibilityRenderObject::canHaveChildren() const
    2739 {
    2740     if (!m_renderer)
    2741         return false;
    2742 
    2743     return AccessibilityNodeObject::canHaveChildren();
    2744 }
    2745 
     3599       
    27463600const AtomicString& AccessibilityRenderObject::ariaLiveRegionStatus() const
    27473601{
  • trunk/Source/WebCore/accessibility/AccessibilityRenderObject.h

    r128318 r128353  
    6767    virtual void init();
    6868   
     69    virtual bool isAnchor() const;
    6970    virtual bool isAttachment() const;
     71    virtual bool isHeading() const;
     72    virtual bool isLink() const;
     73    virtual bool isImageButton() const;
     74    virtual bool isImage() const;
     75    virtual bool isNativeImage() const;
     76    virtual bool isPasswordField() const;
     77    virtual bool isNativeTextControl() const;
     78    virtual bool isSearchField() const;
     79    virtual bool isWebArea() const;
    7080    virtual bool isFileUploadButton() const;
    71 
     81    virtual bool isInputImage() const;
     82    virtual bool isProgressIndicator() const;
     83    virtual bool isSlider() const;
     84    virtual bool isMenuRelated() const;
     85    virtual bool isMenu() const;
     86    virtual bool isMenuBar() const;
     87    virtual bool isMenuButton() const;
     88    virtual bool isMenuItem() const;
     89    virtual bool isControl() const;
     90    virtual bool isFieldset() const;
     91    virtual bool isGroup() const;
     92
     93    virtual bool isEnabled() const;
    7294    virtual bool isSelected() const;
    7395    virtual bool isFocused() const;
     96    virtual bool isChecked() const;
     97    virtual bool isHovered() const;
     98    virtual bool isIndeterminate() const;
    7499    virtual bool isLoaded() const;
     100    virtual bool isMultiSelectable() const;
    75101    virtual bool isOffScreen() const;
     102    virtual bool isPressed() const;
    76103    virtual bool isReadOnly() const;
    77104    virtual bool isUnvisited() const;
    78105    virtual bool isVisited() const;       
     106    virtual bool isRequired() const;
    79107    virtual bool isLinked() const;
    80108    virtual bool hasBoldFont() const;
     
    96124    virtual bool accessibilityIsIgnored() const;
    97125   
     126    virtual int headingLevel() const;
     127    virtual AccessibilityButtonState checkboxOrRadioValue() const;
     128    virtual String valueDescription() const;
     129    virtual float valueForRange() const;
     130    virtual float maxValueForRange() const;
     131    virtual float minValueForRange() const;
     132    virtual float stepValueForRange() const;
     133    virtual AccessibilityObject* selectedRadioButton();
     134    virtual AccessibilityObject* selectedTabItem();
    98135    virtual int layoutCount() const;
    99136    virtual double estimatedLoadingProgress() const;
     
    120157    virtual AccessibilityObject* accessibilityHitTest(const IntPoint&) const;
    121158
     159    virtual Element* actionElement() const;
     160    Element* mouseButtonListener() const;
    122161    FrameView* frameViewIfRenderView() const;
    123162    virtual Element* anchorElement() const;
     163    AccessibilityObject* menuForMenuButton() const;
     164    AccessibilityObject* menuButtonForMenu() const;
    124165   
    125166    virtual LayoutRect boundingBoxRect() const;
     
    144185    virtual VisibleSelection selection() const;
    145186    virtual String stringValue() const;
     187    virtual String ariaLabeledByAttribute() const;
     188    virtual String title() const;
    146189    virtual String ariaDescribedByAttribute() const;
    147190    virtual String accessibilityDescription() const;
     
    157200    virtual void getDocumentLinks(AccessibilityChildrenVector&);
    158201    virtual FrameView* documentFrameView() const;
     202    virtual unsigned hierarchicalLevel() const;
    159203
    160204    virtual void clearChildren();
     
    165209    virtual void setValue(const String&);
    166210    virtual void setSelectedRows(AccessibilityChildrenVector&);
     211    virtual void changeValueByPercent(float percentChange);
    167212    virtual AccessibilityOrientation orientation() const;
     213    virtual void increment();
     214    virtual void decrement();
    168215   
    169216    virtual void detach();
     
    217264   
    218265    void setRenderObject(RenderObject* renderer) { m_renderer = renderer; }
     266    void ariaLabeledByElements(Vector<Element*>& elements) const;
    219267    bool needsToUpdateChildren() const { return m_childrenDirty; }
    220268    ScrollableArea* getScrollableAreaIfScrollable() const;
     
    229277    void ariaListboxVisibleChildren(AccessibilityChildrenVector&);
    230278    bool ariaIsHidden() const;
     279    bool isDescendantOfBarrenParent() const;
    231280    bool isAllowedChildOfTree() const;
    232281    bool hasTextAlternative() const;
     
    237286    virtual void setNeedsToUpdateChildren() { m_childrenDirty = true; }
    238287
     288    Element* menuElementForMenuButton() const;
     289    Element* menuItemElementForMenu() const;
     290
    239291    bool isTabItemSelected() const;
     292    void alterSliderValue(bool increase);
     293    void changeValueByStep(bool increase);
     294    bool isNativeCheckboxOrRadio() const;
    240295    LayoutRect checkboxOrRadioRect() const;
    241296    void addRadioButtonGroupMembers(AccessibilityChildrenVector& linkedUIElements) const;
     
    247302    bool isDescendantOfElementType(const QualifiedName& tagName) const;
    248303    // This returns true if it's focusable but it's not content editable and it's not a control or ARIA control.
     304    bool isGenericFocusableElement() const;
     305    bool isARIARange() const;
    249306
    250307    void addTextFieldChildren();
     
    261318    void setElementAttributeValue(const QualifiedName&, bool);
    262319   
     320    String accessibilityDescriptionForElements(Vector<Element*> &elements) const;
     321    void elementsFromAttribute(Vector<Element*>& elements, const QualifiedName&) const;
     322    String ariaAccessibilityDescription() const;
    263323    String webAreaAccessibilityDescription() const;
    264324
Note: See TracChangeset for help on using the changeset viewer.