AX: AOM: Implement number type properties
[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->supportsLiveRegion())
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         if (auto disabled = object->boolValueForProperty(AXPropertyName::Disabled)) {
629             if (disabled.value())
630                 return false;
631             break;
632         }
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(stringValueForProperty(AXPropertyName::Pressed), "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(stringValueForProperty(AXPropertyName::Checked), "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     if (auto multiSelectable = boolValueForProperty(AXPropertyName::Multiselectable))
708         return multiSelectable.value();
709     
710     return node() && node()->hasTagName(selectTag) && downcast<HTMLSelectElement>(*node()).multiple();
711 }
712
713 bool AccessibilityNodeObject::isRequired() const
714 {
715     // Explicit aria-required values should trump native required attributes.
716     if (auto axRequired = boolValueForProperty(AXPropertyName::Required))
717         return axRequired.value();
718
719     Node* n = this->node();
720     if (is<HTMLFormControlElement>(n))
721         return downcast<HTMLFormControlElement>(*n).isRequired();
722
723     return false;
724 }
725
726 bool AccessibilityNodeObject::supportsRequiredAttribute() const
727 {
728     switch (roleValue()) {
729     case AccessibilityRole::Button:
730         return isFileUploadButton();
731     case AccessibilityRole::Cell:
732     case AccessibilityRole::ColumnHeader:
733     case AccessibilityRole::CheckBox:
734     case AccessibilityRole::ComboBox:
735     case AccessibilityRole::Grid:
736     case AccessibilityRole::GridCell:
737     case AccessibilityRole::Incrementor:
738     case AccessibilityRole::ListBox:
739     case AccessibilityRole::PopUpButton:
740     case AccessibilityRole::RadioButton:
741     case AccessibilityRole::RadioGroup:
742     case AccessibilityRole::RowHeader:
743     case AccessibilityRole::Slider:
744     case AccessibilityRole::SpinButton:
745     case AccessibilityRole::TableHeaderContainer:
746     case AccessibilityRole::TextArea:
747     case AccessibilityRole::TextField:
748     case AccessibilityRole::ToggleButton:
749         return true;
750     default:
751         return false;
752     }
753 }
754
755 int AccessibilityNodeObject::headingLevel() const
756 {
757     // headings can be in block flow and non-block flow
758     Node* node = this->node();
759     if (!node)
760         return false;
761
762     if (isHeading()) {
763         int level = unsignedValueForProperty(AXPropertyName::Level);
764         if (level > 0)
765             return level;
766     }
767
768     if (node->hasTagName(h1Tag))
769         return 1;
770
771     if (node->hasTagName(h2Tag))
772         return 2;
773
774     if (node->hasTagName(h3Tag))
775         return 3;
776
777     if (node->hasTagName(h4Tag))
778         return 4;
779
780     if (node->hasTagName(h5Tag))
781         return 5;
782
783     if (node->hasTagName(h6Tag))
784         return 6;
785
786     // The implicit value of aria-level is 2 for the heading role.
787     // https://www.w3.org/TR/wai-aria-1.1/#heading
788     if (ariaRoleAttribute() == AccessibilityRole::Heading)
789         return 2;
790
791     return 0;
792 }
793
794 String AccessibilityNodeObject::valueDescription() const
795 {
796     if (!isRangeControl())
797         return String();
798
799     return stringValueForProperty(AXPropertyName::ValueText);
800 }
801
802 float AccessibilityNodeObject::valueForRange() const
803 {
804     if (is<HTMLInputElement>(node())) {
805         HTMLInputElement& input = downcast<HTMLInputElement>(*node());
806         if (input.isRangeControl())
807             return input.valueAsNumber();
808     }
809
810     if (!isRangeControl())
811         return 0.0f;
812
813     // In ARIA 1.1, the implicit value for aria-valuenow on a spin button is 0.
814     // For other roles, it is half way between aria-valuemin and aria-valuemax.
815     if (hasProperty(AXPropertyName::ValueNow))
816         return doubleValueForProperty(AXPropertyName::ValueNow);
817
818     return isSpinButton() ? 0 : (minValueForRange() + maxValueForRange()) / 2;
819 }
820
821 float AccessibilityNodeObject::maxValueForRange() const
822 {
823     if (is<HTMLInputElement>(node())) {
824         HTMLInputElement& input = downcast<HTMLInputElement>(*node());
825         if (input.isRangeControl())
826             return input.maximum();
827     }
828
829     if (!isRangeControl())
830         return 0.0f;
831
832     if (hasProperty(AXPropertyName::ValueMax))
833         return doubleValueForProperty(AXPropertyName::ValueMax);
834
835     // In ARIA 1.1, the implicit value for aria-valuemax on a spin button
836     // is that there is no maximum value. For other roles, it is 100.
837     return isSpinButton() ? std::numeric_limits<float>::max() : 100.0f;
838 }
839
840 float AccessibilityNodeObject::minValueForRange() const
841 {
842     if (is<HTMLInputElement>(node())) {
843         HTMLInputElement& input = downcast<HTMLInputElement>(*node());
844         if (input.isRangeControl())
845             return input.minimum();
846     }
847
848     if (!isRangeControl())
849         return 0.0f;
850
851     if (hasProperty(AXPropertyName::ValueMin))
852         return doubleValueForProperty(AXPropertyName::ValueMin);
853
854     // In ARIA 1.1, the implicit value for aria-valuemin on a spin button
855     // is that there is no minimum value. For other roles, it is 0.
856     return isSpinButton() ? -std::numeric_limits<float>::max() : 0.0f;
857 }
858
859 float AccessibilityNodeObject::stepValueForRange() const
860 {
861     return getAttribute(stepAttr).toFloat();
862 }
863
864 bool AccessibilityNodeObject::isHeading() const
865 {
866     return roleValue() == AccessibilityRole::Heading;
867 }
868
869 bool AccessibilityNodeObject::isLink() const
870 {
871     return roleValue() == AccessibilityRole::WebCoreLink;
872 }
873
874 bool AccessibilityNodeObject::isControl() const
875 {
876     Node* node = this->node();
877     if (!node)
878         return false;
879
880     return is<HTMLFormControlElement>(*node) || AccessibilityObject::isARIAControl(ariaRoleAttribute());
881 }
882
883 bool AccessibilityNodeObject::isFieldset() const
884 {
885     Node* node = this->node();
886     if (!node)
887         return false;
888
889     return node->hasTagName(fieldsetTag);
890 }
891
892 bool AccessibilityNodeObject::isGroup() const
893 {
894     AccessibilityRole role = roleValue();
895     return role == AccessibilityRole::Group || role == AccessibilityRole::TextGroup || role == AccessibilityRole::ApplicationGroup || role == AccessibilityRole::ApplicationTextGroup;
896 }
897
898 AccessibilityObject* AccessibilityNodeObject::selectedRadioButton()
899 {
900     if (!isRadioGroup())
901         return nullptr;
902
903     // Find the child radio button that is selected (ie. the intValue == 1).
904     for (const auto& child : children()) {
905         if (child->roleValue() == AccessibilityRole::RadioButton && child->checkboxOrRadioValue() == AccessibilityButtonState::On)
906             return child.get();
907     }
908     return nullptr;
909 }
910
911 AccessibilityObject* AccessibilityNodeObject::selectedTabItem()
912 {
913     if (!isTabList())
914         return nullptr;
915
916     // FIXME: Is this valid? ARIA tab items support aria-selected; not aria-checked.
917     // Find the child tab item that is selected (ie. the intValue == 1).
918     AccessibilityObject::AccessibilityChildrenVector tabs;
919     tabChildren(tabs);
920
921     for (const auto& child : children()) {
922         if (child->isTabItem() && (child->isChecked() || child->isSelected()))
923             return child.get();
924     }
925     return nullptr;
926 }
927
928 AccessibilityButtonState AccessibilityNodeObject::checkboxOrRadioValue() const
929 {
930     if (isNativeCheckboxOrRadio())
931         return isIndeterminate() ? AccessibilityButtonState::Mixed : isChecked() ? AccessibilityButtonState::On : AccessibilityButtonState::Off;
932
933     return AccessibilityObject::checkboxOrRadioValue();
934 }
935
936 Element* AccessibilityNodeObject::anchorElement() const
937 {
938     Node* node = this->node();
939     if (!node)
940         return nullptr;
941
942     AXObjectCache* cache = axObjectCache();
943
944     // search up the DOM tree for an anchor element
945     // NOTE: this assumes that any non-image with an anchor is an HTMLAnchorElement
946     for ( ; node; node = node->parentNode()) {
947         if (is<HTMLAnchorElement>(*node) || (node->renderer() && cache->getOrCreate(node->renderer())->isLink()))
948             return downcast<Element>(node);
949     }
950
951     return nullptr;
952 }
953
954 static bool isNodeActionElement(Node* node)
955 {
956     if (is<HTMLInputElement>(*node)) {
957         HTMLInputElement& input = downcast<HTMLInputElement>(*node);
958         if (!input.isDisabledFormControl() && (input.isRadioButton() || input.isCheckbox() || input.isTextButton() || input.isFileUpload() || input.isImageButton()))
959             return true;
960     } else if (node->hasTagName(buttonTag) || node->hasTagName(selectTag))
961         return true;
962
963     return false;
964 }
965     
966 static Element* nativeActionElement(Node* start)
967 {
968     if (!start)
969         return nullptr;
970     
971     // Do a deep-dive to see if any nodes should be used as the action element.
972     // We have to look at Nodes, since this method should only be called on objects that do not have children (like buttons).
973     // It solves the problem when authors put role="button" on a group and leave the actual button inside the group.
974     
975     for (Node* child = start->firstChild(); child; child = child->nextSibling()) {
976         if (isNodeActionElement(child))
977             return downcast<Element>(child);
978
979         if (Element* subChild = nativeActionElement(child))
980             return subChild;
981     }
982     return nullptr;
983 }
984     
985 Element* AccessibilityNodeObject::actionElement() const
986 {
987     Node* node = this->node();
988     if (!node)
989         return nullptr;
990
991     if (isNodeActionElement(node))
992         return downcast<Element>(node);
993     
994     if (AccessibilityObject::isARIAInput(ariaRoleAttribute()))
995         return downcast<Element>(node);
996
997     switch (roleValue()) {
998     case AccessibilityRole::Button:
999     case AccessibilityRole::PopUpButton:
1000     case AccessibilityRole::ToggleButton:
1001     case AccessibilityRole::Tab:
1002     case AccessibilityRole::MenuItem:
1003     case AccessibilityRole::MenuItemCheckbox:
1004     case AccessibilityRole::MenuItemRadio:
1005     case AccessibilityRole::ListItem:
1006         // Check if the author is hiding the real control element inside the ARIA element.
1007         if (Element* nativeElement = nativeActionElement(node))
1008             return nativeElement;
1009         return downcast<Element>(node);
1010     default:
1011         break;
1012     }
1013     
1014     Element* elt = anchorElement();
1015     if (!elt)
1016         elt = mouseButtonListener();
1017     return elt;
1018 }
1019
1020 Element* AccessibilityNodeObject::mouseButtonListener(MouseButtonListenerResultFilter filter) const
1021 {
1022     Node* node = this->node();
1023     if (!node)
1024         return nullptr;
1025
1026     // check if our parent is a mouse button listener
1027     // FIXME: Do the continuation search like anchorElement does
1028     for (auto& element : elementLineage(is<Element>(*node) ? downcast<Element>(node) : node->parentElement())) {
1029         // 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.
1030         // It can cause false positives, where every piece of text is labeled as accepting press actions.
1031         if (element.hasTagName(bodyTag) && isStaticText() && filter == ExcludeBodyElement)
1032             break;
1033         
1034         if (element.hasEventListeners(eventNames().clickEvent) || element.hasEventListeners(eventNames().mousedownEvent) || element.hasEventListeners(eventNames().mouseupEvent))
1035             return &element;
1036     }
1037
1038     return nullptr;
1039 }
1040
1041 bool AccessibilityNodeObject::isDescendantOfBarrenParent() const
1042 {
1043     if (!m_isIgnoredFromParentData.isNull())
1044         return m_isIgnoredFromParentData.isDescendantOfBarrenParent;
1045     
1046     for (AccessibilityObject* object = parentObject(); object; object = object->parentObject()) {
1047         if (!object->canHaveChildren())
1048             return true;
1049     }
1050
1051     return false;
1052 }
1053
1054 void AccessibilityNodeObject::alterSliderValue(bool increase)
1055 {
1056     if (roleValue() != AccessibilityRole::Slider)
1057         return;
1058
1059     if (!getAttribute(stepAttr).isEmpty())
1060         changeValueByStep(increase);
1061     else
1062         changeValueByPercent(increase ? 5 : -5);
1063 }
1064     
1065 void AccessibilityNodeObject::increment()
1066 {
1067     UserGestureIndicator gestureIndicator(ProcessingUserGesture, document());
1068     alterSliderValue(true);
1069 }
1070
1071 void AccessibilityNodeObject::decrement()
1072 {
1073     UserGestureIndicator gestureIndicator(ProcessingUserGesture, document());
1074     alterSliderValue(false);
1075 }
1076
1077 void AccessibilityNodeObject::changeValueByStep(bool increase)
1078 {
1079     float step = stepValueForRange();
1080     float value = valueForRange();
1081
1082     value += increase ? step : -step;
1083
1084     setValue(String::number(value));
1085
1086     axObjectCache()->postNotification(node(), AXObjectCache::AXValueChanged);
1087 }
1088
1089 void AccessibilityNodeObject::changeValueByPercent(float percentChange)
1090 {
1091     float range = maxValueForRange() - minValueForRange();
1092     float step = range * (percentChange / 100);
1093     float value = valueForRange();
1094
1095     // Make sure the specified percent will cause a change of one integer step or larger.
1096     if (fabs(step) < 1)
1097         step = fabs(percentChange) * (1 / percentChange);
1098
1099     value += step;
1100     setValue(String::number(value));
1101
1102     axObjectCache()->postNotification(node(), AXObjectCache::AXValueChanged);
1103 }
1104
1105 bool AccessibilityNodeObject::isGenericFocusableElement() const
1106 {
1107     if (!canSetFocusAttribute())
1108         return false;
1109
1110     // If it's a control, it's not generic.
1111     if (isControl())
1112         return false;
1113     
1114     AccessibilityRole role = roleValue();
1115     if (role == AccessibilityRole::Video || role == AccessibilityRole::Audio)
1116         return false;
1117
1118     // If it has an aria role, it's not generic.
1119     if (m_ariaRole != AccessibilityRole::Unknown)
1120         return false;
1121
1122     // If the content editable attribute is set on this element, that's the reason
1123     // it's focusable, and existing logic should handle this case already - so it's not a
1124     // generic focusable element.
1125
1126     if (hasContentEditableAttributeSet())
1127         return false;
1128
1129     // The web area and body element are both focusable, but existing logic handles these
1130     // cases already, so we don't need to include them here.
1131     if (role == AccessibilityRole::WebArea)
1132         return false;
1133     if (node() && node()->hasTagName(bodyTag))
1134         return false;
1135
1136     // An SVG root is focusable by default, but it's probably not interactive, so don't
1137     // include it. It can still be made accessible by giving it an ARIA role.
1138     if (role == AccessibilityRole::SVGRoot)
1139         return false;
1140
1141     return true;
1142 }
1143
1144 HTMLLabelElement* AccessibilityNodeObject::labelForElement(Element* element) const
1145 {
1146     if (!is<HTMLElement>(*element) || !downcast<HTMLElement>(*element).isLabelable())
1147         return nullptr;
1148
1149     const AtomicString& id = element->getIdAttribute();
1150     if (!id.isEmpty()) {
1151         if (HTMLLabelElement* label = element->treeScope().labelElementForId(id))
1152             return label;
1153     }
1154
1155     return ancestorsOfType<HTMLLabelElement>(*element).first();
1156 }
1157
1158 String AccessibilityNodeObject::ariaAccessibilityDescription() const
1159 {
1160     String ariaLabeledBy = ariaLabeledByAttribute();
1161     if (!ariaLabeledBy.isEmpty())
1162         return ariaLabeledBy;
1163
1164     const AtomicString& ariaLabel = stringValueForProperty(AXPropertyName::Label);
1165     if (!ariaLabel.isEmpty())
1166         return ariaLabel;
1167
1168     return String();
1169 }
1170
1171 static Element* siblingWithAriaRole(Node* node, const char* role)
1172 {
1173     // FIXME: Either we should add a null check here or change the function to take a reference instead of a pointer.
1174     ContainerNode* parent = node->parentNode();
1175     if (!parent)
1176         return nullptr;
1177
1178     for (auto& sibling : childrenOfType<Element>(*parent)) {
1179         // FIXME: Should skip sibling that is the same as the node.
1180         if (equalIgnoringASCIICase(AccessibleNode::effectiveStringValueForElement(sibling, AXPropertyName::Role), role))
1181             return &sibling;
1182     }
1183
1184     return nullptr;
1185 }
1186
1187 Element* AccessibilityNodeObject::menuElementForMenuButton() const
1188 {
1189     if (ariaRoleAttribute() != AccessibilityRole::MenuButton)
1190         return nullptr;
1191
1192     return siblingWithAriaRole(node(), "menu");
1193 }
1194
1195 AccessibilityObject* AccessibilityNodeObject::menuForMenuButton() const
1196 {
1197     if (AXObjectCache* cache = axObjectCache())
1198         return cache->getOrCreate(menuElementForMenuButton());
1199     return nullptr;
1200 }
1201
1202 Element* AccessibilityNodeObject::menuItemElementForMenu() const
1203 {
1204     if (ariaRoleAttribute() != AccessibilityRole::Menu)
1205         return nullptr;
1206     
1207     return siblingWithAriaRole(node(), "menuitem");
1208 }
1209
1210 AccessibilityObject* AccessibilityNodeObject::menuButtonForMenu() const
1211 {
1212     AXObjectCache* cache = axObjectCache();
1213     if (!cache)
1214         return nullptr;
1215
1216     Element* menuItem = menuItemElementForMenu();
1217
1218     if (menuItem) {
1219         // ARIA just has generic menu items. AppKit needs to know if this is a top level items like MenuBarButton or MenuBarItem
1220         AccessibilityObject* menuItemAX = cache->getOrCreate(menuItem);
1221         if (menuItemAX && menuItemAX->isMenuButton())
1222             return menuItemAX;
1223     }
1224     return nullptr;
1225 }
1226
1227 AccessibilityObject* AccessibilityNodeObject::captionForFigure() const
1228 {
1229     if (!isFigureElement())
1230         return nullptr;
1231     
1232     AXObjectCache* cache = axObjectCache();
1233     if (!cache)
1234         return nullptr;
1235     
1236     Node* node = this->node();
1237     for (Node* child = node->firstChild(); child; child = child->nextSibling()) {
1238         if (child->hasTagName(figcaptionTag))
1239             return cache->getOrCreate(child);
1240     }
1241     return nullptr;
1242 }
1243
1244 bool AccessibilityNodeObject::usesAltTagForTextComputation() const
1245 {
1246     return isImage() || isInputImage() || isNativeImage() || isCanvas() || (node() && node()->hasTagName(imgTag));
1247 }
1248
1249 bool AccessibilityNodeObject::isLabelable() const
1250 {
1251     Node* node = this->node();
1252     if (!node)
1253         return false;
1254     
1255     return is<HTMLInputElement>(*node) || AccessibilityObject::isARIAInput(ariaRoleAttribute()) || isControl() || isProgressIndicator() || isMeter();
1256 }
1257
1258 String AccessibilityNodeObject::textForLabelElement(Element* element) const
1259 {
1260     String result = String();
1261     if (!is<HTMLLabelElement>(*element))
1262         return result;
1263     
1264     HTMLLabelElement* label = downcast<HTMLLabelElement>(element);
1265     // Check to see if there's aria-labelledby attribute on the label element.
1266     if (AccessibilityObject* labelObject = axObjectCache()->getOrCreate(label))
1267         result = labelObject->ariaLabeledByAttribute();
1268     
1269     // Then check for aria-label attribute.
1270     if (result.isEmpty())
1271         result = AccessibleNode::effectiveStringValueForElement(*label, AXPropertyName::Label);
1272     
1273     return !result.isEmpty() ? result : label->innerText();
1274 }
1275     
1276 void AccessibilityNodeObject::titleElementText(Vector<AccessibilityText>& textOrder) const
1277 {
1278     Node* node = this->node();
1279     if (!node)
1280         return;
1281     
1282     if (isLabelable()) {
1283         if (HTMLLabelElement* label = labelForElement(downcast<Element>(node))) {
1284             AccessibilityObject* labelObject = axObjectCache()->getOrCreate(label);
1285             String innerText = textForLabelElement(label);
1286             
1287             // Only use the <label> text if there's no ARIA override.
1288             if (!innerText.isEmpty() && !ariaAccessibilityDescription())
1289                 textOrder.append(AccessibilityText(innerText, isMeter() ? AccessibilityTextSource::Alternative : AccessibilityTextSource::LabelByElement, labelObject));
1290             return;
1291         }
1292     }
1293     
1294     AccessibilityObject* titleUIElement = this->titleUIElement();
1295     if (titleUIElement)
1296         textOrder.append(AccessibilityText(String(), AccessibilityTextSource::LabelByElement, titleUIElement));
1297 }
1298
1299 void AccessibilityNodeObject::alternativeText(Vector<AccessibilityText>& textOrder) const
1300 {
1301     if (isWebArea()) {
1302         String webAreaText = alternativeTextForWebArea();
1303         if (!webAreaText.isEmpty())
1304             textOrder.append(AccessibilityText(webAreaText, AccessibilityTextSource::Alternative));
1305         return;
1306     }
1307     
1308     ariaLabeledByText(textOrder);
1309     
1310     const AtomicString& ariaLabel = stringValueForProperty(AXPropertyName::Label);
1311     if (!ariaLabel.isEmpty())
1312         textOrder.append(AccessibilityText(ariaLabel, AccessibilityTextSource::Alternative));
1313     
1314     if (usesAltTagForTextComputation()) {
1315         if (is<RenderImage>(renderer())) {
1316             String renderAltText = downcast<RenderImage>(*renderer()).altText();
1317
1318             // RenderImage will return title as a fallback from altText, but we don't want title here because we consider that in helpText.
1319             if (!renderAltText.isEmpty() && renderAltText != getAttribute(titleAttr)) {
1320                 textOrder.append(AccessibilityText(renderAltText, AccessibilityTextSource::Alternative));
1321                 return;
1322             }
1323         }
1324         // Images should use alt as long as the attribute is present, even if empty.
1325         // Otherwise, it should fallback to other methods, like the title attribute.
1326         const AtomicString& alt = getAttribute(altAttr);
1327         if (!alt.isEmpty())
1328             textOrder.append(AccessibilityText(alt, AccessibilityTextSource::Alternative));
1329     }
1330     
1331     Node* node = this->node();
1332     if (!node)
1333         return;
1334     
1335     // The fieldset element derives its alternative text from the first associated legend element if one is available.
1336     if (is<HTMLFieldSetElement>(*node)) {
1337         AccessibilityObject* object = axObjectCache()->getOrCreate(downcast<HTMLFieldSetElement>(*node).legend());
1338         if (object && !object->isHidden())
1339             textOrder.append(AccessibilityText(accessibleNameForNode(object->node()), AccessibilityTextSource::Alternative));
1340     }
1341     
1342     // The figure element derives its alternative text from the first associated figcaption element if one is available.
1343     if (isFigureElement()) {
1344         AccessibilityObject* captionForFigure = this->captionForFigure();
1345         if (captionForFigure && !captionForFigure->isHidden())
1346             textOrder.append(AccessibilityText(accessibleNameForNode(captionForFigure->node()), AccessibilityTextSource::Alternative));
1347     }
1348     
1349     // Tree items missing a label are labeled by all child elements.
1350     if (isTreeItem() && ariaLabel.isEmpty() && ariaLabeledByAttribute().isEmpty())
1351         textOrder.append(AccessibilityText(accessibleNameForNode(node), AccessibilityTextSource::Alternative));
1352     
1353 #if ENABLE(MATHML)
1354     if (node->isMathMLElement())
1355         textOrder.append(AccessibilityText(getAttribute(MathMLNames::alttextAttr), AccessibilityTextSource::Alternative));
1356 #endif
1357 }
1358
1359 void AccessibilityNodeObject::visibleText(Vector<AccessibilityText>& textOrder) const
1360 {
1361     Node* node = this->node();
1362     if (!node)
1363         return;
1364     
1365     bool isInputTag = is<HTMLInputElement>(*node);
1366     if (isInputTag) {
1367         HTMLInputElement& input = downcast<HTMLInputElement>(*node);
1368         if (input.isTextButton()) {
1369             textOrder.append(AccessibilityText(input.valueWithDefault(), AccessibilityTextSource::Visible));
1370             return;
1371         }
1372     }
1373     
1374     // If this node isn't rendered, there's no inner text we can extract from a select element.
1375     if (!isAccessibilityRenderObject() && node->hasTagName(selectTag))
1376         return;
1377     
1378     bool useTextUnderElement = false;
1379     
1380     switch (roleValue()) {
1381     case AccessibilityRole::PopUpButton:
1382         // Native popup buttons should not use their button children's text as a title. That value is retrieved through stringValue().
1383         if (node->hasTagName(selectTag))
1384             break;
1385         FALLTHROUGH;
1386     case AccessibilityRole::Button:
1387     case AccessibilityRole::ToggleButton:
1388     case AccessibilityRole::CheckBox:
1389     case AccessibilityRole::ListBoxOption:
1390     // MacOS does not expect native <li> elements to expose label information, it only expects leaf node elements to do that.
1391 #if !PLATFORM(COCOA)
1392     case AccessibilityRole::ListItem:
1393 #endif
1394     case AccessibilityRole::MenuButton:
1395     case AccessibilityRole::MenuItem:
1396     case AccessibilityRole::MenuItemCheckbox:
1397     case AccessibilityRole::MenuItemRadio:
1398     case AccessibilityRole::RadioButton:
1399     case AccessibilityRole::Switch:
1400     case AccessibilityRole::Tab:
1401         useTextUnderElement = true;
1402         break;
1403     default:
1404         break;
1405     }
1406     
1407     // If it's focusable but it's not content editable or a known control type, then it will appear to
1408     // the user as a single atomic object, so we should use its text as the default title.
1409     if (isHeading() || isLink())
1410         useTextUnderElement = true;
1411     
1412     if (isOutput())
1413         useTextUnderElement = true;
1414     
1415     if (useTextUnderElement) {
1416         AccessibilityTextUnderElementMode mode;
1417         
1418         // Headings often include links as direct children. Those links need to be included in text under element.
1419         if (isHeading())
1420             mode.includeFocusableContent = true;
1421
1422         String text = textUnderElement(mode);
1423         if (!text.isEmpty())
1424             textOrder.append(AccessibilityText(text, AccessibilityTextSource::Children));
1425     }
1426 }
1427
1428 void AccessibilityNodeObject::helpText(Vector<AccessibilityText>& textOrder) const
1429 {
1430     const AtomicString& ariaHelp = getAttribute(aria_helpAttr);
1431     if (!ariaHelp.isEmpty())
1432         textOrder.append(AccessibilityText(ariaHelp, AccessibilityTextSource::Help));
1433     
1434     String describedBy = ariaDescribedByAttribute();
1435     if (!describedBy.isEmpty())
1436         textOrder.append(AccessibilityText(describedBy, AccessibilityTextSource::Summary));
1437
1438     // Summary attribute used as help text on tables.
1439     const AtomicString& summary = getAttribute(summaryAttr);
1440     if (!summary.isEmpty())
1441         textOrder.append(AccessibilityText(summary, AccessibilityTextSource::Summary));
1442
1443     // The title attribute should be used as help text unless it is already being used as descriptive text.
1444     // However, when the title attribute is the only text alternative provided, it may be exposed as the
1445     // descriptive text. This is problematic in the case of meters because the HTML spec suggests authors
1446     // can expose units through this attribute. Therefore, if the element is a meter, change its source
1447     // type to AccessibilityTextSource::Help.
1448     const AtomicString& title = getAttribute(titleAttr);
1449     if (!title.isEmpty()) {
1450         if (!isMeter() && !roleIgnoresTitle())
1451             textOrder.append(AccessibilityText(title, AccessibilityTextSource::TitleTag));
1452         else
1453             textOrder.append(AccessibilityText(title, AccessibilityTextSource::Help));
1454     }
1455 }
1456
1457 void AccessibilityNodeObject::accessibilityText(Vector<AccessibilityText>& textOrder)
1458 {
1459     titleElementText(textOrder);
1460     alternativeText(textOrder);
1461     visibleText(textOrder);
1462     helpText(textOrder);
1463     
1464     String placeholder = placeholderValue();
1465     if (!placeholder.isEmpty())
1466         textOrder.append(AccessibilityText(placeholder, AccessibilityTextSource::Placeholder));
1467 }
1468     
1469 void AccessibilityNodeObject::ariaLabeledByText(Vector<AccessibilityText>& textOrder) const
1470 {
1471     String ariaLabeledBy = ariaLabeledByAttribute();
1472     if (!ariaLabeledBy.isEmpty()) {
1473         Vector<Element*> elements;
1474         ariaLabeledByElements(elements);
1475         
1476         Vector<RefPtr<AccessibilityObject>> axElements;
1477         for (const auto& element : elements)
1478             axElements.append(axObjectCache()->getOrCreate(element));
1479         
1480         textOrder.append(AccessibilityText(ariaLabeledBy, AccessibilityTextSource::Alternative, WTFMove(axElements)));
1481     }
1482 }
1483     
1484 String AccessibilityNodeObject::alternativeTextForWebArea() const
1485 {
1486     // The WebArea description should follow this order:
1487     //     aria-label on the <html>
1488     //     title on the <html>
1489     //     <title> inside the <head> (of it was set through JS)
1490     //     name on the <html>
1491     // For iframes:
1492     //     aria-label on the <iframe>
1493     //     title on the <iframe>
1494     //     name on the <iframe>
1495     
1496     Document* document = this->document();
1497     if (!document)
1498         return String();
1499     
1500     // Check if the HTML element has an aria-label for the webpage.
1501     if (Element* documentElement = document->documentElement()) {
1502         const AtomicString& ariaLabel = AccessibleNode::effectiveStringValueForElement(*documentElement, AXPropertyName::Label);
1503         if (!ariaLabel.isEmpty())
1504             return ariaLabel;
1505     }
1506     
1507     if (auto* owner = document->ownerElement()) {
1508         if (owner->hasTagName(frameTag) || owner->hasTagName(iframeTag)) {
1509             const AtomicString& title = owner->attributeWithoutSynchronization(titleAttr);
1510             if (!title.isEmpty())
1511                 return title;
1512         }
1513         return owner->getNameAttribute();
1514     }
1515     
1516     String documentTitle = document->title();
1517     if (!documentTitle.isEmpty())
1518         return documentTitle;
1519     
1520     if (auto* body = document->bodyOrFrameset())
1521         return body->getNameAttribute();
1522     
1523     return String();
1524 }
1525     
1526 String AccessibilityNodeObject::accessibilityDescription() const
1527 {
1528     // Static text should not have a description, it should only have a stringValue.
1529     if (roleValue() == AccessibilityRole::StaticText)
1530         return String();
1531
1532     String ariaDescription = ariaAccessibilityDescription();
1533     if (!ariaDescription.isEmpty())
1534         return ariaDescription;
1535
1536     if (usesAltTagForTextComputation()) {
1537         // Images should use alt as long as the attribute is present, even if empty.                    
1538         // Otherwise, it should fallback to other methods, like the title attribute.                    
1539         const AtomicString& alt = getAttribute(altAttr);
1540         if (!alt.isNull())
1541             return alt;
1542     }
1543     
1544 #if ENABLE(MATHML)
1545     if (is<MathMLElement>(m_node))
1546         return getAttribute(MathMLNames::alttextAttr);
1547 #endif
1548
1549     // An element's descriptive text is comprised of title() (what's visible on the screen) and accessibilityDescription() (other descriptive text).
1550     // Both are used to generate what a screen reader speaks.                                                           
1551     // If this point is reached (i.e. there's no accessibilityDescription) and there's no title(), we should fallback to using the title attribute.
1552     // 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).
1553     // 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.
1554     if (title().isEmpty() && !roleIgnoresTitle())
1555         return getAttribute(titleAttr);
1556
1557     return String();
1558 }
1559
1560 // Returns whether the role was not intended to play a semantically meaningful part of the
1561 // accessibility hierarchy. This applies to generic groups like <div>'s with no role value set.
1562 bool AccessibilityNodeObject::roleIgnoresTitle() const
1563 {
1564     if (ariaRoleAttribute() != AccessibilityRole::Unknown)
1565         return false;
1566
1567     switch (roleValue()) {
1568     case AccessibilityRole::Div:
1569     case AccessibilityRole::Unknown:
1570         return true;
1571     default:
1572         return false;
1573     }
1574 }
1575
1576 String AccessibilityNodeObject::helpText() const
1577 {
1578     Node* node = this->node();
1579     if (!node)
1580         return String();
1581     
1582     const AtomicString& ariaHelp = getAttribute(aria_helpAttr);
1583     if (!ariaHelp.isEmpty())
1584         return ariaHelp;
1585     
1586     String describedBy = ariaDescribedByAttribute();
1587     if (!describedBy.isEmpty())
1588         return describedBy;
1589     
1590     String description = accessibilityDescription();
1591     for (Node* ancestor = node; ancestor; ancestor = ancestor->parentNode()) {
1592         if (is<HTMLElement>(*ancestor)) {
1593             HTMLElement& element = downcast<HTMLElement>(*ancestor);
1594             const AtomicString& summary = element.getAttribute(summaryAttr);
1595             if (!summary.isEmpty())
1596                 return summary;
1597             
1598             // The title attribute should be used as help text unless it is already being used as descriptive text.
1599             const AtomicString& title = element.getAttribute(titleAttr);
1600             if (!title.isEmpty() && description != title)
1601                 return title;
1602         }
1603         
1604         // Only take help text from an ancestor element if its a group or an unknown role. If help was 
1605         // added to those kinds of elements, it is likely it was meant for a child element.
1606         if (AccessibilityObject* axObj = axObjectCache()->getOrCreate(ancestor)) {
1607             if (!axObj->isGroup() && axObj->roleValue() != AccessibilityRole::Unknown)
1608                 break;
1609         }
1610     }
1611     
1612     return String();
1613 }
1614     
1615 unsigned AccessibilityNodeObject::hierarchicalLevel() const
1616 {
1617     Node* node = this->node();
1618     if (!is<Element>(node))
1619         return 0;
1620     if (hasProperty(AXPropertyName::Level))
1621         return unsignedValueForProperty(AXPropertyName::Level);
1622     
1623     // Only tree item will calculate its level through the DOM currently.
1624     if (roleValue() != AccessibilityRole::TreeItem)
1625         return 0;
1626     
1627     // Hierarchy leveling starts at 1, to match the aria-level spec.
1628     // We measure tree hierarchy by the number of groups that the item is within.
1629     unsigned level = 1;
1630     for (AccessibilityObject* parent = parentObject(); parent; parent = parent->parentObject()) {
1631         AccessibilityRole parentRole = parent->ariaRoleAttribute();
1632         if (parentRole == AccessibilityRole::ApplicationGroup)
1633             level++;
1634         else if (parentRole == AccessibilityRole::Tree)
1635             break;
1636     }
1637     
1638     return level;
1639 }
1640
1641 void AccessibilityNodeObject::setIsExpanded(bool expand)
1642 {
1643     if (is<HTMLDetailsElement>(node())) {
1644         auto& details = downcast<HTMLDetailsElement>(*node());
1645         if (expand != details.isOpen())
1646             details.toggleOpen();
1647     }
1648 }
1649     
1650 // When building the textUnderElement for an object, determine whether or not
1651 // we should include the inner text of this given descendant object or skip it.
1652 static bool shouldUseAccessibilityObjectInnerText(AccessibilityObject* obj, AccessibilityTextUnderElementMode mode)
1653 {
1654     // Do not use any heuristic if we are explicitly asking to include all the children.
1655     if (mode.childrenInclusion == AccessibilityTextUnderElementMode::TextUnderElementModeIncludeAllChildren)
1656         return true;
1657
1658     // Consider this hypothetical example:
1659     // <div tabindex=0>
1660     //   <h2>
1661     //     Table of contents
1662     //   </h2>
1663     //   <a href="#start">Jump to start of book</a>
1664     //   <ul>
1665     //     <li><a href="#1">Chapter 1</a></li>
1666     //     <li><a href="#1">Chapter 2</a></li>
1667     //   </ul>
1668     // </div>
1669     //
1670     // The goal is to return a reasonable title for the outer container div, because
1671     // it's focusable - but without making its title be the full inner text, which is
1672     // quite long. As a heuristic, skip links, controls, and elements that are usually
1673     // containers with lots of children.
1674
1675     // ARIA states that certain elements are not allowed to expose their children content for name calculation.
1676     if (mode.childrenInclusion == AccessibilityTextUnderElementMode::TextUnderElementModeIncludeNameFromContentsChildren
1677         && !obj->accessibleNameDerivesFromContent())
1678         return false;
1679     
1680     if (obj->boolValueForProperty(AXPropertyName::Hidden).value())
1681         return false;
1682     
1683     // If something doesn't expose any children, then we can always take the inner text content.
1684     // This is what we want when someone puts an <a> inside a <button> for example.
1685     if (obj->isDescendantOfBarrenParent())
1686         return true;
1687     
1688     // Skip focusable children, so we don't include the text of links and controls.
1689     if (obj->canSetFocusAttribute() && !mode.includeFocusableContent)
1690         return false;
1691
1692     // Skip big container elements like lists, tables, etc.
1693     if (is<AccessibilityList>(*obj))
1694         return false;
1695
1696     if (is<AccessibilityTable>(*obj) && downcast<AccessibilityTable>(*obj).isExposableThroughAccessibility())
1697         return false;
1698
1699     if (obj->isTree() || obj->isCanvas())
1700         return false;
1701
1702     return true;
1703 }
1704
1705 static bool shouldAddSpaceBeforeAppendingNextElement(StringBuilder& builder, const String& childText)
1706 {
1707     if (!builder.length() || !childText.length())
1708         return false;
1709
1710     // We don't need to add an additional space before or after a line break.
1711     return !(isHTMLLineBreak(childText[0]) || isHTMLLineBreak(builder[builder.length() - 1]));
1712 }
1713     
1714 static void appendNameToStringBuilder(StringBuilder& builder, const String& text)
1715 {
1716     if (shouldAddSpaceBeforeAppendingNextElement(builder, text))
1717         builder.append(' ');
1718     builder.append(text);
1719 }
1720
1721 String AccessibilityNodeObject::textUnderElement(AccessibilityTextUnderElementMode mode) const
1722 {
1723     Node* node = this->node();
1724     if (is<Text>(node))
1725         return downcast<Text>(*node).wholeText();
1726
1727     StringBuilder builder;
1728     for (AccessibilityObject* child = firstChild(); child; child = child->nextSibling()) {
1729         if (mode.ignoredChildNode && child->node() == mode.ignoredChildNode)
1730             continue;
1731         
1732         bool shouldDeriveNameFromAuthor = (mode.childrenInclusion == AccessibilityTextUnderElementMode::TextUnderElementModeIncludeNameFromContentsChildren && !child->accessibleNameDerivesFromContent());
1733         if (shouldDeriveNameFromAuthor) {
1734             appendNameToStringBuilder(builder, accessibleNameForNode(child->node()));
1735             continue;
1736         }
1737         
1738         if (!shouldUseAccessibilityObjectInnerText(child, mode))
1739             continue;
1740
1741         if (is<AccessibilityNodeObject>(*child)) {
1742             // We should ignore the child if it's labeled by this node.
1743             // This could happen when this node labels multiple child nodes and we didn't
1744             // skip in the above ignoredChildNode check.
1745             Vector<Element*> labeledByElements;
1746             downcast<AccessibilityNodeObject>(*child).ariaLabeledByElements(labeledByElements);
1747             if (labeledByElements.contains(node))
1748                 continue;
1749             
1750             Vector<AccessibilityText> textOrder;
1751             downcast<AccessibilityNodeObject>(*child).alternativeText(textOrder);
1752             if (textOrder.size() > 0 && textOrder[0].text.length()) {
1753                 appendNameToStringBuilder(builder, textOrder[0].text);
1754                 continue;
1755             }
1756         }
1757         
1758         String childText = child->textUnderElement(mode);
1759         if (childText.length())
1760             appendNameToStringBuilder(builder, childText);
1761     }
1762
1763     return builder.toString().stripWhiteSpace().simplifyWhiteSpace(isHTMLSpaceButNotLineBreak);
1764 }
1765
1766 String AccessibilityNodeObject::title() const
1767 {
1768     Node* node = this->node();
1769     if (!node)
1770         return String();
1771
1772     bool isInputTag = is<HTMLInputElement>(*node);
1773     if (isInputTag) {
1774         HTMLInputElement& input = downcast<HTMLInputElement>(*node);
1775         if (input.isTextButton())
1776             return input.valueWithDefault();
1777     }
1778
1779     if (isLabelable()) {
1780         HTMLLabelElement* label = labelForElement(downcast<Element>(node));
1781         // Use the label text as the title if 1) the title element is NOT an exposed element and 2) there's no ARIA override.
1782         if (label && !exposesTitleUIElement() && !ariaAccessibilityDescription().length())
1783             return textForLabelElement(label);
1784     }
1785
1786     // If this node isn't rendered, there's no inner text we can extract from a select element.
1787     if (!isAccessibilityRenderObject() && node->hasTagName(selectTag))
1788         return String();
1789
1790     switch (roleValue()) {
1791     case AccessibilityRole::PopUpButton:
1792         // Native popup buttons should not use their button children's text as a title. That value is retrieved through stringValue().
1793         if (node->hasTagName(selectTag))
1794             return String();
1795         FALLTHROUGH;
1796     case AccessibilityRole::Button:
1797     case AccessibilityRole::ToggleButton:
1798     case AccessibilityRole::CheckBox:
1799     case AccessibilityRole::ListBoxOption:
1800     case AccessibilityRole::ListItem:
1801     case AccessibilityRole::MenuButton:
1802     case AccessibilityRole::MenuItem:
1803     case AccessibilityRole::MenuItemCheckbox:
1804     case AccessibilityRole::MenuItemRadio:
1805     case AccessibilityRole::RadioButton:
1806     case AccessibilityRole::Switch:
1807     case AccessibilityRole::Tab:
1808         return textUnderElement();
1809     // SVGRoots should not use the text under itself as a title. That could include the text of objects like <text>.
1810     case AccessibilityRole::SVGRoot:
1811         return String();
1812     default:
1813         break;
1814     }
1815
1816     if (isLink())
1817         return textUnderElement();
1818     if (isHeading())
1819         return textUnderElement(AccessibilityTextUnderElementMode(AccessibilityTextUnderElementMode::TextUnderElementModeSkipIgnoredChildren, true));
1820
1821     return String();
1822 }
1823
1824 String AccessibilityNodeObject::text() const
1825 {
1826     // If this is a user defined static text, use the accessible name computation.                                      
1827     if (isARIAStaticText()) {
1828         Vector<AccessibilityText> textOrder;
1829         alternativeText(textOrder);
1830         if (textOrder.size() > 0 && textOrder[0].text.length())
1831             return textOrder[0].text;
1832     }
1833
1834     if (!isTextControl())
1835         return String();
1836
1837     Node* node = this->node();
1838     if (!node)
1839         return String();
1840
1841     if (isNativeTextControl() && is<HTMLTextFormControlElement>(*node))
1842         return downcast<HTMLTextFormControlElement>(*node).value();
1843
1844     if (!node->isElementNode())
1845         return String();
1846
1847     return downcast<Element>(node)->innerText();
1848 }
1849
1850 String AccessibilityNodeObject::stringValue() const
1851 {
1852     Node* node = this->node();
1853     if (!node)
1854         return String();
1855
1856     if (isARIAStaticText()) {
1857         String staticText = text();
1858         if (!staticText.length())
1859             staticText = textUnderElement();
1860         return staticText;
1861     }
1862
1863     if (node->isTextNode())
1864         return textUnderElement();
1865
1866     if (node->hasTagName(selectTag)) {
1867         HTMLSelectElement& selectElement = downcast<HTMLSelectElement>(*node);
1868         int selectedIndex = selectElement.selectedIndex();
1869         const Vector<HTMLElement*>& listItems = selectElement.listItems();
1870         if (selectedIndex >= 0 && static_cast<size_t>(selectedIndex) < listItems.size()) {
1871             const AtomicString& overriddenDescription = AccessibleNode::effectiveStringValueForElement(*listItems[selectedIndex], AXPropertyName::Label);
1872             if (!overriddenDescription.isNull())
1873                 return overriddenDescription;
1874         }
1875         if (!selectElement.multiple())
1876             return selectElement.value();
1877         return String();
1878     }
1879
1880     if (isTextControl())
1881         return text();
1882
1883     // FIXME: We might need to implement a value here for more types
1884     // FIXME: It would be better not to advertise a value at all for the types for which we don't implement one;
1885     // this would require subclassing or making accessibilityAttributeNames do something other than return a
1886     // single static array.
1887     return String();
1888 }
1889
1890 void AccessibilityNodeObject::colorValue(int& r, int& g, int& b) const
1891 {
1892     r = 0;
1893     g = 0;
1894     b = 0;
1895
1896 #if ENABLE(INPUT_TYPE_COLOR)
1897     if (!isColorWell())
1898         return;
1899
1900     if (!is<HTMLInputElement>(node()))
1901         return;
1902
1903     auto& input = downcast<HTMLInputElement>(*node());
1904     if (!input.isColorControl())
1905         return;
1906
1907     // HTMLInputElement::value always returns a string parseable by Color().
1908     Color color(input.value());
1909     r = color.red();
1910     g = color.green();
1911     b = color.blue();
1912 #endif
1913 }
1914
1915 // This function implements the ARIA accessible name as described by the Mozilla                                        
1916 // ARIA Implementer's Guide.                                                                                            
1917 static String accessibleNameForNode(Node* node, Node* labelledbyNode)
1918 {
1919     ASSERT(node);
1920     if (!is<Element>(node))
1921         return String();
1922     
1923     Element& element = downcast<Element>(*node);
1924     const AtomicString& ariaLabel = AccessibleNode::effectiveStringValueForElement(element, AXPropertyName::Label);
1925     if (!ariaLabel.isEmpty())
1926         return ariaLabel;
1927     
1928     const AtomicString& alt = element.attributeWithoutSynchronization(altAttr);
1929     if (!alt.isEmpty())
1930         return alt;
1931
1932     // If the node can be turned into an AX object, we can use standard name computation rules.
1933     // If however, the node cannot (because there's no renderer e.g.) fallback to using the basic text underneath.
1934     AccessibilityObject* axObject = node->document().axObjectCache()->getOrCreate(node);
1935     if (axObject) {
1936         String valueDescription = axObject->valueDescription();
1937         if (!valueDescription.isEmpty())
1938             return valueDescription;
1939     }
1940     
1941     if (is<HTMLInputElement>(*node))
1942         return downcast<HTMLInputElement>(*node).value();
1943     
1944     String text;
1945     if (axObject) {
1946         if (axObject->accessibleNameDerivesFromContent())
1947             text = axObject->textUnderElement(AccessibilityTextUnderElementMode(AccessibilityTextUnderElementMode::TextUnderElementModeIncludeNameFromContentsChildren, true, labelledbyNode));
1948     } else
1949         text = element.innerText();
1950
1951     if (!text.isEmpty())
1952         return text;
1953     
1954     const AtomicString& title = element.attributeWithoutSynchronization(titleAttr);
1955     if (!title.isEmpty())
1956         return title;
1957     
1958     return String();
1959 }
1960
1961 String AccessibilityNodeObject::accessibilityDescriptionForChildren() const
1962 {
1963     Node* node = this->node();
1964     if (!node)
1965         return String();
1966
1967     AXObjectCache* cache = axObjectCache();
1968     if (!cache)
1969         return String();
1970
1971     StringBuilder builder;
1972     for (Node* child = node->firstChild(); child; child = child->nextSibling()) {
1973         if (!is<Element>(child))
1974             continue;
1975
1976         if (AccessibilityObject* axObject = cache->getOrCreate(child)) {
1977             String description = axObject->ariaLabeledByAttribute();
1978             if (description.isEmpty())
1979                 description = accessibleNameForNode(child);
1980             appendNameToStringBuilder(builder, description);
1981         }
1982     }
1983
1984     return builder.toString();
1985 }
1986
1987 String AccessibilityNodeObject::accessibilityDescriptionForElements(Vector<Element*> &elements) const
1988 {
1989     StringBuilder builder;
1990     unsigned size = elements.size();
1991     for (unsigned i = 0; i < size; ++i)
1992         appendNameToStringBuilder(builder, accessibleNameForNode(elements[i], node()));
1993     return builder.toString();
1994 }
1995
1996 String AccessibilityNodeObject::ariaDescribedByAttribute() const
1997 {
1998     Vector<Element*> elements;
1999     elementsFromAttribute(elements, aria_describedbyAttr);
2000     
2001     return accessibilityDescriptionForElements(elements);
2002 }
2003
2004 void AccessibilityNodeObject::ariaLabeledByElements(Vector<Element*>& elements) const
2005 {
2006     elementsFromAttribute(elements, aria_labelledbyAttr);
2007     if (!elements.size())
2008         elementsFromAttribute(elements, aria_labeledbyAttr);
2009 }
2010
2011
2012 String AccessibilityNodeObject::ariaLabeledByAttribute() const
2013 {
2014     Vector<Element*> elements;
2015     ariaLabeledByElements(elements);
2016
2017     return accessibilityDescriptionForElements(elements);
2018 }
2019
2020 bool AccessibilityNodeObject::hasAttributesRequiredForInclusion() const
2021 {
2022     if (AccessibilityObject::hasAttributesRequiredForInclusion())
2023         return true;
2024
2025     if (!ariaAccessibilityDescription().isEmpty())
2026         return true;
2027
2028     return false;
2029 }
2030
2031 bool AccessibilityNodeObject::canSetFocusAttribute() const
2032 {
2033     Node* node = this->node();
2034     if (!node)
2035         return false;
2036
2037     if (isWebArea())
2038         return true;
2039     
2040     // NOTE: It would be more accurate to ask the document whether setFocusedElement() would
2041     // do anything. For example, setFocusedElement() will do nothing if the current focused
2042     // node will not relinquish the focus.
2043     if (!is<Element>(node))
2044         return false;
2045
2046     Element& element = downcast<Element>(*node);
2047
2048     if (element.isDisabledFormControl())
2049         return false;
2050
2051     return element.supportsFocus();
2052 }
2053
2054 bool AccessibilityNodeObject::canSetValueAttribute() const
2055 {
2056     Node* node = this->node();
2057     if (!node)
2058         return false;
2059
2060     // The host-language readonly attribute trumps aria-readonly.
2061     if (is<HTMLTextAreaElement>(*node))
2062         return !downcast<HTMLTextAreaElement>(*node).isReadOnly();
2063     if (is<HTMLInputElement>(*node)) {
2064         HTMLInputElement& input = downcast<HTMLInputElement>(*node);
2065         if (input.isTextField())
2066             return !input.isReadOnly();
2067     }
2068
2069     String readOnly = readOnlyValue();
2070     if (!readOnly.isEmpty())
2071         return readOnly == "true" ? false : true;
2072
2073     if (isNonNativeTextControl())
2074         return true;
2075
2076     if (isMeter())
2077         return false;
2078
2079     if (isProgressIndicator() || isSlider())
2080         return true;
2081
2082 #if PLATFORM(GTK)
2083     // In ATK, input types which support aria-readonly are treated as having a
2084     // settable value if the user can modify the widget's value or its state.
2085     if (supportsReadOnly())
2086         return true;
2087
2088     if (isRadioButton()) {
2089         auto radioGroup = radioGroupAncestor();
2090         return radioGroup ? radioGroup->readOnlyValue() != "true" : true;
2091     }
2092 #endif
2093
2094     if (isWebArea()) {
2095         Document* document = this->document();
2096         if (!document)
2097             return false;
2098
2099         if (HTMLElement* body = document->bodyOrFrameset()) {
2100             if (body->hasEditableStyle())
2101                 return true;
2102         }
2103
2104         return document->hasEditableStyle();
2105     }
2106
2107     return node->hasEditableStyle();
2108 }
2109
2110 AccessibilityRole AccessibilityNodeObject::determineAriaRoleAttribute() const
2111 {
2112     const AtomicString& ariaRole = stringValueForProperty(AXPropertyName::Role);
2113     if (ariaRole.isNull() || ariaRole.isEmpty())
2114         return AccessibilityRole::Unknown;
2115     
2116     AccessibilityRole role = ariaRoleToWebCoreRole(ariaRole);
2117
2118     // ARIA states if an item can get focus, it should not be presentational.
2119     if (role == AccessibilityRole::Presentational && canSetFocusAttribute())
2120         return AccessibilityRole::Unknown;
2121
2122     if (role == AccessibilityRole::Button)
2123         role = buttonRoleType();
2124
2125     if (role == AccessibilityRole::TextArea && !ariaIsMultiline())
2126         role = AccessibilityRole::TextField;
2127
2128     role = remapAriaRoleDueToParent(role);
2129     
2130     // Presentational roles are invalidated by the presence of ARIA attributes.
2131     if (role == AccessibilityRole::Presentational && supportsARIAAttributes())
2132         role = AccessibilityRole::Unknown;
2133     
2134     // The ARIA spec states, "Authors must give each element with role region a brief label that
2135     // describes the purpose of the content in the region." The Core AAM states, "Special case:
2136     // if the region does not have an accessible name, do not expose the element as a landmark.
2137     // Use the native host language role of the element instead."
2138     if (role == AccessibilityRole::LandmarkRegion && !hasProperty(AXPropertyName::Label) && !hasAttribute(aria_labelledbyAttr))
2139         role = AccessibilityRole::Unknown;
2140
2141     if (static_cast<int>(role))
2142         return role;
2143
2144     return AccessibilityRole::Unknown;
2145 }
2146
2147 AccessibilityRole AccessibilityNodeObject::ariaRoleAttribute() const
2148 {
2149     return m_ariaRole;
2150 }
2151
2152 AccessibilityRole AccessibilityNodeObject::remapAriaRoleDueToParent(AccessibilityRole role) const
2153 {
2154     // Some objects change their role based on their parent.
2155     // However, asking for the unignoredParent calls accessibilityIsIgnored(), which can trigger a loop. 
2156     // While inside the call stack of creating an element, we need to avoid accessibilityIsIgnored().
2157     // https://bugs.webkit.org/show_bug.cgi?id=65174
2158
2159     if (role != AccessibilityRole::ListBoxOption && role != AccessibilityRole::MenuItem)
2160         return role;
2161     
2162     for (AccessibilityObject* parent = parentObject(); parent && !parent->accessibilityIsIgnored(); parent = parent->parentObject()) {
2163         AccessibilityRole parentAriaRole = parent->ariaRoleAttribute();
2164
2165         // Selects and listboxes both have options as child roles, but they map to different roles within WebCore.
2166         if (role == AccessibilityRole::ListBoxOption && parentAriaRole == AccessibilityRole::Menu)
2167             return AccessibilityRole::MenuItem;
2168         // An aria "menuitem" may map to MenuButton or MenuItem depending on its parent.
2169         if (role == AccessibilityRole::MenuItem && parentAriaRole == AccessibilityRole::ApplicationGroup)
2170             return AccessibilityRole::MenuButton;
2171         
2172         // If the parent had a different role, then we don't need to continue searching up the chain.
2173         if (parentAriaRole != AccessibilityRole::Unknown)
2174             break;
2175     }
2176     
2177     return role;
2178 }   
2179
2180 bool AccessibilityNodeObject::canSetSelectedAttribute() const
2181 {
2182     // Elements that can be selected
2183     switch (roleValue()) {
2184     case AccessibilityRole::Cell:
2185     case AccessibilityRole::GridCell:
2186     case AccessibilityRole::RadioButton:
2187     case AccessibilityRole::RowHeader:
2188     case AccessibilityRole::Row:
2189     case AccessibilityRole::TabList:
2190     case AccessibilityRole::Tab:
2191     case AccessibilityRole::TreeGrid:
2192     case AccessibilityRole::TreeItem:
2193     case AccessibilityRole::Tree:
2194     case AccessibilityRole::MenuItemCheckbox:
2195     case AccessibilityRole::MenuItemRadio:
2196     case AccessibilityRole::MenuItem:
2197         return isEnabled();
2198     default:
2199         return false;
2200     }
2201 }
2202
2203 } // namespace WebCore