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