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