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