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