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