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