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