9983ec1f42a249cef4d9f2415bfcb87818c26f0f
[WebKit-https.git] / Source / WebCore / accessibility / AccessibilityObject.cpp
1 /*
2  * Copyright (C) 2008-2009, 2011, 2017 Apple 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 "AccessibilityObject.h"
31
32 #include "AXObjectCache.h"
33 #include "AccessibilityRenderObject.h"
34 #include "AccessibilityScrollView.h"
35 #include "AccessibilityTable.h"
36 #include "DOMTokenList.h"
37 #include "Editing.h"
38 #include "Editor.h"
39 #include "ElementIterator.h"
40 #include "EventHandler.h"
41 #include "FloatRect.h"
42 #include "FocusController.h"
43 #include "Frame.h"
44 #include "FrameLoader.h"
45 #include "FrameSelection.h"
46 #include "HTMLDetailsElement.h"
47 #include "HTMLFormControlElement.h"
48 #include "HTMLInputElement.h"
49 #include "HTMLMediaElement.h"
50 #include "HTMLNames.h"
51 #include "HTMLParserIdioms.h"
52 #include "HitTestResult.h"
53 #include "LocalizedStrings.h"
54 #include "MainFrame.h"
55 #include "MathMLNames.h"
56 #include "NodeList.h"
57 #include "NodeTraversal.h"
58 #include "Page.h"
59 #include "RenderImage.h"
60 #include "RenderLayer.h"
61 #include "RenderListItem.h"
62 #include "RenderListMarker.h"
63 #include "RenderMenuList.h"
64 #include "RenderText.h"
65 #include "RenderTextControl.h"
66 #include "RenderTheme.h"
67 #include "RenderView.h"
68 #include "RenderWidget.h"
69 #include "RenderedPosition.h"
70 #include "Settings.h"
71 #include "TextCheckerClient.h"
72 #include "TextCheckingHelper.h"
73 #include "TextIterator.h"
74 #include "UserGestureIndicator.h"
75 #include "VisibleUnits.h"
76 #include <wtf/NeverDestroyed.h>
77 #include <wtf/StdLibExtras.h>
78 #include <wtf/text/StringBuilder.h>
79 #include <wtf/text/StringView.h>
80 #include <wtf/text/WTFString.h>
81 #include <wtf/unicode/CharacterNames.h>
82
83 namespace WebCore {
84
85 using namespace HTMLNames;
86
87 AccessibilityObject::AccessibilityObject()
88     : m_id(0)
89     , m_haveChildren(false)
90     , m_role(UnknownRole)
91     , m_lastKnownIsIgnoredValue(DefaultBehavior)
92     , m_isIgnoredFromParentData(AccessibilityIsIgnoredFromParentData())
93     , m_childrenDirty(false)
94     , m_subtreeDirty(false)
95 #if PLATFORM(GTK)
96     , m_wrapper(nullptr)
97 #endif
98 {
99 }
100
101 AccessibilityObject::~AccessibilityObject()
102 {
103     ASSERT(isDetached());
104 }
105
106 void AccessibilityObject::detach(AccessibilityDetachmentType detachmentType, AXObjectCache* cache)
107 {
108     // Menu close events need to notify the platform. No element is used in the notification because it's a destruction event.
109     if (detachmentType == ElementDestroyed && roleValue() == MenuRole && cache)
110         cache->postNotification(nullptr, &cache->document(), AXObjectCache::AXMenuClosed);
111     
112     // Clear any children and call detachFromParent on them so that
113     // no children are left with dangling pointers to their parent.
114     clearChildren();
115
116 #if HAVE(ACCESSIBILITY)
117     setWrapper(nullptr);
118 #endif
119 }
120
121 bool AccessibilityObject::isDetached() const
122 {
123 #if HAVE(ACCESSIBILITY)
124     return !wrapper();
125 #else
126     return true;
127 #endif
128 }
129
130 bool AccessibilityObject::isAccessibilityObjectSearchMatchAtIndex(AccessibilityObject* axObject, AccessibilitySearchCriteria* criteria, size_t index)
131 {
132     switch (criteria->searchKeys[index]) {
133     // The AnyTypeSearchKey matches any non-null AccessibilityObject.
134     case AnyTypeSearchKey:
135         return true;
136         
137     case ArticleSearchKey:
138         return axObject->roleValue() == DocumentArticleRole;
139             
140     case BlockquoteSameLevelSearchKey:
141         return criteria->startObject
142             && axObject->isBlockquote()
143             && axObject->blockquoteLevel() == criteria->startObject->blockquoteLevel();
144         
145     case BlockquoteSearchKey:
146         return axObject->isBlockquote();
147         
148     case BoldFontSearchKey:
149         return axObject->hasBoldFont();
150         
151     case ButtonSearchKey:
152         return axObject->isButton();
153         
154     case CheckBoxSearchKey:
155         return axObject->isCheckbox();
156         
157     case ControlSearchKey:
158         return axObject->isControl();
159         
160     case DifferentTypeSearchKey:
161         return criteria->startObject
162             && axObject->roleValue() != criteria->startObject->roleValue();
163         
164     case FontChangeSearchKey:
165         return criteria->startObject
166             && !axObject->hasSameFont(criteria->startObject->renderer());
167         
168     case FontColorChangeSearchKey:
169         return criteria->startObject
170             && !axObject->hasSameFontColor(criteria->startObject->renderer());
171         
172     case FrameSearchKey:
173         return axObject->isWebArea();
174         
175     case GraphicSearchKey:
176         return axObject->isImage();
177         
178     case HeadingLevel1SearchKey:
179         return axObject->headingLevel() == 1;
180         
181     case HeadingLevel2SearchKey:
182         return axObject->headingLevel() == 2;
183         
184     case HeadingLevel3SearchKey:
185         return axObject->headingLevel() == 3;
186         
187     case HeadingLevel4SearchKey:
188         return axObject->headingLevel() == 4;
189         
190     case HeadingLevel5SearchKey:
191         return axObject->headingLevel() == 5;
192         
193     case HeadingLevel6SearchKey:
194         return axObject->headingLevel() == 6;
195         
196     case HeadingSameLevelSearchKey:
197         return criteria->startObject
198             && axObject->isHeading()
199             && axObject->headingLevel() == criteria->startObject->headingLevel();
200         
201     case HeadingSearchKey:
202         return axObject->isHeading();
203     
204     case HighlightedSearchKey:
205         return axObject->hasHighlighting();
206             
207     case ItalicFontSearchKey:
208         return axObject->hasItalicFont();
209         
210     case LandmarkSearchKey:
211         return axObject->isLandmark();
212         
213     case LinkSearchKey: {
214         bool isLink = axObject->isLink();
215 #if PLATFORM(IOS)
216         if (!isLink)
217             isLink = axObject->isDescendantOfRole(WebCoreLinkRole);
218 #endif
219         return isLink;
220     }
221         
222     case ListSearchKey:
223         return axObject->isList();
224         
225     case LiveRegionSearchKey:
226         return axObject->supportsARIALiveRegion();
227         
228     case MisspelledWordSearchKey:
229         return axObject->hasMisspelling();
230         
231     case OutlineSearchKey:
232         return axObject->isTree();
233         
234     case PlainTextSearchKey:
235         return axObject->hasPlainText();
236         
237     case RadioGroupSearchKey:
238         return axObject->isRadioGroup();
239         
240     case SameTypeSearchKey:
241         return criteria->startObject
242             && axObject->roleValue() == criteria->startObject->roleValue();
243         
244     case StaticTextSearchKey:
245         return axObject->isStaticText();
246         
247     case StyleChangeSearchKey:
248         return criteria->startObject
249             && !axObject->hasSameStyle(criteria->startObject->renderer());
250         
251     case TableSameLevelSearchKey:
252         return criteria->startObject
253             && is<AccessibilityTable>(*axObject) && downcast<AccessibilityTable>(*axObject).isExposableThroughAccessibility()
254             && downcast<AccessibilityTable>(*axObject).tableLevel() == criteria->startObject->tableLevel();
255         
256     case TableSearchKey:
257         return is<AccessibilityTable>(*axObject) && downcast<AccessibilityTable>(*axObject).isExposableThroughAccessibility();
258         
259     case TextFieldSearchKey:
260         return axObject->isTextControl();
261         
262     case UnderlineSearchKey:
263         return axObject->hasUnderline();
264         
265     case UnvisitedLinkSearchKey:
266         return axObject->isUnvisited();
267         
268     case VisitedLinkSearchKey:
269         return axObject->isVisited();
270         
271     default:
272         return false;
273     }
274 }
275
276 bool AccessibilityObject::isAccessibilityObjectSearchMatch(AccessibilityObject* axObject, AccessibilitySearchCriteria* criteria)
277 {
278     if (!axObject || !criteria)
279         return false;
280     
281     size_t length = criteria->searchKeys.size();
282     for (size_t i = 0; i < length; ++i) {
283         if (isAccessibilityObjectSearchMatchAtIndex(axObject, criteria, i)) {
284             if (criteria->visibleOnly && !axObject->isOnscreen())
285                 return false;
286             return true;
287         }
288     }
289     return false;
290 }
291
292 bool AccessibilityObject::isAccessibilityTextSearchMatch(AccessibilityObject* axObject, AccessibilitySearchCriteria* criteria)
293 {
294     if (!axObject || !criteria)
295         return false;
296     
297     return axObject->accessibilityObjectContainsText(&criteria->searchText);
298 }
299
300 bool AccessibilityObject::accessibilityObjectContainsText(String* text) const
301 {
302     // If text is null or empty we return true.
303     return !text
304         || text->isEmpty()
305         || title().contains(*text, false)
306         || accessibilityDescription().contains(*text, false)
307         || stringValue().contains(*text, false);
308 }
309
310 // ARIA marks elements as having their accessible name derive from either their contents, or their author provide name.
311 bool AccessibilityObject::accessibleNameDerivesFromContent() const
312 {
313     // First check for objects specifically identified by ARIA.
314     switch (ariaRoleAttribute()) {
315     case ApplicationAlertRole:
316     case ApplicationAlertDialogRole:
317     case ApplicationDialogRole:
318     case ApplicationGroupRole:
319     case ApplicationLogRole:
320     case ApplicationMarqueeRole:
321     case ApplicationStatusRole:
322     case ApplicationTimerRole:
323     case ComboBoxRole:
324     case DefinitionRole:
325     case DocumentRole:
326     case DocumentArticleRole:
327     case DocumentMathRole:
328     case DocumentNoteRole:
329     case LandmarkRegionRole:
330     case LandmarkDocRegionRole:
331     case FormRole:
332     case GridRole:
333     case GroupRole:
334     case ImageRole:
335     case ListRole:
336     case ListBoxRole:
337     case LandmarkBannerRole:
338     case LandmarkComplementaryRole:
339     case LandmarkContentInfoRole:
340     case LandmarkNavigationRole:
341     case LandmarkMainRole:
342     case LandmarkSearchRole:
343     case MenuRole:
344     case MenuBarRole:
345     case ProgressIndicatorRole:
346     case RadioGroupRole:
347     case ScrollBarRole:
348     case SliderRole:
349     case SpinButtonRole:
350     case SplitterRole:
351     case TableRole:
352     case TabListRole:
353     case TabPanelRole:
354     case TextAreaRole:
355     case TextFieldRole:
356     case ToolbarRole:
357     case TreeGridRole:
358     case TreeRole:
359     case WebApplicationRole:
360         return false;
361     default:
362         break;
363     }
364     
365     // Now check for generically derived elements now that we know the element does not match a specific ARIA role.
366     switch (roleValue()) {
367     case SliderRole:
368         return false;
369     default:
370         break;
371     }
372     
373     return true;
374 }
375     
376 String AccessibilityObject::computedLabel()
377 {
378     // This method is being called by WebKit inspector, which may happen at any time, so we need to update our backing store now.
379     // Also hold onto this object in case updateBackingStore deletes this node.
380     RefPtr<AccessibilityObject> protectedThis(this);
381     updateBackingStore();
382     Vector<AccessibilityText> text;
383     accessibilityText(text);
384     if (text.size())
385         return text[0].text;
386     return String();
387 }
388
389 bool AccessibilityObject::isBlockquote() const
390 {
391     return roleValue() == BlockquoteRole;
392 }
393
394 bool AccessibilityObject::isTextControl() const
395 {
396     switch (roleValue()) {
397     case ComboBoxRole:
398     case SearchFieldRole:
399     case TextAreaRole:
400     case TextFieldRole:
401         return true;
402     default:
403         return false;
404     }
405 }
406     
407 bool AccessibilityObject::isARIATextControl() const
408 {
409     return ariaRoleAttribute() == TextAreaRole || ariaRoleAttribute() == TextFieldRole || ariaRoleAttribute() == SearchFieldRole;
410 }
411
412 bool AccessibilityObject::isNonNativeTextControl() const
413 {
414     return (isARIATextControl() || hasContentEditableAttributeSet()) && !isNativeTextControl();
415 }
416
417 bool AccessibilityObject::isLandmark() const
418 {
419     AccessibilityRole role = roleValue();
420     
421     return role == LandmarkBannerRole
422         || role == LandmarkComplementaryRole
423         || role == LandmarkContentInfoRole
424         || role == LandmarkDocRegionRole
425         || role == LandmarkMainRole
426         || role == LandmarkNavigationRole
427         || role == LandmarkRegionRole
428         || role == LandmarkSearchRole;
429 }
430
431 bool AccessibilityObject::hasMisspelling() const
432 {
433     if (!node())
434         return false;
435     
436     Frame* frame = node()->document().frame();
437     if (!frame)
438         return false;
439     
440     Editor& editor = frame->editor();
441     
442     TextCheckerClient* textChecker = editor.textChecker();
443     if (!textChecker)
444         return false;
445     
446     bool isMisspelled = false;
447
448     if (unifiedTextCheckerEnabled(frame)) {
449         Vector<TextCheckingResult> results;
450         checkTextOfParagraph(*textChecker, stringValue(), TextCheckingTypeSpelling, results, frame->selection().selection());
451         if (!results.isEmpty())
452             isMisspelled = true;
453         return isMisspelled;
454     }
455
456     int misspellingLength = 0;
457     int misspellingLocation = -1;
458     textChecker->checkSpellingOfString(stringValue(), &misspellingLocation, &misspellingLength);
459     if (misspellingLength || misspellingLocation != -1)
460         isMisspelled = true;
461     
462     return isMisspelled;
463 }
464
465 unsigned AccessibilityObject::blockquoteLevel() const
466 {
467     unsigned level = 0;
468     for (Node* elementNode = node(); elementNode; elementNode = elementNode->parentNode()) {
469         if (elementNode->hasTagName(blockquoteTag))
470             ++level;
471     }
472     
473     return level;
474 }
475
476 AccessibilityObject* AccessibilityObject::parentObjectUnignored() const
477 {
478     return const_cast<AccessibilityObject*>(AccessibilityObject::matchedParent(*this, false, [] (const AccessibilityObject& object) {
479         return !object.accessibilityIsIgnored();
480     }));
481 }
482
483 AccessibilityObject* AccessibilityObject::previousSiblingUnignored(int limit) const
484 {
485     AccessibilityObject* previous;
486     ASSERT(limit >= 0);
487     for (previous = previousSibling(); previous && previous->accessibilityIsIgnored(); previous = previous->previousSibling()) {
488         limit--;
489         if (limit <= 0)
490             break;
491     }
492     return previous;
493 }
494
495 AccessibilityObject* AccessibilityObject::nextSiblingUnignored(int limit) const
496 {
497     AccessibilityObject* next;
498     ASSERT(limit >= 0);
499     for (next = nextSibling(); next && next->accessibilityIsIgnored(); next = next->nextSibling()) {
500         limit--;
501         if (limit <= 0)
502             break;
503     }
504     return next;
505 }
506
507 AccessibilityObject* AccessibilityObject::firstAccessibleObjectFromNode(const Node* node)
508 {
509     if (!node)
510         return nullptr;
511
512     AXObjectCache* cache = node->document().axObjectCache();
513     if (!cache)
514         return nullptr;
515     
516     AccessibilityObject* accessibleObject = cache->getOrCreate(node->renderer());
517     while (accessibleObject && accessibleObject->accessibilityIsIgnored()) {
518         node = NodeTraversal::next(*node);
519
520         while (node && !node->renderer())
521             node = NodeTraversal::nextSkippingChildren(*node);
522
523         if (!node)
524             return nullptr;
525
526         accessibleObject = cache->getOrCreate(node->renderer());
527     }
528
529     return accessibleObject;
530 }
531
532 bool AccessibilityObject::isDescendantOfRole(AccessibilityRole role) const
533 {
534     return AccessibilityObject::matchedParent(*this, false, [&role] (const AccessibilityObject& object) {
535         return object.roleValue() == role;
536     }) != nullptr;
537 }
538
539 static void appendAccessibilityObject(AccessibilityObject* object, AccessibilityObject::AccessibilityChildrenVector& results)
540 {
541     // Find the next descendant of this attachment object so search can continue through frames.
542     if (object->isAttachment()) {
543         Widget* widget = object->widgetForAttachmentView();
544         if (!is<FrameView>(widget))
545             return;
546         
547         Document* document = downcast<FrameView>(*widget).frame().document();
548         if (!document || !document->hasLivingRenderTree())
549             return;
550         
551         object = object->axObjectCache()->getOrCreate(document);
552     }
553
554     if (object)
555         results.append(object);
556 }
557     
558 void AccessibilityObject::insertChild(AccessibilityObject* child, unsigned index)
559 {
560     if (!child)
561         return;
562     
563     // If the parent is asking for this child's children, then either it's the first time (and clearing is a no-op),
564     // or its visibility has changed. In the latter case, this child may have a stale child cached.
565     // This can prevent aria-hidden changes from working correctly. Hence, whenever a parent is getting children, ensure data is not stale.
566     // Only clear the child's children when we know it's in the updating chain in order to avoid unnecessary work.
567     if (child->needsToUpdateChildren() || m_subtreeDirty) {
568         child->clearChildren();
569         // Pass m_subtreeDirty flag down to the child so that children cache gets reset properly.
570         if (m_subtreeDirty)
571             child->setNeedsToUpdateSubtree();
572     } else {
573         // For some reason the grand children might be detached so that we need to regenerate the
574         // children list of this child.
575         for (const auto& grandChild : child->children(false)) {
576             if (grandChild->isDetachedFromParent()) {
577                 child->clearChildren();
578                 break;
579             }
580         }
581     }
582     
583     setIsIgnoredFromParentDataForChild(child);
584     if (child->accessibilityIsIgnored()) {
585         const auto& children = child->children();
586         size_t length = children.size();
587         for (size_t i = 0; i < length; ++i)
588             m_children.insert(index + i, children[i]);
589     } else {
590         ASSERT(child->parentObject() == this);
591         m_children.insert(index, child);
592     }
593     
594     // Reset the child's m_isIgnoredFromParentData since we are done adding that child and its children.
595     child->clearIsIgnoredFromParentData();
596 }
597     
598 void AccessibilityObject::addChild(AccessibilityObject* child)
599 {
600     insertChild(child, m_children.size());
601 }
602     
603 static void appendChildrenToArray(AccessibilityObject* object, bool isForward, AccessibilityObject* startObject, AccessibilityObject::AccessibilityChildrenVector& results)
604 {
605     // A table's children includes elements whose own children are also the table's children (due to the way the Mac exposes tables).
606     // The rows from the table should be queried, since those are direct descendants of the table, and they contain content.
607     const auto& searchChildren = is<AccessibilityTable>(*object) && downcast<AccessibilityTable>(*object).isExposableThroughAccessibility() ? downcast<AccessibilityTable>(*object).rows() : object->children();
608
609     size_t childrenSize = searchChildren.size();
610
611     size_t startIndex = isForward ? childrenSize : 0;
612     size_t endIndex = isForward ? 0 : childrenSize;
613
614     // If the startObject is ignored, we should use an accessible sibling as a start element instead.
615     if (startObject && startObject->accessibilityIsIgnored() && startObject->isDescendantOfObject(object)) {
616         AccessibilityObject* parentObject = startObject->parentObject();
617         // Go up the parent chain to find the highest ancestor that's also being ignored.
618         while (parentObject && parentObject->accessibilityIsIgnored()) {
619             if (parentObject == object)
620                 break;
621             startObject = parentObject;
622             parentObject = parentObject->parentObject();
623         }
624         // Get the un-ignored sibling based on the search direction, and update the searchPosition.
625         while (startObject && startObject->accessibilityIsIgnored())
626             startObject = isForward ? startObject->previousSibling() : startObject->nextSibling();
627     }
628     
629     size_t searchPosition = startObject ? searchChildren.find(startObject) : WTF::notFound;
630     
631     if (searchPosition != WTF::notFound) {
632         if (isForward)
633             endIndex = searchPosition + 1;
634         else
635             endIndex = searchPosition;
636     }
637
638     // This is broken into two statements so that it's easier read.
639     if (isForward) {
640         for (size_t i = startIndex; i > endIndex; i--)
641             appendAccessibilityObject(searchChildren.at(i - 1).get(), results);
642     } else {
643         for (size_t i = startIndex; i < endIndex; i++)
644             appendAccessibilityObject(searchChildren.at(i).get(), results);
645     }
646 }
647
648 // Returns true if the number of results is now >= the number of results desired.
649 bool AccessibilityObject::objectMatchesSearchCriteriaWithResultLimit(AccessibilityObject* object, AccessibilitySearchCriteria* criteria, AccessibilityChildrenVector& results)
650 {
651     if (isAccessibilityObjectSearchMatch(object, criteria) && isAccessibilityTextSearchMatch(object, criteria)) {
652         results.append(object);
653         
654         // Enough results were found to stop searching.
655         if (results.size() >= criteria->resultsLimit)
656             return true;
657     }
658     
659     return false;
660 }
661
662 void AccessibilityObject::findMatchingObjects(AccessibilitySearchCriteria* criteria, AccessibilityChildrenVector& results)
663 {
664     ASSERT(criteria);
665     
666     if (!criteria)
667         return;
668
669     if (AXObjectCache* cache = axObjectCache())
670         cache->startCachingComputedObjectAttributesUntilTreeMutates();
671
672     // This search mechanism only searches the elements before/after the starting object.
673     // It does this by stepping up the parent chain and at each level doing a DFS.
674     
675     // If there's no start object, it means we want to search everything.
676     AccessibilityObject* startObject = criteria->startObject;
677     if (!startObject)
678         startObject = this;
679     
680     bool isForward = criteria->searchDirection == SearchDirectionNext;
681     
682     // The first iteration of the outer loop will examine the children of the start object for matches. However, when
683     // iterating backwards, the start object children should not be considered, so the loop is skipped ahead. We make an
684     // exception when no start object was specified because we want to search everything regardless of search direction.
685     AccessibilityObject* previousObject = nullptr;
686     if (!isForward && startObject != this) {
687         previousObject = startObject;
688         startObject = startObject->parentObjectUnignored();
689     }
690     
691     // The outer loop steps up the parent chain each time (unignored is important here because otherwise elements would be searched twice)
692     for (AccessibilityObject* stopSearchElement = parentObjectUnignored(); startObject && startObject != stopSearchElement; startObject = startObject->parentObjectUnignored()) {
693
694         // Only append the children after/before the previous element, so that the search does not check elements that are 
695         // already behind/ahead of start element.
696         AccessibilityChildrenVector searchStack;
697         if (!criteria->immediateDescendantsOnly || startObject == this)
698             appendChildrenToArray(startObject, isForward, previousObject, searchStack);
699
700         // This now does a DFS at the current level of the parent.
701         while (!searchStack.isEmpty()) {
702             AccessibilityObject* searchObject = searchStack.last().get();
703             searchStack.removeLast();
704             
705             if (objectMatchesSearchCriteriaWithResultLimit(searchObject, criteria, results))
706                 break;
707             
708             if (!criteria->immediateDescendantsOnly)
709                 appendChildrenToArray(searchObject, isForward, 0, searchStack);
710         }
711         
712         if (results.size() >= criteria->resultsLimit)
713             break;
714
715         // When moving backwards, the parent object needs to be checked, because technically it's "before" the starting element.
716         if (!isForward && startObject != this && objectMatchesSearchCriteriaWithResultLimit(startObject, criteria, results))
717             break;
718
719         previousObject = startObject;
720     }
721 }
722
723 // Returns the range that is fewer positions away from the reference range.
724 // NOTE: The after range is expected to ACTUALLY be after the reference range and the before
725 // range is expected to ACTUALLY be before. These are not checked for performance reasons.
726 static RefPtr<Range> rangeClosestToRange(Range* referenceRange, RefPtr<Range>&& afterRange, RefPtr<Range>&& beforeRange)
727 {
728     if (!referenceRange)
729         return nullptr;
730     
731     // The treeScope for shadow nodes may not be the same scope as another element in a document.
732     // Comparisons may fail in that case, which are expected behavior and should not assert.
733     if (afterRange && (referenceRange->endPosition().isNull() || ((afterRange->startPosition().anchorNode()->compareDocumentPosition(*referenceRange->endPosition().anchorNode()) & Node::DOCUMENT_POSITION_DISCONNECTED) == Node::DOCUMENT_POSITION_DISCONNECTED)))
734         return nullptr;
735     ASSERT(!afterRange || afterRange->startPosition() >= referenceRange->endPosition());
736     
737     if (beforeRange && (referenceRange->startPosition().isNull() || ((beforeRange->endPosition().anchorNode()->compareDocumentPosition(*referenceRange->startPosition().anchorNode()) & Node::DOCUMENT_POSITION_DISCONNECTED) == Node::DOCUMENT_POSITION_DISCONNECTED)))
738         return nullptr;
739     ASSERT(!beforeRange || beforeRange->endPosition() <= referenceRange->startPosition());
740     
741     if (!afterRange && !beforeRange)
742         return nullptr;
743     if (afterRange && !beforeRange)
744         return afterRange;
745     if (!afterRange && beforeRange)
746         return beforeRange;
747     
748     unsigned positionsToAfterRange = Position::positionCountBetweenPositions(afterRange->startPosition(), referenceRange->endPosition());
749     unsigned positionsToBeforeRange = Position::positionCountBetweenPositions(beforeRange->endPosition(), referenceRange->startPosition());
750     
751     return positionsToAfterRange < positionsToBeforeRange ? afterRange : beforeRange;
752 }
753
754 RefPtr<Range> AccessibilityObject::rangeOfStringClosestToRangeInDirection(Range* referenceRange, AccessibilitySearchDirection searchDirection, Vector<String>& searchStrings) const
755 {
756     Frame* frame = this->frame();
757     if (!frame)
758         return nullptr;
759     
760     if (!referenceRange)
761         return nullptr;
762     
763     bool isBackwardSearch = searchDirection == SearchDirectionPrevious;
764     FindOptions findOptions = AtWordStarts | AtWordEnds | CaseInsensitive | StartInSelection;
765     if (isBackwardSearch)
766         findOptions |= Backwards;
767     
768     RefPtr<Range> closestStringRange = nullptr;
769     for (const auto& searchString : searchStrings) {
770         if (RefPtr<Range> searchStringRange = frame->editor().rangeOfString(searchString, referenceRange, findOptions)) {
771             if (!closestStringRange)
772                 closestStringRange = searchStringRange;
773             else {
774                 // If searching backward, use the trailing range edges to correctly determine which
775                 // range is closest. Similarly, if searching forward, use the leading range edges.
776                 Position closestStringPosition = isBackwardSearch ? closestStringRange->endPosition() : closestStringRange->startPosition();
777                 Position searchStringPosition = isBackwardSearch ? searchStringRange->endPosition() : searchStringRange->startPosition();
778                 
779                 int closestPositionOffset = closestStringPosition.computeOffsetInContainerNode();
780                 int searchPositionOffset = searchStringPosition.computeOffsetInContainerNode();
781                 Node* closestContainerNode = closestStringPosition.containerNode();
782                 Node* searchContainerNode = searchStringPosition.containerNode();
783                 
784                 short result = Range::compareBoundaryPoints(closestContainerNode, closestPositionOffset, searchContainerNode, searchPositionOffset).releaseReturnValue();
785                 if ((!isBackwardSearch && result > 0) || (isBackwardSearch && result < 0))
786                     closestStringRange = searchStringRange;
787             }
788         }
789     }
790     return closestStringRange;
791 }
792
793 // Returns the range of the entire document if there is no selection.
794 RefPtr<Range> AccessibilityObject::selectionRange() const
795 {
796     Frame* frame = this->frame();
797     if (!frame)
798         return nullptr;
799     
800     const VisibleSelection& selection = frame->selection().selection();
801     if (!selection.isNone())
802         return selection.firstRange();
803     
804     return Range::create(*frame->document());
805 }
806
807 RefPtr<Range> AccessibilityObject::elementRange() const
808 {    
809     return AXObjectCache::rangeForNodeContents(node());
810 }
811
812 String AccessibilityObject::selectText(AccessibilitySelectTextCriteria* criteria)
813 {
814     ASSERT(criteria);
815     
816     if (!criteria)
817         return String();
818     
819     Frame* frame = this->frame();
820     if (!frame)
821         return String();
822     
823     AccessibilitySelectTextActivity& activity = criteria->activity;
824     AccessibilitySelectTextAmbiguityResolution& ambiguityResolution = criteria->ambiguityResolution;
825     String& replacementString = criteria->replacementString;
826     Vector<String>& searchStrings = criteria->searchStrings;
827     
828     RefPtr<Range> selectedStringRange = selectionRange();
829     // When starting our search again, make this a zero length range so that search forwards will find this selected range if its appropriate.
830     selectedStringRange->setEnd(selectedStringRange->startContainer(), selectedStringRange->startOffset());
831     
832     RefPtr<Range> closestAfterStringRange = nullptr;
833     RefPtr<Range> closestBeforeStringRange = nullptr;
834     // Search forward if necessary.
835     if (ambiguityResolution == ClosestAfterSelectionAmbiguityResolution || ambiguityResolution == ClosestToSelectionAmbiguityResolution)
836         closestAfterStringRange = rangeOfStringClosestToRangeInDirection(selectedStringRange.get(), SearchDirectionNext, searchStrings);
837     // Search backward if necessary.
838     if (ambiguityResolution == ClosestBeforeSelectionAmbiguityResolution || ambiguityResolution == ClosestToSelectionAmbiguityResolution)
839         closestBeforeStringRange = rangeOfStringClosestToRangeInDirection(selectedStringRange.get(), SearchDirectionPrevious, searchStrings);
840     
841     // Determine which candidate is closest to the selection and perform the activity.
842     if (RefPtr<Range> closestStringRange = rangeClosestToRange(selectedStringRange.get(), WTFMove(closestAfterStringRange), WTFMove(closestBeforeStringRange))) {
843         // If the search started within a text control, ensure that the result is inside that element.
844         if (element() && element()->isTextFormControl()) {
845             if (!closestStringRange->startContainer().isDescendantOrShadowDescendantOf(element()) || !closestStringRange->endContainer().isDescendantOrShadowDescendantOf(element()))
846                 return String();
847         }
848         
849         String closestString = closestStringRange->text();
850         bool replaceSelection = false;
851         if (frame->selection().setSelectedRange(closestStringRange.get(), DOWNSTREAM, true)) {
852             switch (activity) {
853             case FindAndCapitalize:
854                 replacementString = closestString;
855                 makeCapitalized(&replacementString, 0);
856                 replaceSelection = true;
857                 break;
858             case FindAndUppercase:
859                 replacementString = closestString.convertToUppercaseWithoutLocale(); // FIXME: Needs locale to work correctly.
860                 replaceSelection = true;
861                 break;
862             case FindAndLowercase:
863                 replacementString = closestString.convertToLowercaseWithoutLocale(); // FIXME: Needs locale to work correctly.
864                 replaceSelection = true;
865                 break;
866             case FindAndReplaceActivity: {
867                 replaceSelection = true;
868                 // When applying find and replace activities, we want to match the capitalization of the replaced text,
869                 // (unless we're replacing with an abbreviation.)
870                 if (closestString.length() > 0 && replacementString.length() > 2 && replacementString != replacementString.convertToUppercaseWithoutLocale()) {
871                     if (closestString[0] == u_toupper(closestString[0]))
872                         makeCapitalized(&replacementString, 0);
873                     else
874                         replacementString = replacementString.convertToLowercaseWithoutLocale(); // FIXME: Needs locale to work correctly.
875                 }
876                 break;
877             }
878             case FindAndSelectActivity:
879                 break;
880             }
881             
882             // A bit obvious, but worth noting the API contract for this method is that we should
883             // return the replacement string when replacing, but the selected string if not.
884             if (replaceSelection) {
885                 frame->editor().replaceSelectionWithText(replacementString, true, true);
886                 return replacementString;
887             }
888             
889             return closestString;
890         }
891     }
892     
893     return String();
894 }
895
896 bool AccessibilityObject::hasAttributesRequiredForInclusion() const
897 {
898     // These checks are simplified in the interest of execution speed.
899     if (!getAttribute(aria_helpAttr).isEmpty()
900         || !getAttribute(aria_describedbyAttr).isEmpty()
901         || !getAttribute(altAttr).isEmpty()
902         || !getAttribute(titleAttr).isEmpty())
903         return true;
904
905 #if ENABLE(MATHML)
906     if (!getAttribute(MathMLNames::alttextAttr).isEmpty())
907         return true;
908 #endif
909
910     return false;
911 }
912
913 bool AccessibilityObject::isARIAInput(AccessibilityRole ariaRole)
914 {
915     return ariaRole == RadioButtonRole || ariaRole == CheckBoxRole || ariaRole == TextFieldRole || ariaRole == SwitchRole || ariaRole == SearchFieldRole;
916 }    
917     
918 bool AccessibilityObject::isARIAControl(AccessibilityRole ariaRole)
919 {
920     return isARIAInput(ariaRole) || ariaRole == TextAreaRole || ariaRole == ButtonRole 
921     || ariaRole == ComboBoxRole || ariaRole == SliderRole; 
922 }
923     
924 bool AccessibilityObject::isRangeControl() const
925 {
926     switch (roleValue()) {
927     case ProgressIndicatorRole:
928     case SliderRole:
929     case ScrollBarRole:
930     case SpinButtonRole:
931         return true;
932     case SplitterRole:
933         return canSetFocusAttribute();
934     default:
935         return false;
936     }
937 }
938
939 bool AccessibilityObject::isMeter() const
940 {
941 #if ENABLE(METER_ELEMENT)
942     RenderObject* renderer = this->renderer();
943     return renderer && renderer->isMeter();
944 #else
945     return false;
946 #endif
947 }
948
949 IntPoint AccessibilityObject::clickPoint()
950 {
951     LayoutRect rect = elementRect();
952     return roundedIntPoint(LayoutPoint(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2));
953 }
954
955 IntRect AccessibilityObject::boundingBoxForQuads(RenderObject* obj, const Vector<FloatQuad>& quads)
956 {
957     ASSERT(obj);
958     if (!obj)
959         return IntRect();
960     
961     FloatRect result;
962     for (const auto& quad : quads) {
963         FloatRect r = quad.enclosingBoundingBox();
964         if (!r.isEmpty()) {
965             if (obj->style().hasAppearance())
966                 obj->theme().adjustRepaintRect(*obj, r);
967             result.unite(r);
968         }
969     }
970     return snappedIntRect(LayoutRect(result));
971 }
972     
973 bool AccessibilityObject::press()
974 {
975     // The presence of the actionElement will confirm whether we should even attempt a press.
976     Element* actionElem = actionElement();
977     if (!actionElem)
978         return false;
979     if (Frame* f = actionElem->document().frame())
980         f->loader().resetMultipleFormSubmissionProtection();
981     
982     // Hit test at this location to determine if there is a sub-node element that should act
983     // as the target of the action.
984     Element* hitTestElement = nullptr;
985     Document* document = this->document();
986     if (document) {
987         HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::AccessibilityHitTest);
988         HitTestResult hitTestResult(clickPoint());
989         document->renderView()->hitTest(request, hitTestResult);
990         if (hitTestResult.innerNode()) {
991             Node* innerNode = hitTestResult.innerNode()->deprecatedShadowAncestorNode();
992             if (is<Element>(*innerNode))
993                 hitTestElement = downcast<Element>(innerNode);
994             else if (innerNode)
995                 hitTestElement = innerNode->parentElement();
996         }
997     }
998     
999     
1000     // Prefer the actionElement instead of this node, if the actionElement is inside this node.
1001     Element* pressElement = this->element();
1002     if (!pressElement || actionElem->isDescendantOf(*pressElement))
1003         pressElement = actionElem;
1004     
1005     ASSERT(pressElement);
1006     // Prefer the hit test element, if it is inside the target element.
1007     if (hitTestElement && hitTestElement->isDescendantOf(*pressElement))
1008         pressElement = hitTestElement;
1009     
1010     UserGestureIndicator gestureIndicator(ProcessingUserGesture, document);
1011     
1012     bool dispatchedTouchEvent = false;
1013 #if PLATFORM(IOS)
1014     if (hasTouchEventListener())
1015         dispatchedTouchEvent = dispatchTouchEvent();
1016 #endif
1017     if (!dispatchedTouchEvent)
1018         pressElement->accessKeyAction(true);
1019     
1020     return true;
1021 }
1022     
1023 bool AccessibilityObject::dispatchTouchEvent()
1024 {
1025 #if ENABLE(IOS_TOUCH_EVENTS)
1026     if (auto* frame = mainFrame())
1027         return frame->eventHandler().dispatchSimulatedTouchEvent(clickPoint());
1028 #endif
1029     return false;
1030 }
1031
1032 Frame* AccessibilityObject::frame() const
1033 {
1034     Node* node = this->node();
1035     if (!node)
1036         return nullptr;
1037     
1038     return node->document().frame();
1039 }
1040
1041 MainFrame* AccessibilityObject::mainFrame() const
1042 {
1043     Document* document = topDocument();
1044     if (!document)
1045         return nullptr;
1046     
1047     Frame* frame = document->frame();
1048     if (!frame)
1049         return nullptr;
1050     
1051     return &frame->mainFrame();
1052 }
1053
1054 Document* AccessibilityObject::topDocument() const
1055 {
1056     if (!document())
1057         return nullptr;
1058     return &document()->topDocument();
1059 }
1060
1061 String AccessibilityObject::language() const
1062 {
1063     const AtomicString& lang = getAttribute(langAttr);
1064     if (!lang.isEmpty())
1065         return lang;
1066
1067     AccessibilityObject* parent = parentObject();
1068     
1069     // as a last resort, fall back to the content language specified in the meta tag
1070     if (!parent) {
1071         Document* doc = document();
1072         if (doc)
1073             return doc->contentLanguage();
1074         return nullAtom();
1075     }
1076     
1077     return parent->language();
1078 }
1079     
1080 VisiblePositionRange AccessibilityObject::visiblePositionRangeForUnorderedPositions(const VisiblePosition& visiblePos1, const VisiblePosition& visiblePos2) const
1081 {
1082     if (visiblePos1.isNull() || visiblePos2.isNull())
1083         return VisiblePositionRange();
1084
1085     // If there's no common tree scope between positions, return early.
1086     if (!commonTreeScope(visiblePos1.deepEquivalent().deprecatedNode(), visiblePos2.deepEquivalent().deprecatedNode()))
1087         return VisiblePositionRange();
1088     
1089     VisiblePosition startPos;
1090     VisiblePosition endPos;
1091     bool alreadyInOrder;
1092
1093     // upstream is ordered before downstream for the same position
1094     if (visiblePos1 == visiblePos2 && visiblePos2.affinity() == UPSTREAM)
1095         alreadyInOrder = false;
1096
1097     // use selection order to see if the positions are in order
1098     else
1099         alreadyInOrder = VisibleSelection(visiblePos1, visiblePos2).isBaseFirst();
1100
1101     if (alreadyInOrder) {
1102         startPos = visiblePos1;
1103         endPos = visiblePos2;
1104     } else {
1105         startPos = visiblePos2;
1106         endPos = visiblePos1;
1107     }
1108
1109     return VisiblePositionRange(startPos, endPos);
1110 }
1111
1112 VisiblePositionRange AccessibilityObject::positionOfLeftWord(const VisiblePosition& visiblePos) const
1113 {
1114     VisiblePosition startPosition = startOfWord(visiblePos, LeftWordIfOnBoundary);
1115     VisiblePosition endPosition = endOfWord(startPosition);
1116     return VisiblePositionRange(startPosition, endPosition);
1117 }
1118
1119 VisiblePositionRange AccessibilityObject::positionOfRightWord(const VisiblePosition& visiblePos) const
1120 {
1121     VisiblePosition startPosition = startOfWord(visiblePos, RightWordIfOnBoundary);
1122     VisiblePosition endPosition = endOfWord(startPosition);
1123     return VisiblePositionRange(startPosition, endPosition);
1124 }
1125
1126 static VisiblePosition updateAXLineStartForVisiblePosition(const VisiblePosition& visiblePosition)
1127 {
1128     // A line in the accessibility sense should include floating objects, such as aligned image, as part of a line.
1129     // So let's update the position to include that.
1130     VisiblePosition tempPosition;
1131     VisiblePosition startPosition = visiblePosition;
1132     while (true) {
1133         tempPosition = startPosition.previous();
1134         if (tempPosition.isNull())
1135             break;
1136         Position p = tempPosition.deepEquivalent();
1137         RenderObject* renderer = p.deprecatedNode()->renderer();
1138         if (!renderer || (renderer->isRenderBlock() && !p.deprecatedEditingOffset()))
1139             break;
1140         if (!RenderedPosition(tempPosition).isNull())
1141             break;
1142         startPosition = tempPosition;
1143     }
1144
1145     return startPosition;
1146 }
1147
1148 VisiblePositionRange AccessibilityObject::leftLineVisiblePositionRange(const VisiblePosition& visiblePos) const
1149 {
1150     if (visiblePos.isNull())
1151         return VisiblePositionRange();
1152
1153     // make a caret selection for the position before marker position (to make sure
1154     // we move off of a line start)
1155     VisiblePosition prevVisiblePos = visiblePos.previous();
1156     if (prevVisiblePos.isNull())
1157         return VisiblePositionRange();
1158
1159     VisiblePosition startPosition = startOfLine(prevVisiblePos);
1160
1161     // keep searching for a valid line start position.  Unless the VisiblePosition is at the very beginning, there should
1162     // always be a valid line range.  However, startOfLine will return null for position next to a floating object,
1163     // since floating object doesn't really belong to any line.
1164     // This check will reposition the marker before the floating object, to ensure we get a line start.
1165     if (startPosition.isNull()) {
1166         while (startPosition.isNull() && prevVisiblePos.isNotNull()) {
1167             prevVisiblePos = prevVisiblePos.previous();
1168             startPosition = startOfLine(prevVisiblePos);
1169         }
1170     } else
1171         startPosition = updateAXLineStartForVisiblePosition(startPosition);
1172
1173     VisiblePosition endPosition = endOfLine(prevVisiblePos);
1174     return VisiblePositionRange(startPosition, endPosition);
1175 }
1176
1177 VisiblePositionRange AccessibilityObject::rightLineVisiblePositionRange(const VisiblePosition& visiblePos) const
1178 {
1179     if (visiblePos.isNull())
1180         return VisiblePositionRange();
1181
1182     // make sure we move off of a line end
1183     VisiblePosition nextVisiblePos = visiblePos.next();
1184     if (nextVisiblePos.isNull())
1185         return VisiblePositionRange();
1186
1187     VisiblePosition startPosition = startOfLine(nextVisiblePos);
1188
1189     // fetch for a valid line start position
1190     if (startPosition.isNull()) {
1191         startPosition = visiblePos;
1192         nextVisiblePos = nextVisiblePos.next();
1193     } else
1194         startPosition = updateAXLineStartForVisiblePosition(startPosition);
1195
1196     VisiblePosition endPosition = endOfLine(nextVisiblePos);
1197
1198     // as long as the position hasn't reached the end of the doc,  keep searching for a valid line end position
1199     // Unless the VisiblePosition is at the very end, there should always be a valid line range.  However, endOfLine will
1200     // return null for position by a floating object, since floating object doesn't really belong to any line.
1201     // This check will reposition the marker after the floating object, to ensure we get a line end.
1202     while (endPosition.isNull() && nextVisiblePos.isNotNull()) {
1203         nextVisiblePos = nextVisiblePos.next();
1204         endPosition = endOfLine(nextVisiblePos);
1205     }
1206
1207     return VisiblePositionRange(startPosition, endPosition);
1208 }
1209
1210 VisiblePositionRange AccessibilityObject::sentenceForPosition(const VisiblePosition& visiblePos) const
1211 {
1212     // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
1213     // Related? <rdar://problem/3927736> Text selection broken in 8A336
1214     VisiblePosition startPosition = startOfSentence(visiblePos);
1215     VisiblePosition endPosition = endOfSentence(startPosition);
1216     return VisiblePositionRange(startPosition, endPosition);
1217 }
1218
1219 VisiblePositionRange AccessibilityObject::paragraphForPosition(const VisiblePosition& visiblePos) const
1220 {
1221     VisiblePosition startPosition = startOfParagraph(visiblePos);
1222     VisiblePosition endPosition = endOfParagraph(startPosition);
1223     return VisiblePositionRange(startPosition, endPosition);
1224 }
1225
1226 static VisiblePosition startOfStyleRange(const VisiblePosition& visiblePos)
1227 {
1228     RenderObject* renderer = visiblePos.deepEquivalent().deprecatedNode()->renderer();
1229     RenderObject* startRenderer = renderer;
1230     auto* style = &renderer->style();
1231
1232     // traverse backward by renderer to look for style change
1233     for (RenderObject* r = renderer->previousInPreOrder(); r; r = r->previousInPreOrder()) {
1234         // skip non-leaf nodes
1235         if (r->firstChildSlow())
1236             continue;
1237
1238         // stop at style change
1239         if (&r->style() != style)
1240             break;
1241
1242         // remember match
1243         startRenderer = r;
1244     }
1245
1246     return firstPositionInOrBeforeNode(startRenderer->node());
1247 }
1248
1249 static VisiblePosition endOfStyleRange(const VisiblePosition& visiblePos)
1250 {
1251     RenderObject* renderer = visiblePos.deepEquivalent().deprecatedNode()->renderer();
1252     RenderObject* endRenderer = renderer;
1253     const RenderStyle& style = renderer->style();
1254
1255     // traverse forward by renderer to look for style change
1256     for (RenderObject* r = renderer->nextInPreOrder(); r; r = r->nextInPreOrder()) {
1257         // skip non-leaf nodes
1258         if (r->firstChildSlow())
1259             continue;
1260
1261         // stop at style change
1262         if (&r->style() != &style)
1263             break;
1264
1265         // remember match
1266         endRenderer = r;
1267     }
1268
1269     return lastPositionInOrAfterNode(endRenderer->node());
1270 }
1271
1272 VisiblePositionRange AccessibilityObject::styleRangeForPosition(const VisiblePosition& visiblePos) const
1273 {
1274     if (visiblePos.isNull())
1275         return VisiblePositionRange();
1276
1277     return VisiblePositionRange(startOfStyleRange(visiblePos), endOfStyleRange(visiblePos));
1278 }
1279
1280 // NOTE: Consider providing this utility method as AX API
1281 VisiblePositionRange AccessibilityObject::visiblePositionRangeForRange(const PlainTextRange& range) const
1282 {
1283     unsigned textLength = getLengthForTextRange();
1284     if (range.start + range.length > textLength)
1285         return VisiblePositionRange();
1286
1287     VisiblePosition startPosition = visiblePositionForIndex(range.start);
1288     startPosition.setAffinity(DOWNSTREAM);
1289     VisiblePosition endPosition = visiblePositionForIndex(range.start + range.length);
1290     return VisiblePositionRange(startPosition, endPosition);
1291 }
1292
1293 RefPtr<Range> AccessibilityObject::rangeForPlainTextRange(const PlainTextRange& range) const
1294 {
1295     unsigned textLength = getLengthForTextRange();
1296     if (range.start + range.length > textLength)
1297         return nullptr;
1298     
1299     if (AXObjectCache* cache = axObjectCache()) {
1300         CharacterOffset start = cache->characterOffsetForIndex(range.start, this);
1301         CharacterOffset end = cache->characterOffsetForIndex(range.start + range.length, this);
1302         return cache->rangeForUnorderedCharacterOffsets(start, end);
1303     }
1304     return nullptr;
1305 }
1306
1307 VisiblePositionRange AccessibilityObject::lineRangeForPosition(const VisiblePosition& visiblePosition) const
1308 {
1309     VisiblePosition startPosition = startOfLine(visiblePosition);
1310     VisiblePosition endPosition = endOfLine(visiblePosition);
1311     return VisiblePositionRange(startPosition, endPosition);
1312 }
1313
1314 bool AccessibilityObject::replacedNodeNeedsCharacter(Node* replacedNode)
1315 {
1316     // we should always be given a rendered node and a replaced node, but be safe
1317     // replaced nodes are either attachments (widgets) or images
1318     if (!replacedNode || !isRendererReplacedElement(replacedNode->renderer()) || replacedNode->isTextNode())
1319         return false;
1320
1321     // create an AX object, but skip it if it is not supposed to be seen
1322     AccessibilityObject* object = replacedNode->renderer()->document().axObjectCache()->getOrCreate(replacedNode);
1323     if (object->accessibilityIsIgnored())
1324         return false;
1325
1326     return true;
1327 }
1328
1329 // Finds a RenderListItem parent give a node.
1330 static RenderListItem* renderListItemContainerForNode(Node* node)
1331 {
1332     for (; node; node = node->parentNode()) {
1333         RenderBoxModelObject* renderer = node->renderBoxModelObject();
1334         if (is<RenderListItem>(renderer))
1335             return downcast<RenderListItem>(renderer);
1336     }
1337     return nullptr;
1338 }
1339
1340 static String listMarkerTextForNode(Node* node)
1341 {
1342     RenderListItem* listItem = renderListItemContainerForNode(node);
1343     if (!listItem)
1344         return String();
1345     
1346     // If this is in a list item, we need to manually add the text for the list marker
1347     // because a RenderListMarker does not have a Node equivalent and thus does not appear
1348     // when iterating text.
1349     return listItem->markerTextWithSuffix();
1350 }
1351
1352 // Returns the text associated with a list marker if this node is contained within a list item.
1353 String AccessibilityObject::listMarkerTextForNodeAndPosition(Node* node, const VisiblePosition& visiblePositionStart)
1354 {
1355     // If the range does not contain the start of the line, the list marker text should not be included.
1356     if (!isStartOfLine(visiblePositionStart))
1357         return String();
1358
1359     // We should speak the list marker only for the first line.
1360     RenderListItem* listItem = renderListItemContainerForNode(node);
1361     if (!listItem)
1362         return String();
1363     if (!inSameLine(visiblePositionStart, firstPositionInNode(&listItem->element())))
1364         return String();
1365     
1366     return listMarkerTextForNode(node);
1367 }
1368
1369 String AccessibilityObject::stringForRange(RefPtr<Range> range) const
1370 {
1371     if (!range)
1372         return String();
1373     
1374     TextIterator it(range.get());
1375     if (it.atEnd())
1376         return String();
1377     
1378     StringBuilder builder;
1379     for (; !it.atEnd(); it.advance()) {
1380         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
1381         if (it.text().length()) {
1382             // Add a textual representation for list marker text.
1383             // Don't add list marker text for new line character.
1384             if (it.text().length() != 1 || !isSpaceOrNewline(it.text()[0]))
1385                 builder.append(listMarkerTextForNodeAndPosition(it.node(), VisiblePosition(range->startPosition())));
1386             it.appendTextToStringBuilder(builder);
1387         } else {
1388             // locate the node and starting offset for this replaced range
1389             Node& node = it.range()->startContainer();
1390             ASSERT(&node == &it.range()->endContainer());
1391             int offset = it.range()->startOffset();
1392             if (replacedNodeNeedsCharacter(node.traverseToChildAt(offset)))
1393                 builder.append(objectReplacementCharacter);
1394         }
1395     }
1396     
1397     return builder.toString();
1398 }
1399
1400 String AccessibilityObject::stringForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange)
1401 {
1402     if (visiblePositionRange.isNull())
1403         return String();
1404
1405     StringBuilder builder;
1406     RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end);
1407     for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
1408         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
1409         if (it.text().length()) {
1410             // Add a textual representation for list marker text.
1411             builder.append(listMarkerTextForNodeAndPosition(it.node(), visiblePositionRange.start));
1412             it.appendTextToStringBuilder(builder);
1413         } else {
1414             // locate the node and starting offset for this replaced range
1415             Node& node = it.range()->startContainer();
1416             ASSERT(&node == &it.range()->endContainer());
1417             int offset = it.range()->startOffset();
1418             if (replacedNodeNeedsCharacter(node.traverseToChildAt(offset)))
1419                 builder.append(objectReplacementCharacter);
1420         }
1421     }
1422
1423     return builder.toString();
1424 }
1425
1426 int AccessibilityObject::lengthForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const
1427 {
1428     // FIXME: Multi-byte support
1429     if (visiblePositionRange.isNull())
1430         return -1;
1431     
1432     int length = 0;
1433     RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end);
1434     for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
1435         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
1436         if (it.text().length())
1437             length += it.text().length();
1438         else {
1439             // locate the node and starting offset for this replaced range
1440             Node& node = it.range()->startContainer();
1441             ASSERT(&node == &it.range()->endContainer());
1442             int offset = it.range()->startOffset();
1443
1444             if (replacedNodeNeedsCharacter(node.traverseToChildAt(offset)))
1445                 ++length;
1446         }
1447     }
1448     
1449     return length;
1450 }
1451
1452 VisiblePosition AccessibilityObject::visiblePositionForBounds(const IntRect& rect, AccessibilityVisiblePositionForBounds visiblePositionForBounds) const
1453 {
1454     if (rect.isEmpty())
1455         return VisiblePosition();
1456     
1457     MainFrame* mainFrame = this->mainFrame();
1458     if (!mainFrame)
1459         return VisiblePosition();
1460     
1461     // FIXME: Add support for right-to-left languages.
1462     IntPoint corner = (visiblePositionForBounds == FirstVisiblePositionForBounds) ? rect.minXMinYCorner() : rect.maxXMaxYCorner();
1463     VisiblePosition position = mainFrame->visiblePositionForPoint(corner);
1464     
1465     if (rect.contains(position.absoluteCaretBounds().center()))
1466         return position;
1467     
1468     // If the initial position is located outside the bounds adjust it incrementally as needed.
1469     VisiblePosition nextPosition = position.next();
1470     VisiblePosition previousPosition = position.previous();
1471     while (nextPosition.isNotNull() || previousPosition.isNotNull()) {
1472         if (rect.contains(nextPosition.absoluteCaretBounds().center()))
1473             return nextPosition;
1474         if (rect.contains(previousPosition.absoluteCaretBounds().center()))
1475             return previousPosition;
1476         
1477         nextPosition = nextPosition.next();
1478         previousPosition = previousPosition.previous();
1479     }
1480     
1481     return VisiblePosition();
1482 }
1483
1484 VisiblePosition AccessibilityObject::nextWordEnd(const VisiblePosition& visiblePos) const
1485 {
1486     if (visiblePos.isNull())
1487         return VisiblePosition();
1488
1489     // make sure we move off of a word end
1490     VisiblePosition nextVisiblePos = visiblePos.next();
1491     if (nextVisiblePos.isNull())
1492         return VisiblePosition();
1493
1494     return endOfWord(nextVisiblePos, LeftWordIfOnBoundary);
1495 }
1496
1497 VisiblePosition AccessibilityObject::previousWordStart(const VisiblePosition& visiblePos) const
1498 {
1499     if (visiblePos.isNull())
1500         return VisiblePosition();
1501
1502     // make sure we move off of a word start
1503     VisiblePosition prevVisiblePos = visiblePos.previous();
1504     if (prevVisiblePos.isNull())
1505         return VisiblePosition();
1506
1507     return startOfWord(prevVisiblePos, RightWordIfOnBoundary);
1508 }
1509
1510 VisiblePosition AccessibilityObject::nextLineEndPosition(const VisiblePosition& visiblePos) const
1511 {
1512     if (visiblePos.isNull())
1513         return VisiblePosition();
1514
1515     // to make sure we move off of a line end
1516     VisiblePosition nextVisiblePos = visiblePos.next();
1517     if (nextVisiblePos.isNull())
1518         return VisiblePosition();
1519
1520     VisiblePosition endPosition = endOfLine(nextVisiblePos);
1521
1522     // as long as the position hasn't reached the end of the doc,  keep searching for a valid line end position
1523     // There are cases like when the position is next to a floating object that'll return null for end of line. This code will avoid returning null.
1524     while (endPosition.isNull() && nextVisiblePos.isNotNull()) {
1525         nextVisiblePos = nextVisiblePos.next();
1526         endPosition = endOfLine(nextVisiblePos);
1527     }
1528
1529     return endPosition;
1530 }
1531
1532 VisiblePosition AccessibilityObject::previousLineStartPosition(const VisiblePosition& visiblePos) const
1533 {
1534     if (visiblePos.isNull())
1535         return VisiblePosition();
1536
1537     // make sure we move off of a line start
1538     VisiblePosition prevVisiblePos = visiblePos.previous();
1539     if (prevVisiblePos.isNull())
1540         return VisiblePosition();
1541
1542     VisiblePosition startPosition = startOfLine(prevVisiblePos);
1543
1544     // as long as the position hasn't reached the beginning of the doc,  keep searching for a valid line start position
1545     // There are cases like when the position is next to a floating object that'll return null for start of line. This code will avoid returning null.
1546     if (startPosition.isNull()) {
1547         while (startPosition.isNull() && prevVisiblePos.isNotNull()) {
1548             prevVisiblePos = prevVisiblePos.previous();
1549             startPosition = startOfLine(prevVisiblePos);
1550         }
1551     } else
1552         startPosition = updateAXLineStartForVisiblePosition(startPosition);
1553
1554     return startPosition;
1555 }
1556
1557 VisiblePosition AccessibilityObject::nextSentenceEndPosition(const VisiblePosition& visiblePos) const
1558 {
1559     // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
1560     // Related? <rdar://problem/3927736> Text selection broken in 8A336
1561     if (visiblePos.isNull())
1562         return VisiblePosition();
1563
1564     // make sure we move off of a sentence end
1565     VisiblePosition nextVisiblePos = visiblePos.next();
1566     if (nextVisiblePos.isNull())
1567         return VisiblePosition();
1568
1569     // an empty line is considered a sentence. If it's skipped, then the sentence parser will not
1570     // see this empty line.  Instead, return the end position of the empty line.
1571     VisiblePosition endPosition;
1572     
1573     String lineString = plainText(makeRange(startOfLine(nextVisiblePos), endOfLine(nextVisiblePos)).get());
1574     if (lineString.isEmpty())
1575         endPosition = nextVisiblePos;
1576     else
1577         endPosition = endOfSentence(nextVisiblePos);
1578
1579     return endPosition;
1580 }
1581
1582 VisiblePosition AccessibilityObject::previousSentenceStartPosition(const VisiblePosition& visiblePos) const
1583 {
1584     // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
1585     // Related? <rdar://problem/3927736> Text selection broken in 8A336
1586     if (visiblePos.isNull())
1587         return VisiblePosition();
1588
1589     // make sure we move off of a sentence start
1590     VisiblePosition previousVisiblePos = visiblePos.previous();
1591     if (previousVisiblePos.isNull())
1592         return VisiblePosition();
1593
1594     // treat empty line as a separate sentence.
1595     VisiblePosition startPosition;
1596     
1597     String lineString = plainText(makeRange(startOfLine(previousVisiblePos), endOfLine(previousVisiblePos)).get());
1598     if (lineString.isEmpty())
1599         startPosition = previousVisiblePos;
1600     else
1601         startPosition = startOfSentence(previousVisiblePos);
1602
1603     return startPosition;
1604 }
1605
1606 VisiblePosition AccessibilityObject::nextParagraphEndPosition(const VisiblePosition& visiblePos) const
1607 {
1608     if (visiblePos.isNull())
1609         return VisiblePosition();
1610
1611     // make sure we move off of a paragraph end
1612     VisiblePosition nextPos = visiblePos.next();
1613     if (nextPos.isNull())
1614         return VisiblePosition();
1615
1616     return endOfParagraph(nextPos);
1617 }
1618
1619 VisiblePosition AccessibilityObject::previousParagraphStartPosition(const VisiblePosition& visiblePos) const
1620 {
1621     if (visiblePos.isNull())
1622         return VisiblePosition();
1623
1624     // make sure we move off of a paragraph start
1625     VisiblePosition previousPos = visiblePos.previous();
1626     if (previousPos.isNull())
1627         return VisiblePosition();
1628
1629     return startOfParagraph(previousPos);
1630 }
1631
1632 AccessibilityObject* AccessibilityObject::accessibilityObjectForPosition(const VisiblePosition& visiblePos) const
1633 {
1634     if (visiblePos.isNull())
1635         return nullptr;
1636
1637     RenderObject* obj = visiblePos.deepEquivalent().deprecatedNode()->renderer();
1638     if (!obj)
1639         return nullptr;
1640
1641     return obj->document().axObjectCache()->getOrCreate(obj);
1642 }
1643     
1644 // If you call node->hasEditableStyle() since that will return true if an ancestor is editable.
1645 // This only returns true if this is the element that actually has the contentEditable attribute set.
1646 bool AccessibilityObject::hasContentEditableAttributeSet() const
1647 {
1648     return contentEditableAttributeIsEnabled(element());
1649 }
1650
1651 bool AccessibilityObject::supportsARIAReadOnly() const
1652 {
1653     AccessibilityRole role = roleValue();
1654
1655     return role == CheckBoxRole
1656         || role == ColumnHeaderRole
1657         || role == ComboBoxRole
1658         || role == GridRole
1659         || role == GridCellRole
1660         || role == ListBoxRole
1661         || role == MenuItemCheckboxRole
1662         || role == MenuItemRadioRole
1663         || role == RadioGroupRole
1664         || role == RowHeaderRole
1665         || role == SearchFieldRole
1666         || role == SliderRole
1667         || role == SpinButtonRole
1668         || role == SwitchRole
1669         || role == TextFieldRole
1670         || role == TreeGridRole
1671         || isPasswordField();
1672 }
1673
1674 String AccessibilityObject::ariaReadOnlyValue() const
1675 {
1676     if (!hasAttribute(aria_readonlyAttr))
1677         return ariaRoleAttribute() != UnknownRole && supportsARIAReadOnly() ? "false" : String();
1678
1679     return getAttribute(aria_readonlyAttr).string().convertToASCIILowercase();
1680 }
1681
1682 bool AccessibilityObject::supportsARIAAutoComplete() const
1683 {
1684     return (isComboBox() || isARIATextControl()) && hasAttribute(aria_autocompleteAttr);
1685 }
1686
1687 String AccessibilityObject::ariaAutoCompleteValue() const
1688 {
1689     const AtomicString& autoComplete = getAttribute(aria_autocompleteAttr);
1690     if (equalLettersIgnoringASCIICase(autoComplete, "inline")
1691         || equalLettersIgnoringASCIICase(autoComplete, "list")
1692         || equalLettersIgnoringASCIICase(autoComplete, "both"))
1693         return autoComplete;
1694
1695     return "none";
1696 }
1697
1698 bool AccessibilityObject::contentEditableAttributeIsEnabled(Element* element)
1699 {
1700     if (!element)
1701         return false;
1702     
1703     const AtomicString& contentEditableValue = element->attributeWithoutSynchronization(contenteditableAttr);
1704     if (contentEditableValue.isNull())
1705         return false;
1706     
1707     // Both "true" (case-insensitive) and the empty string count as true.
1708     return contentEditableValue.isEmpty() || equalLettersIgnoringASCIICase(contentEditableValue, "true");
1709 }
1710     
1711 #if HAVE(ACCESSIBILITY)
1712 int AccessibilityObject::lineForPosition(const VisiblePosition& visiblePos) const
1713 {
1714     if (visiblePos.isNull() || !node())
1715         return -1;
1716
1717     // If the position is not in the same editable region as this AX object, return -1.
1718     Node* containerNode = visiblePos.deepEquivalent().containerNode();
1719     if (!containerNode->containsIncludingShadowDOM(node()) && !node()->containsIncludingShadowDOM(containerNode))
1720         return -1;
1721
1722     int lineCount = -1;
1723     VisiblePosition currentVisiblePos = visiblePos;
1724     VisiblePosition savedVisiblePos;
1725
1726     // move up until we get to the top
1727     // FIXME: This only takes us to the top of the rootEditableElement, not the top of the
1728     // top document.
1729     do {
1730         savedVisiblePos = currentVisiblePos;
1731         VisiblePosition prevVisiblePos = previousLinePosition(currentVisiblePos, 0, HasEditableAXRole);
1732         currentVisiblePos = prevVisiblePos;
1733         ++lineCount;
1734     }  while (currentVisiblePos.isNotNull() && !(inSameLine(currentVisiblePos, savedVisiblePos)));
1735
1736     return lineCount;
1737 }
1738 #endif
1739
1740 // NOTE: Consider providing this utility method as AX API
1741 PlainTextRange AccessibilityObject::plainTextRangeForVisiblePositionRange(const VisiblePositionRange& positionRange) const
1742 {
1743     int index1 = index(positionRange.start);
1744     int index2 = index(positionRange.end);
1745     if (index1 < 0 || index2 < 0 || index1 > index2)
1746         return PlainTextRange();
1747
1748     return PlainTextRange(index1, index2 - index1);
1749 }
1750
1751 // The composed character range in the text associated with this accessibility object that
1752 // is specified by the given screen coordinates. This parameterized attribute returns the
1753 // complete range of characters (including surrogate pairs of multi-byte glyphs) at the given
1754 // screen coordinates.
1755 // NOTE: This varies from AppKit when the point is below the last line. AppKit returns an
1756 // an error in that case. We return textControl->text().length(), 1. Does this matter?
1757 PlainTextRange AccessibilityObject::doAXRangeForPosition(const IntPoint& point) const
1758 {
1759     int i = index(visiblePositionForPoint(point));
1760     if (i < 0)
1761         return PlainTextRange();
1762
1763     return PlainTextRange(i, 1);
1764 }
1765
1766 // Given a character index, the range of text associated with this accessibility object
1767 // over which the style in effect at that character index applies.
1768 PlainTextRange AccessibilityObject::doAXStyleRangeForIndex(unsigned index) const
1769 {
1770     VisiblePositionRange range = styleRangeForPosition(visiblePositionForIndex(index, false));
1771     return plainTextRangeForVisiblePositionRange(range);
1772 }
1773
1774 // Given an indexed character, the line number of the text associated with this accessibility
1775 // object that contains the character.
1776 unsigned AccessibilityObject::doAXLineForIndex(unsigned index)
1777 {
1778     return lineForPosition(visiblePositionForIndex(index, false));
1779 }
1780
1781 #if HAVE(ACCESSIBILITY)
1782 void AccessibilityObject::updateBackingStore()
1783 {
1784     // Updating the layout may delete this object.
1785     RefPtr<AccessibilityObject> protectedThis(this);
1786
1787     if (Document* document = this->document()) {
1788         if (!document->view()->isInRenderTreeLayout())
1789             document->updateLayoutIgnorePendingStylesheets();
1790     }
1791     
1792     updateChildrenIfNecessary();
1793 }
1794 #endif
1795     
1796 ScrollView* AccessibilityObject::scrollViewAncestor() const
1797 {
1798     if (const AccessibilityObject* scrollParent = AccessibilityObject::matchedParent(*this, true, [] (const AccessibilityObject& object) {
1799         return is<AccessibilityScrollView>(object);
1800     }))
1801         return downcast<AccessibilityScrollView>(*scrollParent).scrollView();
1802     
1803     return nullptr;
1804 }
1805     
1806 Document* AccessibilityObject::document() const
1807 {
1808     FrameView* frameView = documentFrameView();
1809     if (!frameView)
1810         return nullptr;
1811     
1812     return frameView->frame().document();
1813 }
1814     
1815 Page* AccessibilityObject::page() const
1816 {
1817     Document* document = this->document();
1818     if (!document)
1819         return nullptr;
1820     return document->page();
1821 }
1822
1823 FrameView* AccessibilityObject::documentFrameView() const 
1824
1825     const AccessibilityObject* object = this;
1826     while (object && !object->isAccessibilityRenderObject()) 
1827         object = object->parentObject();
1828         
1829     if (!object)
1830         return nullptr;
1831
1832     return object->documentFrameView();
1833 }
1834
1835 #if HAVE(ACCESSIBILITY)
1836 const AccessibilityObject::AccessibilityChildrenVector& AccessibilityObject::children(bool updateChildrenIfNeeded)
1837 {
1838     if (updateChildrenIfNeeded)
1839         updateChildrenIfNecessary();
1840
1841     return m_children;
1842 }
1843 #endif
1844
1845 void AccessibilityObject::updateChildrenIfNecessary()
1846 {
1847     if (!hasChildren()) {
1848         // Enable the cache in case we end up adding a lot of children, we don't want to recompute axIsIgnored each time.
1849         AXAttributeCacheEnabler enableCache(axObjectCache());
1850         addChildren();
1851     }
1852 }
1853     
1854 void AccessibilityObject::clearChildren()
1855 {
1856     // Some objects have weak pointers to their parents and those associations need to be detached.
1857     for (const auto& child : m_children)
1858         child->detachFromParent();
1859     
1860     m_children.clear();
1861     m_haveChildren = false;
1862 }
1863
1864 AccessibilityObject* AccessibilityObject::anchorElementForNode(Node* node)
1865 {
1866     RenderObject* obj = node->renderer();
1867     if (!obj)
1868         return nullptr;
1869     
1870     RefPtr<AccessibilityObject> axObj = obj->document().axObjectCache()->getOrCreate(obj);
1871     Element* anchor = axObj->anchorElement();
1872     if (!anchor)
1873         return nullptr;
1874     
1875     RenderObject* anchorRenderer = anchor->renderer();
1876     if (!anchorRenderer)
1877         return nullptr;
1878     
1879     return anchorRenderer->document().axObjectCache()->getOrCreate(anchorRenderer);
1880 }
1881
1882 AccessibilityObject* AccessibilityObject::headingElementForNode(Node* node)
1883 {
1884     if (!node)
1885         return nullptr;
1886     
1887     RenderObject* renderObject = node->renderer();
1888     if (!renderObject)
1889         return nullptr;
1890     
1891     AccessibilityObject* axObject = renderObject->document().axObjectCache()->getOrCreate(renderObject);
1892     
1893     return const_cast<AccessibilityObject*>(AccessibilityObject::matchedParent(*axObject, true, [] (const AccessibilityObject& object) {
1894         return object.roleValue() == HeadingRole;
1895     }));
1896 }
1897
1898 const AccessibilityObject* AccessibilityObject::matchedParent(const AccessibilityObject& object, bool includeSelf, const WTF::Function<bool(const AccessibilityObject&)>& matches)
1899 {
1900     const AccessibilityObject* parent = includeSelf ? &object : object.parentObject();
1901     for (; parent; parent = parent->parentObject()) {
1902         if (matches(*parent))
1903             return parent;
1904     }
1905     return nullptr;
1906 }
1907
1908 void AccessibilityObject::ariaTreeRows(AccessibilityChildrenVector& result)
1909 {
1910     for (const auto& child : children()) {
1911         // Add tree items as the rows.
1912         if (child->roleValue() == TreeItemRole)
1913             result.append(child);
1914
1915         // Now see if this item also has rows hiding inside of it.
1916         child->ariaTreeRows(result);
1917     }
1918 }
1919     
1920 void AccessibilityObject::ariaTreeItemContent(AccessibilityChildrenVector& result)
1921 {
1922     // The ARIA tree item content are the item that are not other tree items or their containing groups.
1923     for (const auto& child : children()) {
1924         if (!child->isGroup() && child->roleValue() != TreeItemRole)
1925             result.append(child);
1926     }
1927 }
1928
1929 void AccessibilityObject::ariaTreeItemDisclosedRows(AccessibilityChildrenVector& result)
1930 {
1931     for (const auto& obj : children()) {
1932         // Add tree items as the rows.
1933         if (obj->roleValue() == TreeItemRole)
1934             result.append(obj);
1935         // If it's not a tree item, then descend into the group to find more tree items.
1936         else 
1937             obj->ariaTreeRows(result);
1938     }    
1939 }
1940     
1941 const String AccessibilityObject::defaultLiveRegionStatusForRole(AccessibilityRole role)
1942 {
1943     switch (role) {
1944     case ApplicationAlertDialogRole:
1945     case ApplicationAlertRole:
1946         return ASCIILiteral("assertive");
1947     case ApplicationLogRole:
1948     case ApplicationStatusRole:
1949         return ASCIILiteral("polite");
1950     case ApplicationTimerRole:
1951     case ApplicationMarqueeRole:
1952         return ASCIILiteral("off");
1953     default:
1954         return nullAtom();
1955     }
1956 }
1957     
1958 #if HAVE(ACCESSIBILITY)
1959 const String& AccessibilityObject::actionVerb() const
1960 {
1961 #if !PLATFORM(IOS)
1962     // FIXME: Need to add verbs for select elements.
1963     static NeverDestroyed<const String> buttonAction(AXButtonActionVerb());
1964     static NeverDestroyed<const String> textFieldAction(AXTextFieldActionVerb());
1965     static NeverDestroyed<const String> radioButtonAction(AXRadioButtonActionVerb());
1966     static NeverDestroyed<const String> checkedCheckBoxAction(AXCheckedCheckBoxActionVerb());
1967     static NeverDestroyed<const String> uncheckedCheckBoxAction(AXUncheckedCheckBoxActionVerb());
1968     static NeverDestroyed<const String> linkAction(AXLinkActionVerb());
1969     static NeverDestroyed<const String> menuListAction(AXMenuListActionVerb());
1970     static NeverDestroyed<const String> menuListPopupAction(AXMenuListPopupActionVerb());
1971     static NeverDestroyed<const String> listItemAction(AXListItemActionVerb());
1972
1973     switch (roleValue()) {
1974     case ButtonRole:
1975     case ToggleButtonRole:
1976         return buttonAction;
1977     case TextFieldRole:
1978     case TextAreaRole:
1979         return textFieldAction;
1980     case RadioButtonRole:
1981         return radioButtonAction;
1982     case CheckBoxRole:
1983     case SwitchRole:
1984         return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction;
1985     case LinkRole:
1986     case WebCoreLinkRole:
1987         return linkAction;
1988     case PopUpButtonRole:
1989         return menuListAction;
1990     case MenuListPopupRole:
1991         return menuListPopupAction;
1992     case ListItemRole:
1993         return listItemAction;
1994     default:
1995         return nullAtom();
1996     }
1997 #else
1998     return nullAtom();
1999 #endif
2000 }
2001 #endif
2002
2003 bool AccessibilityObject::ariaIsMultiline() const
2004 {
2005     return equalLettersIgnoringASCIICase(getAttribute(aria_multilineAttr), "true");
2006 }
2007
2008 String AccessibilityObject::invalidStatus() const
2009 {
2010     String grammarValue = ASCIILiteral("grammar");
2011     String falseValue = ASCIILiteral("false");
2012     String spellingValue = ASCIILiteral("spelling");
2013     String trueValue = ASCIILiteral("true");
2014     String undefinedValue = ASCIILiteral("undefined");
2015
2016     // aria-invalid can return false (default), grammar, spelling, or true.
2017     String ariaInvalid = stripLeadingAndTrailingHTMLSpaces(getAttribute(aria_invalidAttr));
2018     
2019     if (ariaInvalid.isEmpty()) {
2020         // We should expose invalid status for input types.
2021         Node* node = this->node();
2022         if (node && is<HTMLInputElement>(*node)) {
2023             HTMLInputElement& input = downcast<HTMLInputElement>(*node);
2024             if (input.hasBadInput() || input.typeMismatch())
2025                 return trueValue;
2026         }
2027         return falseValue;
2028     }
2029     
2030     // If "false", "undefined" [sic, string value], empty, or missing, return "false".
2031     if (ariaInvalid == falseValue || ariaInvalid == undefinedValue)
2032         return falseValue;
2033     // Besides true/false/undefined, the only tokens defined by WAI-ARIA 1.0...
2034     // ...for @aria-invalid are "grammar" and "spelling".
2035     if (ariaInvalid == grammarValue)
2036         return grammarValue;
2037     if (ariaInvalid == spellingValue)
2038         return spellingValue;
2039     // Any other non empty string should be treated as "true".
2040     return trueValue;
2041 }
2042
2043 bool AccessibilityObject::supportsARIACurrent() const
2044 {
2045     return hasAttribute(aria_currentAttr);
2046 }
2047  
2048 AccessibilityARIACurrentState AccessibilityObject::ariaCurrentState() const
2049 {
2050     // aria-current can return false (default), true, page, step, location, date or time.
2051     String currentStateValue = stripLeadingAndTrailingHTMLSpaces(getAttribute(aria_currentAttr));
2052     
2053     // If "false", empty, or missing, return false state.
2054     if (currentStateValue.isEmpty() || currentStateValue == "false")
2055         return ARIACurrentFalse;
2056     
2057     if (currentStateValue == "page")
2058         return ARIACurrentPage;
2059     if (currentStateValue == "step")
2060         return ARIACurrentStep;
2061     if (currentStateValue == "location")
2062         return ARIACurrentLocation;
2063     if (currentStateValue == "date")
2064         return ARIACurrentDate;
2065     if (currentStateValue == "time")
2066         return ARIACurrentTime;
2067     
2068     // Any value not included in the list of allowed values should be treated as "true".
2069     return ARIACurrentTrue;
2070 }
2071
2072 String AccessibilityObject::ariaCurrentValue() const
2073 {
2074     switch (ariaCurrentState()) {
2075     case ARIACurrentFalse:
2076         return "false";
2077     case ARIACurrentPage:
2078         return "page";
2079     case ARIACurrentStep:
2080         return "step";
2081     case ARIACurrentLocation:
2082         return "location";
2083     case ARIACurrentTime:
2084         return "time";
2085     case ARIACurrentDate:
2086         return "date";
2087     default:
2088     case ARIACurrentTrue:
2089         return "true";
2090     }
2091 }
2092
2093 bool AccessibilityObject::isAriaModalDescendant(Node* ariaModalNode) const
2094 {
2095     if (!ariaModalNode || !this->element())
2096         return false;
2097     
2098     if (this->element() == ariaModalNode)
2099         return true;
2100     
2101     // ARIA 1.1 aria-modal, indicates whether an element is modal when displayed.
2102     // For the decendants of the modal object, they should also be considered as aria-modal=true.
2103     for (auto& ancestor : elementAncestors(this->element())) {
2104         if (&ancestor == ariaModalNode)
2105             return true;
2106     }
2107     return false;
2108 }
2109
2110 bool AccessibilityObject::isAriaModalNode() const
2111 {
2112     if (AXObjectCache* cache = axObjectCache())
2113         return node() && cache->ariaModalNode() == node();
2114
2115     return false;
2116 }
2117
2118 bool AccessibilityObject::ignoredFromARIAModalPresence() const
2119 {
2120     // We shouldn't ignore the top node.
2121     if (!node() || !node()->parentNode())
2122         return false;
2123     
2124     AXObjectCache* cache = axObjectCache();
2125     if (!cache)
2126         return false;
2127     
2128     // ariaModalNode is the current displayed modal dialog.
2129     Node* ariaModalNode = cache->ariaModalNode();
2130     if (!ariaModalNode)
2131         return false;
2132     
2133     // We only want to ignore the objects within the same frame as the modal dialog.
2134     if (ariaModalNode->document().frame() != this->frame())
2135         return false;
2136     
2137     return !isAriaModalDescendant(ariaModalNode);
2138 }
2139
2140 bool AccessibilityObject::hasTagName(const QualifiedName& tagName) const
2141 {
2142     Node* node = this->node();
2143     return is<Element>(node) && downcast<Element>(*node).hasTagName(tagName);
2144 }
2145     
2146 bool AccessibilityObject::hasAttribute(const QualifiedName& attribute) const
2147 {
2148     Node* node = this->node();
2149     if (!is<Element>(node))
2150         return false;
2151     
2152     return downcast<Element>(*node).hasAttributeWithoutSynchronization(attribute);
2153 }
2154     
2155 const AtomicString& AccessibilityObject::getAttribute(const QualifiedName& attribute) const
2156 {
2157     if (Element* element = this->element())
2158         return element->attributeWithoutSynchronization(attribute);
2159     return nullAtom();
2160 }
2161     
2162 // Lacking concrete evidence of orientation, horizontal means width > height. vertical is height > width;
2163 AccessibilityOrientation AccessibilityObject::orientation() const
2164 {
2165     LayoutRect bounds = elementRect();
2166     if (bounds.size().width() > bounds.size().height())
2167         return AccessibilityOrientationHorizontal;
2168     if (bounds.size().height() > bounds.size().width())
2169         return AccessibilityOrientationVertical;
2170
2171     return AccessibilityOrientationUndefined;
2172 }    
2173
2174 bool AccessibilityObject::isDescendantOfObject(const AccessibilityObject* axObject) const
2175 {
2176     if (!axObject || !axObject->hasChildren())
2177         return false;
2178     
2179     return AccessibilityObject::matchedParent(*this, false, [axObject] (const AccessibilityObject& object) {
2180         return &object == axObject;
2181     }) != nullptr;
2182 }
2183
2184 bool AccessibilityObject::isAncestorOfObject(const AccessibilityObject* axObject) const
2185 {
2186     if (!axObject)
2187         return false;
2188
2189     return this == axObject || axObject->isDescendantOfObject(this);
2190 }
2191
2192 AccessibilityObject* AccessibilityObject::firstAnonymousBlockChild() const
2193 {
2194     for (AccessibilityObject* child = firstChild(); child; child = child->nextSibling()) {
2195         if (child->renderer() && child->renderer()->isAnonymousBlock())
2196             return child;
2197     }
2198     return nullptr;
2199 }
2200
2201 using ARIARoleMap = HashMap<String, AccessibilityRole, ASCIICaseInsensitiveHash>;
2202 using ARIAReverseRoleMap = HashMap<AccessibilityRole, String, DefaultHash<int>::Hash, WTF::UnsignedWithZeroKeyHashTraits<int>>;
2203
2204 static ARIARoleMap* gAriaRoleMap = nullptr;
2205 static ARIAReverseRoleMap* gAriaReverseRoleMap = nullptr;
2206
2207 struct RoleEntry {
2208     String ariaRole;
2209     AccessibilityRole webcoreRole;
2210 };
2211
2212 static void initializeRoleMap()
2213 {
2214     if (gAriaRoleMap)
2215         return;
2216     ASSERT(!gAriaReverseRoleMap);
2217
2218     const RoleEntry roles[] = {
2219         { "alert", ApplicationAlertRole },
2220         { "alertdialog", ApplicationAlertDialogRole },
2221         { "application", WebApplicationRole },
2222         { "article", DocumentArticleRole },
2223         { "banner", LandmarkBannerRole },
2224         { "button", ButtonRole },
2225         { "checkbox", CheckBoxRole },
2226         { "complementary", LandmarkComplementaryRole },
2227         { "contentinfo", LandmarkContentInfoRole },
2228         { "dialog", ApplicationDialogRole },
2229         { "directory", DirectoryRole },
2230         // The 'doc-*' roles are defined the ARIA DPUB mobile: https://www.w3.org/TR/dpub-aam-1.0/ 
2231         // Editor's draft is currently at https://rawgit.com/w3c/aria/master/dpub-aam/dpub-aam.html 
2232         { "doc-abstract", ApplicationTextGroupRole },
2233         { "doc-acknowledgments", LandmarkDocRegionRole },
2234         { "doc-afterword", LandmarkDocRegionRole },
2235         { "doc-appendix", LandmarkDocRegionRole },
2236         { "doc-backlink", WebCoreLinkRole },
2237         { "doc-biblioentry", ListItemRole },
2238         { "doc-bibliography", LandmarkDocRegionRole },
2239         { "doc-biblioref", WebCoreLinkRole },
2240         { "doc-chapter", LandmarkDocRegionRole },
2241         { "doc-colophon", ApplicationTextGroupRole },
2242         { "doc-conclusion", LandmarkDocRegionRole },
2243         { "doc-cover", ImageRole },
2244         { "doc-credit", ApplicationTextGroupRole },
2245         { "doc-credits", LandmarkDocRegionRole },
2246         { "doc-dedication", ApplicationTextGroupRole },
2247         { "doc-endnote", ListItemRole },
2248         { "doc-endnotes", LandmarkDocRegionRole },
2249         { "doc-epigraph", ApplicationTextGroupRole },
2250         { "doc-epilogue", LandmarkDocRegionRole },
2251         { "doc-errata", LandmarkDocRegionRole },
2252         { "doc-example", ApplicationTextGroupRole },
2253         { "doc-footnote", FootnoteRole },
2254         { "doc-foreword", LandmarkDocRegionRole },
2255         { "doc-glossary", LandmarkDocRegionRole },
2256         { "doc-glossref", WebCoreLinkRole },
2257         { "doc-index", LandmarkNavigationRole },
2258         { "doc-introduction", LandmarkDocRegionRole },
2259         { "doc-noteref", WebCoreLinkRole },
2260         { "doc-notice", DocumentNoteRole },
2261         { "doc-pagebreak", SplitterRole },
2262         { "doc-pagelist", LandmarkNavigationRole },
2263         { "doc-part", LandmarkDocRegionRole },
2264         { "doc-preface", LandmarkDocRegionRole },
2265         { "doc-prologue", LandmarkDocRegionRole },
2266         { "doc-pullquote", ApplicationTextGroupRole },
2267         { "doc-qna", ApplicationTextGroupRole },
2268         { "doc-subtitle", HeadingRole },
2269         { "doc-tip", DocumentNoteRole },
2270         { "doc-toc", LandmarkNavigationRole },
2271         { "figure", FigureRole },
2272         { "grid", GridRole },
2273         { "gridcell", GridCellRole },
2274         { "table", TableRole },
2275         { "cell", CellRole },
2276         { "columnheader", ColumnHeaderRole },
2277         { "combobox", ComboBoxRole },
2278         { "definition", DefinitionRole },
2279         { "document", DocumentRole },
2280         { "feed", FeedRole },
2281         { "form", FormRole },
2282         { "rowheader", RowHeaderRole },
2283         { "group", ApplicationGroupRole },
2284         { "heading", HeadingRole },
2285         { "img", ImageRole },
2286         { "link", WebCoreLinkRole },
2287         { "list", ListRole },        
2288         { "listitem", ListItemRole },        
2289         { "listbox", ListBoxRole },
2290         { "log", ApplicationLogRole },
2291         { "main", LandmarkMainRole },
2292         { "marquee", ApplicationMarqueeRole },
2293         { "math", DocumentMathRole },
2294         { "menu", MenuRole },
2295         { "menubar", MenuBarRole },
2296         { "menuitem", MenuItemRole },
2297         { "menuitemcheckbox", MenuItemCheckboxRole },
2298         { "menuitemradio", MenuItemRadioRole },
2299         { "none", PresentationalRole },
2300         { "note", DocumentNoteRole },
2301         { "navigation", LandmarkNavigationRole },
2302         { "option", ListBoxOptionRole },
2303         { "presentation", PresentationalRole },
2304         { "progressbar", ProgressIndicatorRole },
2305         { "radio", RadioButtonRole },
2306         { "radiogroup", RadioGroupRole },
2307         { "region", LandmarkRegionRole },
2308         { "row", RowRole },
2309         { "rowgroup", RowGroupRole },
2310         { "scrollbar", ScrollBarRole },
2311         { "search", LandmarkSearchRole },
2312         { "searchbox", SearchFieldRole },
2313         { "separator", SplitterRole },
2314         { "slider", SliderRole },
2315         { "spinbutton", SpinButtonRole },
2316         { "status", ApplicationStatusRole },
2317         { "switch", SwitchRole },
2318         { "tab", TabRole },
2319         { "tablist", TabListRole },
2320         { "tabpanel", TabPanelRole },
2321         { "text", StaticTextRole },
2322         { "textbox", TextAreaRole },
2323         { "term", TermRole },
2324         { "timer", ApplicationTimerRole },
2325         { "toolbar", ToolbarRole },
2326         { "tooltip", UserInterfaceTooltipRole },
2327         { "tree", TreeRole },
2328         { "treegrid", TreeGridRole },
2329         { "treeitem", TreeItemRole }
2330     };
2331
2332     gAriaRoleMap = new ARIARoleMap;
2333     gAriaReverseRoleMap = new ARIAReverseRoleMap;
2334     size_t roleLength = WTF_ARRAY_LENGTH(roles);
2335     for (size_t i = 0; i < roleLength; ++i) {
2336         gAriaRoleMap->set(roles[i].ariaRole, roles[i].webcoreRole);
2337         gAriaReverseRoleMap->set(roles[i].webcoreRole, roles[i].ariaRole);
2338     }
2339 }
2340
2341 static ARIARoleMap& ariaRoleMap()
2342 {
2343     initializeRoleMap();
2344     return *gAriaRoleMap;
2345 }
2346
2347 static ARIAReverseRoleMap& reverseAriaRoleMap()
2348 {
2349     initializeRoleMap();
2350     return *gAriaReverseRoleMap;
2351 }
2352
2353 AccessibilityRole AccessibilityObject::ariaRoleToWebCoreRole(const String& value)
2354 {
2355     ASSERT(!value.isEmpty());
2356     for (auto roleName : StringView(value).split(' ')) {
2357         if (AccessibilityRole role = ariaRoleMap().get<ASCIICaseInsensitiveStringViewHashTranslator>(roleName))
2358             return role;
2359     }
2360     return UnknownRole;
2361 }
2362
2363 String AccessibilityObject::computedRoleString() const
2364 {
2365     // FIXME: Need a few special cases that aren't in the RoleMap: option, etc. http://webkit.org/b/128296
2366     AccessibilityRole role = roleValue();
2367
2368     // We do not compute a role string for generic block elements with user-agent assigned roles.
2369     if (role == GroupRole || role == TextGroupRole)
2370         return "";
2371
2372     // We do compute a role string for block elements with author-provided roles.
2373     if (role == ApplicationTextGroupRole || role == FootnoteRole)
2374         return reverseAriaRoleMap().get(ApplicationGroupRole);
2375
2376     if (role == HorizontalRuleRole)
2377         return reverseAriaRoleMap().get(SplitterRole);
2378
2379     if (role == PopUpButtonRole || role == ToggleButtonRole)
2380         return reverseAriaRoleMap().get(ButtonRole);
2381
2382     if (role == LandmarkDocRegionRole)
2383         return reverseAriaRoleMap().get(LandmarkRegionRole);
2384
2385     return reverseAriaRoleMap().get(role);
2386 }
2387
2388 bool AccessibilityObject::hasHighlighting() const
2389 {
2390     for (Node* node = this->node(); node; node = node->parentNode()) {
2391         if (node->hasTagName(markTag))
2392             return true;
2393     }
2394     
2395     return false;
2396 }
2397
2398 String AccessibilityObject::roleDescription() const
2399 {
2400     return stripLeadingAndTrailingHTMLSpaces(getAttribute(aria_roledescriptionAttr));
2401 }
2402     
2403 bool nodeHasPresentationRole(Node* node)
2404 {
2405     return nodeHasRole(node, "presentation") || nodeHasRole(node, "none");
2406 }
2407     
2408 bool AccessibilityObject::supportsPressAction() const
2409 {
2410     if (isButton())
2411         return true;
2412     if (roleValue() == DetailsRole)
2413         return true;
2414     
2415     Element* actionElement = this->actionElement();
2416     if (!actionElement)
2417         return false;
2418     
2419     // [Bug: 136247] Heuristic: element handlers that have more than one accessible descendant should not be exposed as supporting press.
2420     if (actionElement != element()) {
2421         if (AccessibilityObject* axObj = axObjectCache()->getOrCreate(actionElement)) {
2422             AccessibilityChildrenVector results;
2423             // Search within for immediate descendants that are static text. If we find more than one
2424             // then this is an event delegator actionElement and we should expose the press action.
2425             Vector<AccessibilitySearchKey> keys({ StaticTextSearchKey, ControlSearchKey, GraphicSearchKey, HeadingSearchKey, LinkSearchKey });
2426             AccessibilitySearchCriteria criteria(axObj, SearchDirectionNext, emptyString(), 2, false, false);
2427             criteria.searchKeys = keys;
2428             axObj->findMatchingObjects(&criteria, results);
2429             if (results.size() > 1)
2430                 return false;
2431         }
2432     }
2433     
2434     // [Bug: 133613] Heuristic: If the action element is presentational, we shouldn't expose press as a supported action.
2435     return !nodeHasPresentationRole(actionElement);
2436 }
2437
2438 bool AccessibilityObject::supportsDatetimeAttribute() const
2439 {
2440     return hasTagName(insTag) || hasTagName(delTag) || hasTagName(timeTag);
2441 }
2442
2443 const AtomicString& AccessibilityObject::datetimeAttributeValue() const
2444 {
2445     return getAttribute(datetimeAttr);
2446 }
2447     
2448 Element* AccessibilityObject::element() const
2449 {
2450     Node* node = this->node();
2451     if (is<Element>(node))
2452         return downcast<Element>(node);
2453     return nullptr;
2454 }
2455     
2456 bool AccessibilityObject::isValueAutofillAvailable() const
2457 {
2458     if (!isNativeTextControl())
2459         return false;
2460     
2461     Node* node = this->node();
2462     if (!is<HTMLInputElement>(node))
2463         return false;
2464     
2465     return downcast<HTMLInputElement>(*node).isAutoFillAvailable() || downcast<HTMLInputElement>(*node).autoFillButtonType() != AutoFillButtonType::None;
2466 }
2467
2468 AutoFillButtonType AccessibilityObject::valueAutofillButtonType() const
2469 {
2470     if (!isValueAutofillAvailable())
2471         return AutoFillButtonType::None;
2472     
2473     return downcast<HTMLInputElement>(*this->node()).autoFillButtonType();
2474 }
2475     
2476 bool AccessibilityObject::isValueAutofilled() const
2477 {
2478     if (!isNativeTextControl())
2479         return false;
2480     
2481     Node* node = this->node();
2482     if (!is<HTMLInputElement>(node))
2483         return false;
2484     
2485     return downcast<HTMLInputElement>(*node).isAutoFilled();
2486 }
2487
2488 const AtomicString& AccessibilityObject::placeholderValue() const
2489 {
2490     const AtomicString& placeholder = getAttribute(placeholderAttr);
2491     if (!placeholder.isEmpty())
2492         return placeholder;
2493     
2494     const AtomicString& ariaPlaceholder = getAttribute(aria_placeholderAttr);
2495     if (!ariaPlaceholder.isEmpty())
2496         return ariaPlaceholder;
2497     
2498     return nullAtom();
2499 }
2500     
2501 bool AccessibilityObject::isInsideARIALiveRegion(bool excludeIfOff) const
2502 {
2503     return ariaLiveRegionAncestor(excludeIfOff);
2504 }
2505     
2506 AccessibilityObject* AccessibilityObject::ariaLiveRegionAncestor(bool excludeIfOff) const
2507 {
2508     return const_cast<AccessibilityObject*>(AccessibilityObject::matchedParent(*this, true, [excludeIfOff] (const AccessibilityObject& object) {
2509         return object.supportsARIALiveRegion(excludeIfOff);
2510     }));
2511 }
2512
2513 bool AccessibilityObject::supportsARIAAttributes() const
2514 {
2515     // This returns whether the element supports any global ARIA attributes.
2516     return supportsARIALiveRegion()
2517         || supportsARIADragging()
2518         || supportsARIADropping()
2519         || supportsARIAOwns()
2520         || hasAttribute(aria_atomicAttr)
2521         || hasAttribute(aria_busyAttr)
2522         || hasAttribute(aria_controlsAttr)
2523         || hasAttribute(aria_currentAttr)
2524         || hasAttribute(aria_describedbyAttr)
2525         || hasAttribute(aria_detailsAttr)
2526         || hasAttribute(aria_disabledAttr)
2527         || hasAttribute(aria_errormessageAttr)
2528         || hasAttribute(aria_flowtoAttr)
2529         || hasAttribute(aria_haspopupAttr)
2530         || hasAttribute(aria_invalidAttr)
2531         || hasAttribute(aria_labelAttr)
2532         || hasAttribute(aria_labelledbyAttr)
2533         || hasAttribute(aria_relevantAttr);
2534 }
2535     
2536 bool AccessibilityObject::liveRegionStatusIsEnabled(const AtomicString& liveRegionStatus)
2537 {
2538     return equalLettersIgnoringASCIICase(liveRegionStatus, "polite") || equalLettersIgnoringASCIICase(liveRegionStatus, "assertive");
2539 }
2540     
2541 bool AccessibilityObject::supportsARIALiveRegion(bool excludeIfOff) const
2542 {
2543     const AtomicString& liveRegionStatus = ariaLiveRegionStatus();
2544     return excludeIfOff ? liveRegionStatusIsEnabled(liveRegionStatus) : !liveRegionStatus.isEmpty();
2545 }
2546
2547 AccessibilityObject* AccessibilityObject::elementAccessibilityHitTest(const IntPoint& point) const
2548
2549     // Send the hit test back into the sub-frame if necessary.
2550     if (isAttachment()) {
2551         Widget* widget = widgetForAttachmentView();
2552         // Normalize the point for the widget's bounds.
2553         if (widget && widget->isFrameView()) {
2554             if (AXObjectCache* cache = axObjectCache())
2555                 return cache->getOrCreate(widget)->accessibilityHitTest(IntPoint(point - widget->frameRect().location()));
2556         }
2557     }
2558     
2559     // Check if there are any mock elements that need to be handled.
2560     for (const auto& child : m_children) {
2561         if (child->isMockObject() && child->elementRect().contains(point))
2562             return child->elementAccessibilityHitTest(point);
2563     }
2564
2565     return const_cast<AccessibilityObject*>(this);
2566 }
2567     
2568 AXObjectCache* AccessibilityObject::axObjectCache() const
2569 {
2570     Document* doc = document();
2571     if (doc)
2572         return doc->axObjectCache();
2573     return nullptr;
2574 }
2575     
2576 AccessibilityObject* AccessibilityObject::focusedUIElement() const
2577 {
2578     Document* doc = document();
2579     if (!doc)
2580         return nullptr;
2581     
2582     Page* page = doc->page();
2583     if (!page)
2584         return nullptr;
2585     
2586     return AXObjectCache::focusedUIElementForPage(page);
2587 }
2588     
2589 AccessibilitySortDirection AccessibilityObject::sortDirection() const
2590 {
2591     const AtomicString& sortAttribute = getAttribute(aria_sortAttr);
2592     if (equalLettersIgnoringASCIICase(sortAttribute, "ascending"))
2593         return SortDirectionAscending;
2594     if (equalLettersIgnoringASCIICase(sortAttribute, "descending"))
2595         return SortDirectionDescending;
2596     if (equalLettersIgnoringASCIICase(sortAttribute, "other"))
2597         return SortDirectionOther;
2598     
2599     return SortDirectionNone;
2600 }
2601
2602 bool AccessibilityObject::supportsRangeValue() const
2603 {
2604     return isProgressIndicator()
2605         || isSlider()
2606         || isScrollbar()
2607         || isSpinButton()
2608         || (isSplitter() && canSetFocusAttribute())
2609         || isAttachmentElement();
2610 }
2611     
2612 bool AccessibilityObject::supportsARIAHasPopup() const
2613 {
2614     return hasAttribute(aria_haspopupAttr) || isComboBox();
2615 }
2616
2617 String AccessibilityObject::ariaPopupValue() const
2618 {
2619     const AtomicString& hasPopup = getAttribute(aria_haspopupAttr);
2620     if (equalLettersIgnoringASCIICase(hasPopup, "true")
2621         || equalLettersIgnoringASCIICase(hasPopup, "dialog")
2622         || equalLettersIgnoringASCIICase(hasPopup, "grid")
2623         || equalLettersIgnoringASCIICase(hasPopup, "listbox")
2624         || equalLettersIgnoringASCIICase(hasPopup, "menu")
2625         || equalLettersIgnoringASCIICase(hasPopup, "tree"))
2626         return hasPopup;
2627
2628     // In ARIA 1.1, the implicit value for combobox became "listbox."
2629     if (isComboBox() && hasPopup.isEmpty())
2630         return "listbox";
2631
2632     // The spec states that "User agents must treat any value of aria-haspopup that is not
2633     // included in the list of allowed values, including an empty string, as if the value
2634     // false had been provided."
2635     return "false";
2636 }
2637
2638 bool AccessibilityObject::supportsARIASetSize() const
2639 {
2640     return hasAttribute(aria_setsizeAttr);
2641 }
2642
2643 bool AccessibilityObject::supportsARIAPosInSet() const
2644 {
2645     return hasAttribute(aria_posinsetAttr);
2646 }
2647     
2648 int AccessibilityObject::ariaSetSize() const
2649 {
2650     return getAttribute(aria_setsizeAttr).toInt();
2651 }
2652
2653 int AccessibilityObject::ariaPosInSet() const
2654 {
2655     return getAttribute(aria_posinsetAttr).toInt();
2656 }
2657     
2658 const AtomicString& AccessibilityObject::identifierAttribute() const
2659 {
2660     return getAttribute(idAttr);
2661 }
2662     
2663 void AccessibilityObject::classList(Vector<String>& classList) const
2664 {
2665     Node* node = this->node();
2666     if (!is<Element>(node))
2667         return;
2668     
2669     Element* element = downcast<Element>(node);
2670     DOMTokenList& list = element->classList();
2671     unsigned length = list.length();
2672     for (unsigned k = 0; k < length; k++)
2673         classList.append(list.item(k).string());
2674 }
2675
2676 bool AccessibilityObject::supportsARIAPressed() const
2677 {
2678     const AtomicString& expanded = getAttribute(aria_pressedAttr);
2679     return equalLettersIgnoringASCIICase(expanded, "true") || equalLettersIgnoringASCIICase(expanded, "false");
2680 }
2681     
2682 bool AccessibilityObject::supportsExpanded() const
2683 {
2684     // Undefined values should not result in this attribute being exposed to ATs according to ARIA.
2685     const AtomicString& expanded = getAttribute(aria_expandedAttr);
2686     if (equalLettersIgnoringASCIICase(expanded, "true") || equalLettersIgnoringASCIICase(expanded, "false"))
2687         return true;
2688     switch (roleValue()) {
2689     case ComboBoxRole:
2690     case DisclosureTriangleRole:
2691     case DetailsRole:
2692         return true;
2693     default:
2694         return false;
2695     }
2696 }
2697     
2698 bool AccessibilityObject::isExpanded() const
2699 {
2700     if (equalLettersIgnoringASCIICase(getAttribute(aria_expandedAttr), "true"))
2701         return true;
2702     
2703     if (is<HTMLDetailsElement>(node()))
2704         return downcast<HTMLDetailsElement>(node())->isOpen();
2705     
2706     // Summary element should use its details parent's expanded status.
2707     if (isSummary()) {
2708         if (const AccessibilityObject* parent = AccessibilityObject::matchedParent(*this, false, [] (const AccessibilityObject& object) {
2709             return object.roleValue() == DetailsRole;
2710         }))
2711             return parent->isExpanded();
2712     }
2713     
2714     return false;  
2715 }
2716
2717 bool AccessibilityObject::supportsChecked() const
2718 {
2719     switch (roleValue()) {
2720     case CheckBoxRole:
2721     case MenuItemCheckboxRole:
2722     case MenuItemRadioRole:
2723     case RadioButtonRole:
2724     case SwitchRole:
2725         return true;
2726     default:
2727         return false;
2728     }
2729 }
2730
2731 AccessibilityButtonState AccessibilityObject::checkboxOrRadioValue() const
2732 {
2733     // If this is a real checkbox or radio button, AccessibilityRenderObject will handle.
2734     // If it's an ARIA checkbox, radio, or switch the aria-checked attribute should be used.
2735     // If it's a toggle button, the aria-pressed attribute is consulted.
2736
2737     if (isToggleButton()) {
2738         const AtomicString& ariaPressed = getAttribute(aria_pressedAttr);
2739         if (equalLettersIgnoringASCIICase(ariaPressed, "true"))
2740             return ButtonStateOn;
2741         if (equalLettersIgnoringASCIICase(ariaPressed, "mixed"))
2742             return ButtonStateMixed;
2743         return ButtonStateOff;
2744     }
2745     
2746     const AtomicString& result = getAttribute(aria_checkedAttr);
2747     if (equalLettersIgnoringASCIICase(result, "true"))
2748         return ButtonStateOn;
2749     if (equalLettersIgnoringASCIICase(result, "mixed")) {
2750         // ARIA says that radio, menuitemradio, and switch elements must NOT expose button state mixed.
2751         AccessibilityRole ariaRole = ariaRoleAttribute();
2752         if (ariaRole == RadioButtonRole || ariaRole == MenuItemRadioRole || ariaRole == SwitchRole)
2753             return ButtonStateOff;
2754         return ButtonStateMixed;
2755     }
2756     
2757     if (isIndeterminate())
2758         return ButtonStateMixed;
2759     
2760     return ButtonStateOff;
2761 }
2762
2763 // This is a 1-dimensional scroll offset helper function that's applied
2764 // separately in the horizontal and vertical directions, because the
2765 // logic is the same. The goal is to compute the best scroll offset
2766 // in order to make an object visible within a viewport.
2767 //
2768 // If the object is already fully visible, returns the same scroll
2769 // offset.
2770 //
2771 // In case the whole object cannot fit, you can specify a
2772 // subfocus - a smaller region within the object that should
2773 // be prioritized. If the whole object can fit, the subfocus is
2774 // ignored.
2775 //
2776 // If possible, the object and subfocus are centered within the
2777 // viewport.
2778 //
2779 // Example 1: the object is already visible, so nothing happens.
2780 //   +----------Viewport---------+
2781 //                 +---Object---+
2782 //                 +--SubFocus--+
2783 //
2784 // Example 2: the object is not fully visible, so it's centered
2785 // within the viewport.
2786 //   Before:
2787 //   +----------Viewport---------+
2788 //                         +---Object---+
2789 //                         +--SubFocus--+
2790 //
2791 //   After:
2792 //                 +----------Viewport---------+
2793 //                         +---Object---+
2794 //                         +--SubFocus--+
2795 //
2796 // Example 3: the object is larger than the viewport, so the
2797 // viewport moves to show as much of the object as possible,
2798 // while also trying to center the subfocus.
2799 //   Before:
2800 //   +----------Viewport---------+
2801 //     +---------------Object--------------+
2802 //                         +-SubFocus-+
2803 //
2804 //   After:
2805 //             +----------Viewport---------+
2806 //     +---------------Object--------------+
2807 //                         +-SubFocus-+
2808 //
2809 // When constraints cannot be fully satisfied, the min
2810 // (left/top) position takes precedence over the max (right/bottom).
2811 //
2812 // Note that the return value represents the ideal new scroll offset.
2813 // This may be out of range - the calling function should clip this
2814 // to the available range.
2815 static int computeBestScrollOffset(int currentScrollOffset, int subfocusMin, int subfocusMax, int objectMin, int objectMax, int viewportMin, int viewportMax)
2816 {
2817     int viewportSize = viewportMax - viewportMin;
2818     
2819     // If the object size is larger than the viewport size, consider
2820     // only a portion that's as large as the viewport, centering on
2821     // the subfocus as much as possible.
2822     if (objectMax - objectMin > viewportSize) {
2823         // Since it's impossible to fit the whole object in the
2824         // viewport, exit now if the subfocus is already within the viewport.
2825         if (subfocusMin - currentScrollOffset >= viewportMin && subfocusMax - currentScrollOffset <= viewportMax)
2826             return currentScrollOffset;
2827         
2828         // Subfocus must be within focus.
2829         subfocusMin = std::max(subfocusMin, objectMin);
2830         subfocusMax = std::min(subfocusMax, objectMax);
2831         
2832         // Subfocus must be no larger than the viewport size; favor top/left.
2833         if (subfocusMax - subfocusMin > viewportSize)
2834             subfocusMax = subfocusMin + viewportSize;
2835         
2836         // Compute the size of an object centered on the subfocus, the size of the viewport.
2837         int centeredObjectMin = (subfocusMin + subfocusMax - viewportSize) / 2;
2838         int centeredObjectMax = centeredObjectMin + viewportSize;
2839
2840         objectMin = std::max(objectMin, centeredObjectMin);
2841         objectMax = std::min(objectMax, centeredObjectMax);
2842     }
2843
2844     // Exit now if the focus is already within the viewport.
2845     if (objectMin - currentScrollOffset >= viewportMin
2846         && objectMax - currentScrollOffset <= viewportMax)
2847         return currentScrollOffset;
2848     
2849     // Center the object in the viewport.
2850     return (objectMin + objectMax - viewportMin - viewportMax) / 2;
2851 }
2852
2853 bool AccessibilityObject::isOnscreen() const
2854 {   
2855     bool isOnscreen = true;
2856
2857     // To figure out if the element is onscreen, we start by building of a stack starting with the
2858     // element, and then include every scrollable parent in the hierarchy.
2859     Vector<const AccessibilityObject*> objects;
2860     
2861     objects.append(this);
2862     for (AccessibilityObject* parentObject = this->parentObject(); parentObject; parentObject = parentObject->parentObject()) {
2863         if (parentObject->getScrollableAreaIfScrollable())
2864             objects.append(parentObject);
2865     }
2866
2867     // Now, go back through that chain and make sure each inner object is within the
2868     // visible bounds of the outer object.
2869     size_t levels = objects.size() - 1;
2870     
2871     for (size_t i = levels; i >= 1; i--) {
2872         const AccessibilityObject* outer = objects[i];
2873         const AccessibilityObject* inner = objects[i - 1];
2874         // FIXME: unclear if we need LegacyIOSDocumentVisibleRect.
2875         const IntRect outerRect = i < levels ? snappedIntRect(outer->boundingBoxRect()) : outer->getScrollableAreaIfScrollable()->visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
2876         const IntRect innerRect = snappedIntRect(inner->isAccessibilityScrollView() ? inner->parentObject()->boundingBoxRect() : inner->boundingBoxRect());
2877         
2878         if (!outerRect.intersects(innerRect)) {
2879             isOnscreen = false;
2880             break;
2881         }
2882     }
2883     
2884     return isOnscreen;
2885 }
2886
2887 void AccessibilityObject::scrollToMakeVisible() const
2888 {
2889     IntRect objectRect = snappedIntRect(boundingBoxRect());
2890     objectRect.setLocation(IntPoint());
2891     scrollToMakeVisibleWithSubFocus(objectRect);
2892 }
2893
2894 void AccessibilityObject::scrollToMakeVisibleWithSubFocus(const IntRect& subfocus) const
2895 {
2896     // Search up the parent chain until we find the first one that's scrollable.
2897     AccessibilityObject* scrollParent = parentObject();
2898     ScrollableArea* scrollableArea;
2899     for (scrollableArea = nullptr;
2900          scrollParent && !(scrollableArea = scrollParent->getScrollableAreaIfScrollable());
2901          scrollParent = scrollParent->parentObject()) { }
2902     if (!scrollableArea)
2903         return;
2904
2905     LayoutRect objectRect = boundingBoxRect();
2906     IntPoint scrollPosition = scrollableArea->scrollPosition();
2907     // FIXME: unclear if we need LegacyIOSDocumentVisibleRect.
2908     IntRect scrollVisibleRect = scrollableArea->visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
2909
2910     if (!scrollParent->isScrollView()) {
2911         objectRect.moveBy(scrollPosition);
2912         objectRect.moveBy(-snappedIntRect(scrollParent->elementRect()).location());
2913     }
2914     
2915     int desiredX = computeBestScrollOffset(
2916         scrollPosition.x(),
2917         objectRect.x() + subfocus.x(), objectRect.x() + subfocus.maxX(),
2918         objectRect.x(), objectRect.maxX(),
2919         0, scrollVisibleRect.width());
2920     int desiredY = computeBestScrollOffset(
2921         scrollPosition.y(),
2922         objectRect.y() + subfocus.y(), objectRect.y() + subfocus.maxY(),
2923         objectRect.y(), objectRect.maxY(),
2924         0, scrollVisibleRect.height());
2925
2926     scrollParent->scrollTo(IntPoint(desiredX, desiredY));
2927
2928     // Convert the subfocus into the coordinates of the scroll parent.
2929     IntRect newSubfocus = subfocus;
2930     IntRect newElementRect = snappedIntRect(elementRect());
2931     IntRect scrollParentRect = snappedIntRect(scrollParent->elementRect());
2932     newSubfocus.move(newElementRect.x(), newElementRect.y());
2933     newSubfocus.move(-scrollParentRect.x(), -scrollParentRect.y());
2934     
2935     // Recursively make sure the scroll parent itself is visible.
2936     if (scrollParent->parentObject())
2937         scrollParent->scrollToMakeVisibleWithSubFocus(newSubfocus);
2938 }
2939
2940 void AccessibilityObject::scrollToGlobalPoint(const IntPoint& globalPoint) const
2941 {
2942     // Search up the parent chain and create a vector of all scrollable parent objects
2943     // and ending with this object itself.
2944     Vector<const AccessibilityObject*> objects;
2945
2946     objects.append(this);
2947     for (AccessibilityObject* parentObject = this->parentObject(); parentObject; parentObject = parentObject->parentObject()) {
2948         if (parentObject->getScrollableAreaIfScrollable())
2949             objects.append(parentObject);
2950     }
2951
2952     objects.reverse();
2953
2954     // Start with the outermost scrollable (the main window) and try to scroll the
2955     // next innermost object to the given point.
2956     int offsetX = 0, offsetY = 0;
2957     IntPoint point = globalPoint;
2958     size_t levels = objects.size() - 1;
2959     for (size_t i = 0; i < levels; i++) {
2960         const AccessibilityObject* outer = objects[i];
2961         const AccessibilityObject* inner = objects[i + 1];
2962
2963         ScrollableArea* scrollableArea = outer->getScrollableAreaIfScrollable();
2964
2965         LayoutRect innerRect = inner->isAccessibilityScrollView() ? inner->parentObject()->boundingBoxRect() : inner->boundingBoxRect();
2966         LayoutRect objectRect = innerRect;
2967         IntPoint scrollPosition = scrollableArea->scrollPosition();
2968
2969         // Convert the object rect into local coordinates.
2970         objectRect.move(offsetX, offsetY);
2971         if (!outer->isAccessibilityScrollView())
2972             objectRect.move(scrollPosition.x(), scrollPosition.y());
2973
2974         int desiredX = computeBestScrollOffset(
2975             0,
2976             objectRect.x(), objectRect.maxX(),
2977             objectRect.x(), objectRect.maxX(),
2978             point.x(), point.x());
2979         int desiredY = computeBestScrollOffset(
2980             0,
2981             objectRect.y(), objectRect.maxY(),
2982             objectRect.y(), objectRect.maxY(),
2983             point.y(), point.y());
2984         outer->scrollTo(IntPoint(desiredX, desiredY));
2985
2986         if (outer->isAccessibilityScrollView() && !inner->isAccessibilityScrollView()) {
2987             // If outer object we just scrolled is a scroll view (main window or iframe) but the
2988             // inner object is not, keep track of the coordinate transformation to apply to
2989             // future nested calculations.
2990             scrollPosition = scrollableArea->scrollPosition();
2991             offsetX -= (scrollPosition.x() + point.x());
2992             offsetY -= (scrollPosition.y() + point.y());
2993             point.move(scrollPosition.x() - innerRect.x(),
2994                        scrollPosition.y() - innerRect.y());
2995         } else if (inner->isAccessibilityScrollView()) {
2996             // Otherwise, if the inner object is a scroll view, reset the coordinate transformation.
2997             offsetX = 0;
2998             offsetY = 0;
2999         }
3000     }
3001 }
3002     
3003 void AccessibilityObject::scrollAreaAndAncestor(std::pair<ScrollableArea*, AccessibilityObject*>& scrollers) const
3004 {
3005     // Search up the parent chain until we find the first one that's scrollable.
3006     scrollers.first = nullptr;
3007     for (scrollers.second = parentObject(); scrollers.second; scrollers.second = scrollers.second->parentObject()) {
3008         if ((scrollers.first = scrollers.second->getScrollableAreaIfScrollable()))
3009             break;
3010     }
3011 }
3012     
3013 ScrollableArea* AccessibilityObject::scrollableAreaAncestor() const
3014 {
3015     std::pair<ScrollableArea*, AccessibilityObject*> scrollers;
3016     scrollAreaAndAncestor(scrollers);
3017     return scrollers.first;
3018 }
3019     
3020 IntPoint AccessibilityObject::scrollPosition() const
3021 {
3022     if (auto scroller = scrollableAreaAncestor())
3023         return scroller->scrollPosition();
3024
3025     return IntPoint();
3026 }
3027
3028 IntRect AccessibilityObject::scrollVisibleContentRect() const
3029 {
3030     if (auto scroller = scrollableAreaAncestor())
3031         return scroller->visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
3032     
3033     return IntRect();
3034 }
3035     
3036 IntSize AccessibilityObject::scrollContentsSize() const
3037 {
3038     if (auto scroller = scrollableAreaAncestor())
3039         return scroller->contentsSize();
3040
3041     return IntSize();
3042 }
3043     
3044 bool AccessibilityObject::scrollByPage(ScrollByPageDirection direction) const
3045 {
3046     std::pair<ScrollableArea*, AccessibilityObject*> scrollers;
3047     scrollAreaAndAncestor(scrollers);
3048     ScrollableArea* scrollableArea = scrollers.first;
3049     AccessibilityObject* scrollParent = scrollers.second;
3050     
3051     if (!scrollableArea)
3052         return false;
3053     
3054     IntPoint scrollPosition = scrollableArea->scrollPosition();
3055     IntPoint newScrollPosition = scrollPosition;
3056     IntSize scrollSize = scrollableArea->contentsSize();
3057     IntRect scrollVisibleRect = scrollableArea->visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
3058     switch (direction) {
3059     case Right: {
3060         int scrollAmount = scrollVisibleRect.size().width();
3061         int newX = scrollPosition.x() - scrollAmount;
3062         newScrollPosition.setX(std::max(newX, 0));
3063         break;
3064     }
3065     case Left: {
3066         int scrollAmount = scrollVisibleRect.size().width();
3067         int newX = scrollAmount + scrollPosition.x();
3068         int maxX = scrollSize.width() - scrollAmount;
3069         newScrollPosition.setX(std::min(newX, maxX));
3070         break;
3071     }
3072     case Up: {
3073         int scrollAmount = scrollVisibleRect.size().height();
3074         int newY = scrollPosition.y() - scrollAmount;
3075         newScrollPosition.setY(std::max(newY, 0));
3076         break;
3077     }
3078     case Down: {
3079         int scrollAmount = scrollVisibleRect.size().height();
3080         int newY = scrollAmount + scrollPosition.y();
3081         int maxY = scrollSize.height() - scrollAmount;
3082         newScrollPosition.setY(std::min(newY, maxY));
3083         break;
3084     }
3085     default:
3086         break;
3087     }
3088     
3089     if (newScrollPosition != scrollPosition) {
3090         scrollParent->scrollTo(newScrollPosition);
3091         document()->updateLayoutIgnorePendingStylesheets();
3092         return true;
3093     }
3094     
3095     return false;
3096 }
3097
3098
3099 bool AccessibilityObject::lastKnownIsIgnoredValue()
3100 {
3101     if (m_lastKnownIsIgnoredValue == DefaultBehavior)
3102         m_lastKnownIsIgnoredValue = accessibilityIsIgnored() ? IgnoreObject : IncludeObject;
3103
3104     return m_lastKnownIsIgnoredValue == IgnoreObject;
3105 }
3106
3107 void AccessibilityObject::setLastKnownIsIgnoredValue(bool isIgnored)
3108 {
3109     m_lastKnownIsIgnoredValue = isIgnored ? IgnoreObject : IncludeObject;
3110 }
3111
3112 void AccessibilityObject::notifyIfIgnoredValueChanged()
3113 {
3114     bool isIgnored = accessibilityIsIgnored();
3115     if (lastKnownIsIgnoredValue() != isIgnored) {
3116         if (AXObjectCache* cache = axObjectCache())
3117             cache->childrenChanged(parentObject());
3118         setLastKnownIsIgnoredValue(isIgnored);
3119     }
3120 }
3121
3122 bool AccessibilityObject::ariaPressedIsPresent() const
3123 {
3124     return !getAttribute(aria_pressedAttr).isEmpty();
3125 }
3126
3127 TextIteratorBehavior AccessibilityObject::textIteratorBehaviorForTextRange() const
3128 {
3129     TextIteratorBehavior behavior = TextIteratorIgnoresStyleVisibility;
3130     
3131 #if PLATFORM(GTK)
3132     // We need to emit replaced elements for GTK, and present
3133     // them with the 'object replacement character' (0xFFFC).
3134     behavior = static_cast<TextIteratorBehavior>(behavior | TextIteratorEmitsObjectReplacementCharacters);
3135 #endif
3136     
3137     return behavior;
3138 }
3139     
3140 AccessibilityRole AccessibilityObject::buttonRoleType() const
3141 {
3142     // If aria-pressed is present, then it should be exposed as a toggle button.
3143     // http://www.w3.org/TR/wai-aria/states_and_properties#aria-pressed
3144     if (ariaPressedIsPresent())
3145         return ToggleButtonRole;
3146     if (ariaHasPopup())
3147         return PopUpButtonRole;
3148     // We don't contemplate RadioButtonRole, as it depends on the input
3149     // type.
3150
3151     return ButtonRole;
3152 }
3153
3154 bool AccessibilityObject::isButton() const
3155 {
3156     AccessibilityRole role = roleValue();
3157
3158     return role == ButtonRole || role == PopUpButtonRole || role == ToggleButtonRole;
3159 }
3160
3161 bool AccessibilityObject::accessibilityIsIgnoredByDefault() const
3162 {
3163     return defaultObjectInclusion() == IgnoreObject;
3164 }
3165
3166 // ARIA component of hidden definition.
3167 // http://www.w3.org/TR/wai-aria/terms#def_hidden
3168 bool AccessibilityObject::isARIAHidden() const
3169 {
3170     return AccessibilityObject::matchedParent(*this, true, [] (const AccessibilityObject& object) {
3171         return equalLettersIgnoringASCIICase(object.getAttribute(aria_hiddenAttr), "true");
3172     }) != nullptr;
3173 }
3174
3175 // DOM component of hidden definition.
3176 // http://www.w3.org/TR/wai-aria/terms#def_hidden
3177 bool AccessibilityObject::isDOMHidden() const
3178 {
3179     RenderObject* renderer = this->renderer();
3180     if (!renderer)
3181         return true;
3182     
3183     const RenderStyle& style = renderer->style();
3184     return style.display() == NONE || style.visibility() != VISIBLE;
3185 }
3186
3187 bool AccessibilityObject::isShowingValidationMessage() const
3188 {
3189     if (is<HTMLFormControlElement>(node()))
3190         return downcast<HTMLFormControlElement>(*node()).isShowingValidationMessage();
3191     return false;
3192 }
3193
3194 String AccessibilityObject::validationMessage() const
3195 {
3196     if (is<HTMLFormControlElement>(node()))
3197         return downcast<HTMLFormControlElement>(*node()).validationMessage();
3198     return String();
3199 }
3200
3201 AccessibilityObjectInclusion AccessibilityObject::defaultObjectInclusion() const
3202 {
3203     bool useParentData = !m_isIgnoredFromParentData.isNull();
3204     
3205     if (useParentData ? m_isIgnoredFromParentData.isARIAHidden : isARIAHidden())
3206         return IgnoreObject;
3207     
3208     if (ignoredFromARIAModalPresence())
3209         return IgnoreObject;
3210     
3211     if (useParentData ? m_isIgnoredFromParentData.isPresentationalChildOfAriaRole : isPresentationalChildOfAriaRole())
3212         return IgnoreObject;
3213     
3214     return accessibilityPlatformIncludesObject();
3215 }
3216     
3217 bool AccessibilityObject::accessibilityIsIgnored() const
3218 {
3219     AXComputedObjectAttributeCache* attributeCache = nullptr;
3220     AXObjectCache* cache = axObjectCache();
3221     if (cache)
3222         attributeCache = cache->computedObjectAttributeCache();
3223     
3224     if (attributeCache) {
3225         AccessibilityObjectInclusion ignored = attributeCache->getIgnored(axObjectID());
3226         switch (ignored) {
3227         case IgnoreObject:
3228             return true;
3229         case IncludeObject:
3230             return false;
3231         case DefaultBehavior:
3232             break;
3233         }
3234     }
3235
3236     bool result = computeAccessibilityIsIgnored();
3237
3238     // In case computing axIsIgnored disables attribute caching, we should refetch the object to see if it exists.
3239     if (cache && (attributeCache = cache->computedObjectAttributeCache()))
3240         attributeCache->setIgnored(axObjectID(), result ? IgnoreObject : IncludeObject);
3241
3242     return result;
3243 }
3244
3245 void AccessibilityObject::elementsFromAttribute(Vector<Element*>& elements, const QualifiedName& attribute) const
3246 {
3247     Node* node = this->node();
3248     if (!node || !node->isElementNode())
3249         return;
3250
3251     TreeScope& treeScope = node->treeScope();
3252
3253     const AtomicString& idList = getAttribute(attribute);
3254     if (idList.isEmpty())
3255         return;
3256
3257     auto spaceSplitString = SpaceSplitString(idList, false);
3258     size_t length = spaceSplitString.size();
3259     for (size_t i = 0; i < length; ++i) {
3260         if (auto* idElement = treeScope.getElementById(spaceSplitString[i]))
3261             elements.append(idElement);
3262     }
3263 }
3264
3265 #if PLATFORM(COCOA)
3266 bool AccessibilityObject::preventKeyboardDOMEventDispatch() const
3267 {
3268     Frame* frame = this->frame();
3269     return frame && frame->settings().preventKeyboardDOMEventDispatch();
3270 }
3271
3272 void AccessibilityObject::setPreventKeyboardDOMEventDispatch(bool on)
3273 {
3274     Frame* frame = this->frame();
3275     if (!frame)
3276         return;
3277     frame->settings().setPreventKeyboardDOMEventDispatch(on);
3278 }
3279 #endif
3280
3281 AccessibilityObject* AccessibilityObject::focusableAncestor()
3282 {
3283     return const_cast<AccessibilityObject*>(AccessibilityObject::matchedParent(*this, true, [] (const AccessibilityObject& object) {
3284         return object.canSetFocusAttribute();
3285     }));
3286 }
3287
3288 AccessibilityObject* AccessibilityObject::editableAncestor()
3289 {
3290     return const_cast<AccessibilityObject*>(AccessibilityObject::matchedParent(*this, true, [] (const AccessibilityObject& object) {
3291         return object.isTextControl();
3292     }));
3293 }
3294
3295 AccessibilityObject* AccessibilityObject::highestEditableAncestor()
3296 {
3297     AccessibilityObject* editableAncestor = this->editableAncestor();
3298     AccessibilityObject* previousEditableAncestor = nullptr;
3299     while (editableAncestor) {
3300         if (editableAncestor == previousEditableAncestor) {
3301             if (AccessibilityObject* parent = editableAncestor->parentObject()) {
3302                 editableAncestor = parent->editableAncestor();
3303                 continue;
3304             }
3305             break;
3306         }
3307         previousEditableAncestor = editableAncestor;
3308         editableAncestor = editableAncestor->editableAncestor();
3309     }
3310     return previousEditableAncestor;
3311 }
3312
3313 bool AccessibilityObject::isStyleFormatGroup() const
3314 {
3315     Node* node = this->node();
3316     if (!node)
3317         return false;
3318     
3319     return node->hasTagName(kbdTag) || node->hasTagName(codeTag)
3320     || node->hasTagName(preTag) || node->hasTagName(sampTag)
3321     || node->hasTagName(varTag) || node->hasTagName(citeTag)
3322     || node->hasTagName(insTag) || node->hasTagName(delTag)
3323     || node->hasTagName(supTag) || node->hasTagName(subTag);
3324 }
3325
3326 bool AccessibilityObject::isSubscriptStyleGroup() const
3327 {
3328     Node* node = this->node();
3329     return node && node->hasTagName(subTag);
3330 }
3331
3332 bool AccessibilityObject::isSuperscriptStyleGroup() const
3333 {
3334     Node* node = this->node();
3335     return node && node->hasTagName(supTag);
3336 }
3337
3338 bool AccessibilityObject::isFigureElement() const
3339 {
3340     Node* node = this->node();
3341     return node && node->hasTagName(figureTag);
3342 }
3343
3344 bool AccessibilityObject::isOutput() const
3345 {
3346     Node* node = this->node();
3347     return node && node->hasTagName(outputTag);
3348 }
3349     
3350 bool AccessibilityObject::isContainedByPasswordField() const
3351 {
3352     Node* node = this->node();
3353     if (!node)
3354         return false;
3355     
3356     if (ariaRoleAttribute() != UnknownRole)
3357         return false;
3358
3359     Element* element = node->shadowHost();
3360     return is<HTMLInputElement>(element) && downcast<HTMLInputElement>(*element).isPasswordField();
3361 }
3362
3363 void AccessibilityObject::ariaElementsFromAttribute(AccessibilityChildrenVector& children, const QualifiedName& attributeName) const
3364 {
3365     Vector<Element*> elements;
3366     elementsFromAttribute(elements, attributeName);
3367     AXObjectCache* cache = axObjectCache();
3368     for (const auto& element : elements) {
3369         if (AccessibilityObject* axObject = cache->getOrCreate(element))
3370             children.append(axObject);
3371     }
3372 }
3373
3374 void AccessibilityObject::ariaElementsReferencedByAttribute(AccessibilityChildrenVector& elements, const QualifiedName& attribute) const
3375 {
3376     auto id = identifierAttribute();
3377     if (id.isEmpty())
3378         return;
3379
3380     AXObjectCache* cache = axObjectCache();
3381     if (!cache)
3382         return;
3383
3384     for (auto& element : descendantsOfType<Element>(node()->treeScope().rootNode())) {
3385         const AtomicString& idList = element.attributeWithoutSynchronization(attribute);
3386         if (!SpaceSplitString(idList, false).contains(id))
3387             continue;
3388
3389         if (AccessibilityObject* axObject = cache->getOrCreate(&element))
3390             elements.append(axObject);
3391     }
3392 }
3393
3394 void AccessibilityObject::ariaControlsElements(AccessibilityChildrenVector& ariaControls) const
3395 {
3396     ariaElementsFromAttribute(ariaControls, aria_controlsAttr);
3397 }
3398
3399 void AccessibilityObject::ariaControlsReferencingElements(AccessibilityChildrenVector& controllers) const
3400 {
3401     ariaElementsReferencedByAttribute(controllers, aria_controlsAttr);
3402 }
3403
3404 void AccessibilityObject::ariaDescribedByElements(AccessibilityChildrenVector& ariaDescribedBy) const
3405 {
3406     ariaElementsFromAttribute(ariaDescribedBy, aria_describedbyAttr);
3407 }
3408
3409 void AccessibilityObject::ariaDescribedByReferencingElements(AccessibilityChildrenVector& describers) const
3410 {
3411     ariaElementsReferencedByAttribute(describers, aria_describedbyAttr);
3412 }
3413
3414 void AccessibilityObject::ariaDetailsElements(AccessibilityChildrenVector& ariaDetails) const
3415 {
3416     ariaElementsFromAttribute(ariaDetails, aria_detailsAttr);
3417 }
3418
3419 void AccessibilityObject::ariaDetailsReferencingElements(AccessibilityChildrenVector& detailsFor) const
3420 {
3421     ariaElementsReferencedByAttribute(detailsFor, aria_detailsAttr);
3422 }
3423
3424 void AccessibilityObject::ariaErrorMessageElements(AccessibilityChildrenVector& ariaErrorMessage) const
3425 {
3426     ariaElementsFromAttribute(ariaErrorMessage, aria_errormessageAttr);
3427 }
3428
3429 void AccessibilityObject::ariaErrorMessageReferencingElements(AccessibilityChildrenVector& errorMessageFor) const
3430 {
3431     ariaElementsReferencedByAttribute(errorMessageFor, aria_errormessageAttr);
3432 }
3433
3434 void AccessibilityObject::ariaFlowToElements(AccessibilityChildrenVector& flowTo) const
3435 {
3436     ariaElementsFromAttribute(flowTo, aria_flowtoAttr);
3437 }
3438
3439 void AccessibilityObject::ariaFlowToReferencingElements(AccessibilityChildrenVector& flowFrom) const
3440 {
3441     ariaElementsReferencedByAttribute(flowFrom, aria_flowtoAttr);
3442 }
3443
3444 void AccessibilityObject::ariaLabelledByElements(AccessibilityChildrenVector& ariaLabelledBy) const
3445 {
3446     ariaElementsFromAttribute(ariaLabelledBy, aria_labelledbyAttr);
3447     if (!ariaLabelledBy.size())
3448         ariaElementsFromAttribute(ariaLabelledBy, aria_labeledbyAttr);
3449 }
3450
3451 void AccessibilityObject::ariaLabelledByReferencingElements(AccessibilityChildrenVector& labels) const
3452 {
3453     ariaElementsReferencedByAttribute(labels, aria_labelledbyAttr);
3454     if (!labels.size())
3455         ariaElementsReferencedByAttribute(labels, aria_labeledbyAttr);
3456 }
3457
3458 void AccessibilityObject::ariaOwnsElements(AccessibilityChildrenVector& axObjects) const
3459 {
3460     ariaElementsFromAttribute(axObjects, aria_ownsAttr);
3461 }
3462
3463 void AccessibilityObject::ariaOwnsReferencingElements(AccessibilityChildrenVector& owners) const
3464 {
3465     ariaElementsReferencedByAttribute(owners, aria_ownsAttr);
3466 }
3467
3468 void AccessibilityObject::setIsIgnoredFromParentDataForChild(AccessibilityObject* child)
3469 {
3470     if (!child)
3471         return;
3472     
3473     if (child->parentObject() != this) {
3474         child->clearIsIgnoredFromParentData();
3475         return;
3476     }
3477     
3478     AccessibilityIsIgnoredFromParentData result = AccessibilityIsIgnoredFromParentData(this);
3479     if (!m_isIgnoredFromParentData.isNull()) {
3480         result.isARIAHidden = m_isIgnoredFromParentData.isARIAHidden || equalLettersIgnoringASCIICase(child->getAttribute(aria_hiddenAttr), "true");
3481         result.isPresentationalChildOfAriaRole = m_isIgnoredFromParentData.isPresentationalChildOfAriaRole || ariaRoleHasPresentationalChildren();
3482         result.isDescendantOfBarrenParent = m_isIgnoredFromParentData.isDescendantOfBarrenParent || !canHaveChildren();
3483     } else {
3484         result.isARIAHidden = child->isARIAHidden();
3485         result.isPresentationalChildOfAriaRole = child->isPresentationalChildOfAriaRole();
3486         result.isDescendantOfBarrenParent = child->isDescendantOfBarrenParent();
3487     }
3488     
3489     child->setIsIgnoredFromParentData(result);
3490 }
3491
3492 } // namespace WebCore