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