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