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