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