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