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