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