Changeset 128368 in webkit


Ignore:
Timestamp:
Sep 12, 2012 3:19:50 PM (12 years ago)
Author:
commit-queue@webkit.org
Message:

Unreviewed, rolling out r128353.
http://trac.webkit.org/changeset/128353
https://bugs.webkit.org/show_bug.cgi?id=96565

Re-land change that broke tests on Chromium. Tests are now
disabled, will rebaseline after this rolls. (Requested by
dmazzoni 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::canHaveChildren):
(WebCore):
(WebCore::AccessibilityNodeObject::accessibilityIsIgnored):
(WebCore::AccessibilityNodeObject::isWebArea):
(WebCore::AccessibilityNodeObject::isImageButton):
(WebCore::AccessibilityNodeObject::isAnchor):
(WebCore::AccessibilityNodeObject::isNativeTextControl):
(WebCore::AccessibilityNodeObject::isSearchField):
(WebCore::AccessibilityNodeObject::isNativeImage):
(WebCore::AccessibilityNodeObject::isImage):
(WebCore::AccessibilityNodeObject::isPasswordField):
(WebCore::AccessibilityNodeObject::isInputImage):
(WebCore::AccessibilityNodeObject::isProgressIndicator):
(WebCore::AccessibilityNodeObject::isSlider):
(WebCore::AccessibilityNodeObject::isMenuRelated):
(WebCore::AccessibilityNodeObject::isMenu):
(WebCore::AccessibilityNodeObject::isMenuBar):
(WebCore::AccessibilityNodeObject::isMenuButton):
(WebCore::AccessibilityNodeObject::isMenuItem):
(WebCore::AccessibilityNodeObject::isNativeCheckboxOrRadio):
(WebCore::AccessibilityNodeObject::isEnabled):
(WebCore::AccessibilityNodeObject::isIndeterminate):
(WebCore::AccessibilityNodeObject::isPressed):
(WebCore::AccessibilityNodeObject::isChecked):
(WebCore::AccessibilityNodeObject::isHovered):
(WebCore::AccessibilityNodeObject::isMultiSelectable):
(WebCore::AccessibilityNodeObject::isReadOnly):
(WebCore::AccessibilityNodeObject::isRequired):
(WebCore::AccessibilityNodeObject::headingLevel):
(WebCore::AccessibilityNodeObject::valueDescription):
(WebCore::AccessibilityNodeObject::isARIARange):
(WebCore::AccessibilityNodeObject::valueForRange):
(WebCore::AccessibilityNodeObject::maxValueForRange):
(WebCore::AccessibilityNodeObject::minValueForRange):
(WebCore::AccessibilityNodeObject::stepValueForRange):
(WebCore::AccessibilityNodeObject::isHeading):
(WebCore::AccessibilityNodeObject::isLink):
(WebCore::AccessibilityNodeObject::isControl):
(WebCore::AccessibilityNodeObject::isFieldset):
(WebCore::AccessibilityNodeObject::isGroup):
(WebCore::AccessibilityNodeObject::selectedRadioButton):
(WebCore::AccessibilityNodeObject::selectedTabItem):
(WebCore::AccessibilityNodeObject::checkboxOrRadioValue):
(WebCore::AccessibilityNodeObject::anchorElement):
(WebCore::AccessibilityNodeObject::actionElement):
(WebCore::AccessibilityNodeObject::mouseButtonListener):
(WebCore::AccessibilityNodeObject::isDescendantOfBarrenParent):
(WebCore::AccessibilityNodeObject::alterSliderValue):
(WebCore::AccessibilityNodeObject::increment):
(WebCore::AccessibilityNodeObject::decrement):
(WebCore::AccessibilityNodeObject::changeValueByStep):
(WebCore::AccessibilityNodeObject::changeValueByPercent):
(WebCore::AccessibilityNodeObject::isGenericFocusableElement):
(WebCore::AccessibilityNodeObject::labelForElement):
(WebCore::AccessibilityNodeObject::ariaAccessibilityDescription):
(WebCore::siblingWithAriaRole):
(WebCore::AccessibilityNodeObject::menuElementForMenuButton):
(WebCore::AccessibilityNodeObject::menuForMenuButton):
(WebCore::AccessibilityNodeObject::menuItemElementForMenu):
(WebCore::AccessibilityNodeObject::menuButtonForMenu):
(WebCore::AccessibilityNodeObject::accessibilityDescription):
(WebCore::AccessibilityNodeObject::helpText):
(WebCore::AccessibilityNodeObject::hierarchicalLevel):
(WebCore::AccessibilityNodeObject::textUnderElement):
(WebCore::AccessibilityNodeObject::title):
(WebCore::AccessibilityNodeObject::text):
(WebCore::AccessibilityNodeObject::stringValue):
(WebCore::accessibleNameForNode):
(WebCore::AccessibilityNodeObject::accessibilityDescriptionForElements):
(WebCore::AccessibilityNodeObject::elementsFromAttribute):
(WebCore::AccessibilityNodeObject::ariaLabeledByElements):
(WebCore::AccessibilityNodeObject::ariaLabeledByAttribute):
(WebCore::AccessibilityNodeObject::canSetFocusAttribute):

  • accessibility/AccessibilityNodeObject.h:

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

  • accessibility/AccessibilityRenderObject.cpp:

(WebCore::AccessibilityRenderObject::parentObject):
(WebCore::AccessibilityRenderObject::isReadOnly):
(WebCore::AccessibilityRenderObject::helpText):
(WebCore::AccessibilityRenderObject::accessibilityDescription):
(WebCore::AccessibilityRenderObject::text):
(WebCore::AccessibilityRenderObject::contentChanged):
(WebCore):
(WebCore::AccessibilityRenderObject::canHaveChildren):

  • accessibility/AccessibilityRenderObject.h:

(AccessibilityRenderObject):

LayoutTests:

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

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r128366 r128368  
     12012-09-12  Sheriff Bot  <webkit.review.bot@gmail.com>
     2
     3        Unreviewed, rolling out r128353.
     4        http://trac.webkit.org/changeset/128353
     5        https://bugs.webkit.org/show_bug.cgi?id=96565
     6
     7        Re-land change that broke tests on Chromium. Tests are now
     8        disabled, will rebaseline after this rolls. (Requested by
     9        dmazzoni on #webkit).
     10
     11        * accessibility/canvas-fallback-content-2-expected.txt: Added.
     12        * accessibility/canvas-fallback-content-2.html: Added.
     13
    1142012-09-12  Ojan Vafai  <ojan@chromium.org>
    215
  • trunk/Source/WebCore/ChangeLog

    r128363 r128368  
     12012-09-12  Sheriff Bot  <webkit.review.bot@gmail.com>
     2
     3        Unreviewed, rolling out r128353.
     4        http://trac.webkit.org/changeset/128353
     5        https://bugs.webkit.org/show_bug.cgi?id=96565
     6
     7        Re-land change that broke tests on Chromium. Tests are now
     8        disabled, will rebaseline after this rolls. (Requested by
     9        dmazzoni on #webkit).
     10
     11        * accessibility/AccessibilityNodeObject.cpp:
     12        (WebCore::AccessibilityNodeObject::determineAccessibilityRole):
     13        (WebCore::AccessibilityNodeObject::canHaveChildren):
     14        (WebCore):
     15        (WebCore::AccessibilityNodeObject::accessibilityIsIgnored):
     16        (WebCore::AccessibilityNodeObject::isWebArea):
     17        (WebCore::AccessibilityNodeObject::isImageButton):
     18        (WebCore::AccessibilityNodeObject::isAnchor):
     19        (WebCore::AccessibilityNodeObject::isNativeTextControl):
     20        (WebCore::AccessibilityNodeObject::isSearchField):
     21        (WebCore::AccessibilityNodeObject::isNativeImage):
     22        (WebCore::AccessibilityNodeObject::isImage):
     23        (WebCore::AccessibilityNodeObject::isPasswordField):
     24        (WebCore::AccessibilityNodeObject::isInputImage):
     25        (WebCore::AccessibilityNodeObject::isProgressIndicator):
     26        (WebCore::AccessibilityNodeObject::isSlider):
     27        (WebCore::AccessibilityNodeObject::isMenuRelated):
     28        (WebCore::AccessibilityNodeObject::isMenu):
     29        (WebCore::AccessibilityNodeObject::isMenuBar):
     30        (WebCore::AccessibilityNodeObject::isMenuButton):
     31        (WebCore::AccessibilityNodeObject::isMenuItem):
     32        (WebCore::AccessibilityNodeObject::isNativeCheckboxOrRadio):
     33        (WebCore::AccessibilityNodeObject::isEnabled):
     34        (WebCore::AccessibilityNodeObject::isIndeterminate):
     35        (WebCore::AccessibilityNodeObject::isPressed):
     36        (WebCore::AccessibilityNodeObject::isChecked):
     37        (WebCore::AccessibilityNodeObject::isHovered):
     38        (WebCore::AccessibilityNodeObject::isMultiSelectable):
     39        (WebCore::AccessibilityNodeObject::isReadOnly):
     40        (WebCore::AccessibilityNodeObject::isRequired):
     41        (WebCore::AccessibilityNodeObject::headingLevel):
     42        (WebCore::AccessibilityNodeObject::valueDescription):
     43        (WebCore::AccessibilityNodeObject::isARIARange):
     44        (WebCore::AccessibilityNodeObject::valueForRange):
     45        (WebCore::AccessibilityNodeObject::maxValueForRange):
     46        (WebCore::AccessibilityNodeObject::minValueForRange):
     47        (WebCore::AccessibilityNodeObject::stepValueForRange):
     48        (WebCore::AccessibilityNodeObject::isHeading):
     49        (WebCore::AccessibilityNodeObject::isLink):
     50        (WebCore::AccessibilityNodeObject::isControl):
     51        (WebCore::AccessibilityNodeObject::isFieldset):
     52        (WebCore::AccessibilityNodeObject::isGroup):
     53        (WebCore::AccessibilityNodeObject::selectedRadioButton):
     54        (WebCore::AccessibilityNodeObject::selectedTabItem):
     55        (WebCore::AccessibilityNodeObject::checkboxOrRadioValue):
     56        (WebCore::AccessibilityNodeObject::anchorElement):
     57        (WebCore::AccessibilityNodeObject::actionElement):
     58        (WebCore::AccessibilityNodeObject::mouseButtonListener):
     59        (WebCore::AccessibilityNodeObject::isDescendantOfBarrenParent):
     60        (WebCore::AccessibilityNodeObject::alterSliderValue):
     61        (WebCore::AccessibilityNodeObject::increment):
     62        (WebCore::AccessibilityNodeObject::decrement):
     63        (WebCore::AccessibilityNodeObject::changeValueByStep):
     64        (WebCore::AccessibilityNodeObject::changeValueByPercent):
     65        (WebCore::AccessibilityNodeObject::isGenericFocusableElement):
     66        (WebCore::AccessibilityNodeObject::labelForElement):
     67        (WebCore::AccessibilityNodeObject::ariaAccessibilityDescription):
     68        (WebCore::siblingWithAriaRole):
     69        (WebCore::AccessibilityNodeObject::menuElementForMenuButton):
     70        (WebCore::AccessibilityNodeObject::menuForMenuButton):
     71        (WebCore::AccessibilityNodeObject::menuItemElementForMenu):
     72        (WebCore::AccessibilityNodeObject::menuButtonForMenu):
     73        (WebCore::AccessibilityNodeObject::accessibilityDescription):
     74        (WebCore::AccessibilityNodeObject::helpText):
     75        (WebCore::AccessibilityNodeObject::hierarchicalLevel):
     76        (WebCore::AccessibilityNodeObject::textUnderElement):
     77        (WebCore::AccessibilityNodeObject::title):
     78        (WebCore::AccessibilityNodeObject::text):
     79        (WebCore::AccessibilityNodeObject::stringValue):
     80        (WebCore::accessibleNameForNode):
     81        (WebCore::AccessibilityNodeObject::accessibilityDescriptionForElements):
     82        (WebCore::AccessibilityNodeObject::elementsFromAttribute):
     83        (WebCore::AccessibilityNodeObject::ariaLabeledByElements):
     84        (WebCore::AccessibilityNodeObject::ariaLabeledByAttribute):
     85        (WebCore::AccessibilityNodeObject::canSetFocusAttribute):
     86        * accessibility/AccessibilityNodeObject.h:
     87        (AccessibilityNodeObject):
     88        (WebCore::AccessibilityNodeObject::node):
     89        * accessibility/AccessibilityRenderObject.cpp:
     90        (WebCore::AccessibilityRenderObject::parentObject):
     91        (WebCore::AccessibilityRenderObject::isReadOnly):
     92        (WebCore::AccessibilityRenderObject::helpText):
     93        (WebCore::AccessibilityRenderObject::accessibilityDescription):
     94        (WebCore::AccessibilityRenderObject::text):
     95        (WebCore::AccessibilityRenderObject::contentChanged):
     96        (WebCore):
     97        (WebCore::AccessibilityRenderObject::canHaveChildren):
     98        * accessibility/AccessibilityRenderObject.h:
     99        (AccessibilityRenderObject):
     100
    11012012-09-12  Michael Saboff  <msaboff@apple.com>
    2102
  • trunk/Source/WebCore/accessibility/AccessibilityNodeObject.cpp

    r128353 r128368  
    260260        if (input->isTextButton())
    261261            return buttonRoleType();
     262        if (input->isRangeControl())
     263            return SliderRole;
    262264        return TextFieldRole;
    263265    }
    264266    if (node()->hasTagName(selectTag)) {
    265267        HTMLSelectElement* selectElement = toHTMLSelectElement(node());
    266         return selectElement->multiple() ? ListRole : PopUpButtonRole;
    267     }
     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;
    268280    if (node()->isFocusable())
    269281        return GroupRole;
     
    302314}
    303315
     316bool 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
    304342bool AccessibilityNodeObject::accessibilityIsIgnored() const
    305343{
     344    // If this element is within a parent that cannot have children, it should not be exposed.
     345    if (isDescendantOfBarrenParent())
     346        return true;
     347
    306348    return m_role == UnknownRole;
    307349}
     
    324366}
    325367
     368bool AccessibilityNodeObject::isWebArea() const
     369{
     370    return roleValue() == WebAreaRole;
     371}
     372
     373bool AccessibilityNodeObject::isImageButton() const
     374{
     375    return isNativeImage() && roleValue() == ButtonRole;
     376}
     377
     378bool AccessibilityNodeObject::isAnchor() const
     379{
     380    return !isNativeImage() && isLink();
     381}
     382
     383bool AccessibilityNodeObject::isNativeTextControl() const
     384{
     385    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
     400bool 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
     430bool 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
     450bool AccessibilityNodeObject::isImage() const
     451{
     452    return roleValue() == ImageRole;
     453}
     454
     455bool 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
     471bool 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
     485bool AccessibilityNodeObject::isProgressIndicator() const
     486{
     487    return roleValue() == ProgressIndicatorRole;
     488}
     489
     490bool AccessibilityNodeObject::isSlider() const
     491{
     492    return roleValue() == SliderRole;
     493}
     494
     495bool 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
     508bool AccessibilityNodeObject::isMenu() const
     509{
     510    return roleValue() == MenuRole;
     511}
     512
     513bool AccessibilityNodeObject::isMenuBar() const
     514{
     515    return roleValue() == MenuBarRole;
     516}
     517
     518bool AccessibilityNodeObject::isMenuButton() const
     519{
     520    return roleValue() == MenuButtonRole;
     521}
     522
     523bool AccessibilityNodeObject::isMenuItem() const
     524{
     525    return roleValue() == MenuItemRole;
     526}
     527
     528bool 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
     541bool 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
     553bool 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
     566bool 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
     585bool 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
     608bool AccessibilityNodeObject::isHovered() const
     609{
     610    Node* node = this->node();
     611    if (!node)
     612        return false;
     613
     614    return node->hovered();
     615}
     616
     617bool 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
     628bool 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
     643bool 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
     655int 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
     686String AccessibilityNodeObject::valueDescription() const
     687{
     688    if (!isARIARange())
     689        return String();
     690
     691    return getAttribute(aria_valuetextAttr).string();
     692}
     693
     694bool 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
     707float 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
     721float 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
     735float 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
     749float AccessibilityNodeObject::stepValueForRange() const
     750{
     751    return getAttribute(stepAttr).toFloat();
     752}
     753
     754bool AccessibilityNodeObject::isHeading() const
     755{
     756    return roleValue() == HeadingRole;
     757}
     758
     759bool AccessibilityNodeObject::isLink() const
     760{
     761    return roleValue() == WebCoreLinkRole;
     762}
     763
     764bool 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
     774bool AccessibilityNodeObject::isFieldset() const
     775{
     776    Node* node = this->node();
     777    if (!node)
     778        return false;
     779
     780    return node->hasTagName(fieldsetTag);
     781}
     782
     783bool AccessibilityNodeObject::isGroup() const
     784{
     785    return roleValue() == GroupRole;
     786}
     787
     788AccessibilityObject* 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
     805AccessibilityObject* 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
     824AccessibilityButtonState AccessibilityNodeObject::checkboxOrRadioValue() const
     825{
     826    if (isNativeCheckboxOrRadio())
     827        return isChecked() ? ButtonStateOn : ButtonStateOff;
     828
     829    return AccessibilityObject::checkboxOrRadioValue();
     830}
     831
     832Element* 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
     850Element* 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
     892Element* 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
     914bool 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
     924void 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   
     935void AccessibilityNodeObject::increment()
     936{
     937    alterSliderValue(true);
     938}
     939
     940void AccessibilityNodeObject::decrement()
     941{
     942    alterSliderValue(false);
     943}
     944
     945void 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
     957void 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
     968bool 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
     998HTMLLabelElement* 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
     1013String 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
     1026static 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
     1039Element* AccessibilityNodeObject::menuElementForMenuButton() const
     1040{
     1041    if (ariaRoleAttribute() != MenuButtonRole)
     1042        return 0;
     1043
     1044    return siblingWithAriaRole("menu", node());
     1045}
     1046
     1047AccessibilityObject* AccessibilityNodeObject::menuForMenuButton() const
     1048{
     1049    return axObjectCache()->getOrCreate(menuElementForMenuButton());
     1050}
     1051
     1052Element* AccessibilityNodeObject::menuItemElementForMenu() const
     1053{
     1054    if (ariaRoleAttribute() != MenuRole)
     1055        return 0;
     1056   
     1057    return siblingWithAriaRole("menuitem", node());   
     1058}
     1059
     1060AccessibilityObject* 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
     1073String 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
     1107String 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   
     1147unsigned 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
     1175String 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
     1189String 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
     1237String 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
     1263String 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.                                                                                           
     1305static 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
     1322String 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
     1339void 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
     1367void AccessibilityNodeObject::ariaLabeledByElements(Vector<Element*>& elements) const
     1368{
     1369    elementsFromAttribute(elements, aria_labeledbyAttr);
     1370    if (!elements.size())
     1371        elementsFromAttribute(elements, aria_labelledbyAttr);
     1372}
     1373
     1374
     1375String AccessibilityNodeObject::ariaLabeledByAttribute() const
     1376{
     1377    Vector<Element*> elements;
     1378    ariaLabeledByElements(elements);
     1379
     1380    return accessibilityDescriptionForElements(elements);
     1381}
     1382
    3261383bool AccessibilityNodeObject::canSetFocusAttribute() const
    3271384{
    3281385    Node* node = this->node();
     1386    if (!node)
     1387        return false;
    3291388
    3301389    if (isWebArea())
     
    3371396        return false;
    3381397
    339     if (node->isElementNode() && !static_cast<Element*>(node)->isEnabledFormControl())
     1398    if (node->isElementNode() && !toElement(node)->isEnabledFormControl())
    3401399        return false;
    3411400
  • trunk/Source/WebCore/accessibility/AccessibilityNodeObject.h

    r128353 r128368  
    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
    71107    virtual bool canSetFocusAttribute() const;
    72    
     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 
    73136    virtual AccessibilityObject* firstChild() const;
    74137    virtual AccessibilityObject* lastChild() const;
     
    78141    virtual AccessibilityObject* parentObjectIfExists() const;
    79142
    80     void setNode(Node*);
    81     virtual Node* node() const { return m_node; }
    82     virtual Document* document() const;
    83 
    84143    virtual void detach();
    85144    virtual void childrenChanged();
    86145    virtual void updateAccessibilityRole();
     146
     147    virtual void increment();
     148    virtual void decrement();
    87149
    88150    virtual LayoutRect elementRect() const;
     
    97159    virtual AccessibilityRole determineAccessibilityRole();
    98160    virtual void addChildren();
     161    virtual bool canHaveChildren() const;
    99162    virtual bool accessibilityIsIgnored() const;
    100163    AccessibilityRole ariaRoleAttribute() const;
     
    102165    AccessibilityRole remapAriaRoleDueToParent(AccessibilityRole) const;
    103166    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;
    104181
    105182private:
  • trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp

    r128353 r128368  
    478478    return 0;
    479479}
    480 
    481 bool AccessibilityRenderObject::isWebArea() const
    482 {
    483     return roleValue() == WebAreaRole;
    484 }
    485 
    486 bool AccessibilityRenderObject::isImageButton() const
    487 {
    488     return isNativeImage() && roleValue() == ButtonRole;
    489 }
    490 
    491 bool AccessibilityRenderObject::isAnchor() const
    492 {
    493     return !isNativeImage() && isLink();
    494 }
    495 
    496 bool AccessibilityRenderObject::isNativeTextControl() const
    497 {
    498     return m_renderer->isTextControl();
    499 }
    500    
    501 bool 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    
    530 bool AccessibilityRenderObject::isNativeImage() const
    531 {
    532     return m_renderer->isBoxModelObject() && toRenderBoxModelObject(m_renderer)->isImage();
    533 }   
    534    
    535 bool AccessibilityRenderObject::isImage() const
    536 {
    537     return roleValue() == ImageRole;
    538 }
    539 
     480   
    540481bool AccessibilityRenderObject::isAttachment() const
    541482{
     
    549490}
    550491
    551 bool 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    
    566492bool AccessibilityRenderObject::isFileUploadButton() const
    567493{
     
    574500}
    575501   
    576 bool 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 
    587 bool AccessibilityRenderObject::isProgressIndicator() const
    588 {
    589     return roleValue() == ProgressIndicatorRole;
    590 }
    591 
    592 bool AccessibilityRenderObject::isSlider() const
    593 {
    594     return roleValue() == SliderRole;
    595 }
    596 
    597 bool AccessibilityRenderObject::isMenuRelated() const
    598 {
    599     AccessibilityRole role = roleValue();
    600     return role == MenuRole
    601         || role == MenuBarRole
    602         || role == MenuButtonRole
    603         || role == MenuItemRole;
    604 }   
    605 
    606 bool AccessibilityRenderObject::isMenu() const
    607 {
    608     return roleValue() == MenuRole;
    609 }
    610 
    611 bool AccessibilityRenderObject::isMenuBar() const
    612 {
    613     return roleValue() == MenuBarRole;
    614 }
    615 
    616 bool AccessibilityRenderObject::isMenuButton() const
    617 {
    618     return roleValue() == MenuButtonRole;
    619 }
    620 
    621 bool AccessibilityRenderObject::isMenuItem() const
    622 {
    623     return roleValue() == MenuItemRole;
    624 }
    625      
    626 bool 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 
    646 bool 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 
    659 bool 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    
    671 bool 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 
    696 bool AccessibilityRenderObject::isHovered() const
    697 {
    698     ASSERT(m_renderer);
    699     return m_renderer->node() && m_renderer->node()->hovered();
    700 }
    701 
    702 bool 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 
    717502bool AccessibilityRenderObject::isReadOnly() const
    718503{
     
    731516    }
    732517
    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();
     518    return AccessibilityNodeObject::isReadOnly();
    742519}
    743520
     
    750527    viewRect.intersect(contentRect);
    751528    return viewRect.isEmpty();
    752 }
    753 
    754 int 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 
    785 bool AccessibilityRenderObject::isHeading() const
    786 {
    787     return roleValue() == HeadingRole;
    788 }
    789    
    790 bool AccessibilityRenderObject::isLink() const
    791 {
    792     return roleValue() == WebCoreLinkRole;
    793 }   
    794    
    795 bool 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 
    805 bool AccessibilityRenderObject::isFieldset() const
    806 {
    807     RenderBoxModelObject* renderer = renderBoxModelObject();
    808     if (!renderer)
    809         return false;
    810     return renderer->isFieldset();
    811 }
    812  
    813 bool AccessibilityRenderObject::isGroup() const
    814 {
    815     return roleValue() == GroupRole;
    816 }
    817 
    818 AccessibilityObject* 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 
    835 AccessibilityObject* 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;
    853529}
    854530
     
    882558    }
    883559   
    884     return 0;
    885 }
    886 
    887 Element* 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 
    931 Element* 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 
    953 void 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    
    964 void AccessibilityRenderObject::increment()
    965 {
    966     alterSliderValue(true);
    967 }
    968 
    969 void AccessibilityRenderObject::decrement()
    970 {
    971     alterSliderValue(false);
    972 }
    973 
    974 static 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 
    989 Element* AccessibilityRenderObject::menuElementForMenuButton() const
    990 {
    991     if (ariaRoleAttribute() != MenuButtonRole)
    992         return 0;
    993 
    994     return siblingWithAriaRole("menu", renderer()->node());
    995 }
    996 
    997 AccessibilityObject* AccessibilityRenderObject::menuForMenuButton() const
    998 {
    999     Element* menu = menuElementForMenuButton();
    1000     if (menu && menu->renderer())
    1001         return axObjectCache()->getOrCreate(menu);
    1002     return 0;
    1003 }
    1004 
    1005 Element* AccessibilityRenderObject::menuItemElementForMenu() const
    1006 {
    1007     if (ariaRoleAttribute() != MenuRole)
    1008         return 0;
    1009    
    1010     return siblingWithAriaRole("menuitem", renderer()->node());   
    1011 }
    1012 
    1013 AccessibilityObject* 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     }
    1023560    return 0;
    1024561}
     
    1062599    return String();
    1063600}
    1064    
    1065 unsigned 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 }
    1098601
    1099602static TextIteratorBehavior textIteratorBehaviorForTextRange()
     
    1147650}   
    1148651   
    1149 AccessibilityButtonState AccessibilityRenderObject::checkboxOrRadioValue() const
    1150 {
    1151     if (isNativeCheckboxOrRadio())
    1152         return isChecked() ? ButtonStateOn : ButtonStateOff;
    1153    
    1154     return AccessibilityObject::checkboxOrRadioValue();
    1155 }
    1156 
    1157 String AccessibilityRenderObject::valueDescription() const
    1158 {
    1159     if (!isARIARange())
    1160         return String();
    1161    
    1162     return getAttribute(aria_valuetextAttr).string();
    1163 }
    1164    
    1165 float AccessibilityRenderObject::stepValueForRange() const
    1166 {
    1167     return getAttribute(stepAttr).toFloat();
    1168 }
    1169 
    1170 bool AccessibilityRenderObject::isARIARange() const
    1171 {
    1172     return m_ariaRole == ProgressIndicatorRole
    1173         || m_ariaRole == SliderRole
    1174         || m_ariaRole == ScrollBarRole
    1175         || m_ariaRole == SpinButtonRole;
    1176 }
    1177    
    1178 float AccessibilityRenderObject::valueForRange() const
    1179 {
    1180     if (!isARIARange())
    1181         return 0.0f;
    1182 
    1183     return getAttribute(aria_valuenowAttr).toFloat();
    1184 }
    1185 
    1186 float AccessibilityRenderObject::maxValueForRange() const
    1187 {
    1188     if (!isARIARange())
    1189         return 0.0f;
    1190 
    1191     return getAttribute(aria_valuemaxAttr).toFloat();
    1192 }
    1193 
    1194 float AccessibilityRenderObject::minValueForRange() const
    1195 {
    1196     if (!isARIARange())
    1197         return 0.0f;
    1198 
    1199     return getAttribute(aria_valueminAttr).toFloat();
    1200 }
    1201 
    1202652String AccessibilityRenderObject::stringValue() const
    1203653{
     
    1258708}
    1259709
    1260 // This function implements the ARIA accessible name as described by the Mozilla
    1261 // ARIA Implementer's Guide.
    1262 static 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 
    1279 String 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 
    1296 void 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    
    1323 void AccessibilityRenderObject::ariaLabeledByElements(Vector<Element*>& elements) const
    1324 {
    1325     elementsFromAttribute(elements, aria_labeledbyAttr);
    1326     if (!elements.size())
    1327         elementsFromAttribute(elements, aria_labelledbyAttr);
    1328 }
    1329    
    1330 String AccessibilityRenderObject::ariaLabeledByAttribute() const
    1331 {
    1332     Vector<Element*> elements;
    1333     ariaLabeledByElements(elements);
    1334    
    1335     return accessibilityDescriptionForElements(elements);
    1336 }
    1337 
    1338 static 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    
    1353710HTMLLabelElement* AccessibilityRenderObject::labelElementContainer() const
    1354711{
     
    1369726}
    1370727
    1371 String 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 
    1420728String AccessibilityRenderObject::ariaDescribedByAttribute() const
    1421729{
     
    1426734}
    1427735   
    1428 String 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 
    1441736String AccessibilityRenderObject::webAreaAccessibilityDescription() const
    1442737{
     
    1491786        return String();
    1492787
    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    
    1516788    if (isWebArea())
    1517789        return webAreaAccessibilityDescription();
    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();
     790
     791    return AccessibilityNodeObject::accessibilityDescription();
    1527792}
    1528793
     
    18111076}
    18121077
    1813 bool 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    
    18231078bool AccessibilityRenderObject::isAllowedChildOfTree() const
    18241079{
     
    20601315String AccessibilityRenderObject::text() const
    20611316{
    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 
    20691317    if (isPasswordField())
    20701318        return passwordFieldValue();
    20711319
    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();
     1320    return AccessibilityNodeObject::text();
    20831321}
    20841322   
     
    22381476}
    22391477   
    2240 bool 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 
    22521478bool AccessibilityRenderObject::isSelected() const
    22531479{
     
    23461572}
    23471573
    2348 void 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    
    2360 void 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 
    23711574void AccessibilityRenderObject::setSelectedRows(AccessibilityChildrenVector& selectedRows)
    23721575{
     
    24281631}
    24291632   
    2430 bool 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 
    24441633RenderView* AccessibilityRenderObject::topRenderer() const
    24451634{
     
    31392328}
    31402329
    3141 bool 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    
    31702330AccessibilityRole AccessibilityRenderObject::determineAccessibilityRole()
    31712331{
     
    34382598    }
    34392599}
    3440    
    3441 bool 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 }
    34622600
    34632601void AccessibilityRenderObject::clearChildren()
     
    35972735#endif
    35982736}
    3599        
     2737
     2738bool AccessibilityRenderObject::canHaveChildren() const
     2739{
     2740    if (!m_renderer)
     2741        return false;
     2742
     2743    return AccessibilityNodeObject::canHaveChildren();
     2744}
     2745
    36002746const AtomicString& AccessibilityRenderObject::ariaLiveRegionStatus() const
    36012747{
  • trunk/Source/WebCore/accessibility/AccessibilityRenderObject.h

    r128353 r128368  
    6767    virtual void init();
    6868   
    69     virtual bool isAnchor() const;
    7069    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;
    8070    virtual bool isFileUploadButton() const;
    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;
     71
    9472    virtual bool isSelected() const;
    9573    virtual bool isFocused() const;
    96     virtual bool isChecked() const;
    97     virtual bool isHovered() const;
    98     virtual bool isIndeterminate() const;
    9974    virtual bool isLoaded() const;
    100     virtual bool isMultiSelectable() const;
    10175    virtual bool isOffScreen() const;
    102     virtual bool isPressed() const;
    10376    virtual bool isReadOnly() const;
    10477    virtual bool isUnvisited() const;
    10578    virtual bool isVisited() const;       
    106     virtual bool isRequired() const;
    10779    virtual bool isLinked() const;
    10880    virtual bool hasBoldFont() const;
     
    12496    virtual bool accessibilityIsIgnored() const;
    12597   
    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();
    13598    virtual int layoutCount() const;
    13699    virtual double estimatedLoadingProgress() const;
     
    157120    virtual AccessibilityObject* accessibilityHitTest(const IntPoint&) const;
    158121
    159     virtual Element* actionElement() const;
    160     Element* mouseButtonListener() const;
    161122    FrameView* frameViewIfRenderView() const;
    162123    virtual Element* anchorElement() const;
    163     AccessibilityObject* menuForMenuButton() const;
    164     AccessibilityObject* menuButtonForMenu() const;
    165124   
    166125    virtual LayoutRect boundingBoxRect() const;
     
    185144    virtual VisibleSelection selection() const;
    186145    virtual String stringValue() const;
    187     virtual String ariaLabeledByAttribute() const;
    188     virtual String title() const;
    189146    virtual String ariaDescribedByAttribute() const;
    190147    virtual String accessibilityDescription() const;
     
    200157    virtual void getDocumentLinks(AccessibilityChildrenVector&);
    201158    virtual FrameView* documentFrameView() const;
    202     virtual unsigned hierarchicalLevel() const;
    203159
    204160    virtual void clearChildren();
     
    209165    virtual void setValue(const String&);
    210166    virtual void setSelectedRows(AccessibilityChildrenVector&);
    211     virtual void changeValueByPercent(float percentChange);
    212167    virtual AccessibilityOrientation orientation() const;
    213     virtual void increment();
    214     virtual void decrement();
    215168   
    216169    virtual void detach();
     
    264217   
    265218    void setRenderObject(RenderObject* renderer) { m_renderer = renderer; }
    266     void ariaLabeledByElements(Vector<Element*>& elements) const;
    267219    bool needsToUpdateChildren() const { return m_childrenDirty; }
    268220    ScrollableArea* getScrollableAreaIfScrollable() const;
     
    277229    void ariaListboxVisibleChildren(AccessibilityChildrenVector&);
    278230    bool ariaIsHidden() const;
    279     bool isDescendantOfBarrenParent() const;
    280231    bool isAllowedChildOfTree() const;
    281232    bool hasTextAlternative() const;
     
    286237    virtual void setNeedsToUpdateChildren() { m_childrenDirty = true; }
    287238
    288     Element* menuElementForMenuButton() const;
    289     Element* menuItemElementForMenu() const;
    290 
    291239    bool isTabItemSelected() const;
    292     void alterSliderValue(bool increase);
    293     void changeValueByStep(bool increase);
    294     bool isNativeCheckboxOrRadio() const;
    295240    LayoutRect checkboxOrRadioRect() const;
    296241    void addRadioButtonGroupMembers(AccessibilityChildrenVector& linkedUIElements) const;
     
    302247    bool isDescendantOfElementType(const QualifiedName& tagName) const;
    303248    // 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;
    306249
    307250    void addTextFieldChildren();
     
    318261    void setElementAttributeValue(const QualifiedName&, bool);
    319262   
    320     String accessibilityDescriptionForElements(Vector<Element*> &elements) const;
    321     void elementsFromAttribute(Vector<Element*>& elements, const QualifiedName&) const;
    322     String ariaAccessibilityDescription() const;
    323263    String webAreaAccessibilityDescription() const;
    324264
Note: See TracChangeset for help on using the changeset viewer.