Move most of TextIterator off of live ranges
[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);
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     if (!range)
1300         return String();
1301
1302     for (TextIterator it(*range); !it.atEnd(); it.advance()) {
1303         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
1304         if (it.text().length()) {
1305             // Add a textual representation for list marker text.
1306             builder.append(listMarkerTextForNodeAndPosition(it.node(), visiblePositionRange.start));
1307             it.appendTextToStringBuilder(builder);
1308         } else {
1309             // locate the node and starting offset for this replaced range
1310             if (replacedNodeNeedsCharacter(it.node()))
1311                 builder.append(objectReplacementCharacter);
1312         }
1313     }
1314
1315     return builder.toString();
1316 }
1317
1318 int AccessibilityObject::lengthForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const
1319 {
1320     // FIXME: Multi-byte support
1321     if (visiblePositionRange.isNull())
1322         return -1;
1323
1324     RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end);
1325     if (!range)
1326         return -1;
1327
1328     int length = 0;
1329     for (TextIterator it(*range); !it.atEnd(); it.advance()) {
1330         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
1331         if (it.text().length())
1332             length += it.text().length();
1333         else {
1334             if (replacedNodeNeedsCharacter(it.node()))
1335                 ++length;
1336         }
1337     }
1338     return length;
1339 }
1340
1341 VisiblePosition AccessibilityObject::visiblePositionForBounds(const IntRect& rect, AccessibilityVisiblePositionForBounds visiblePositionForBounds) const
1342 {
1343     if (rect.isEmpty())
1344         return VisiblePosition();
1345     
1346     auto* mainFrame = this->mainFrame();
1347     if (!mainFrame)
1348         return VisiblePosition();
1349     
1350     // FIXME: Add support for right-to-left languages.
1351     IntPoint corner = (visiblePositionForBounds == AccessibilityVisiblePositionForBounds::First) ? rect.minXMinYCorner() : rect.maxXMaxYCorner();
1352     VisiblePosition position = mainFrame->visiblePositionForPoint(corner);
1353     
1354     if (rect.contains(position.absoluteCaretBounds().center()))
1355         return position;
1356     
1357     // If the initial position is located outside the bounds adjust it incrementally as needed.
1358     VisiblePosition nextPosition = position.next();
1359     VisiblePosition previousPosition = position.previous();
1360     while (nextPosition.isNotNull() || previousPosition.isNotNull()) {
1361         if (rect.contains(nextPosition.absoluteCaretBounds().center()))
1362             return nextPosition;
1363         if (rect.contains(previousPosition.absoluteCaretBounds().center()))
1364             return previousPosition;
1365         
1366         nextPosition = nextPosition.next();
1367         previousPosition = previousPosition.previous();
1368     }
1369     
1370     return VisiblePosition();
1371 }
1372
1373 VisiblePosition AccessibilityObject::nextWordEnd(const VisiblePosition& visiblePos) const
1374 {
1375     if (visiblePos.isNull())
1376         return VisiblePosition();
1377
1378     // make sure we move off of a word end
1379     VisiblePosition nextVisiblePos = visiblePos.next();
1380     if (nextVisiblePos.isNull())
1381         return VisiblePosition();
1382
1383     return endOfWord(nextVisiblePos, LeftWordIfOnBoundary);
1384 }
1385
1386 VisiblePosition AccessibilityObject::previousWordStart(const VisiblePosition& visiblePos) const
1387 {
1388     if (visiblePos.isNull())
1389         return VisiblePosition();
1390
1391     // make sure we move off of a word start
1392     VisiblePosition prevVisiblePos = visiblePos.previous();
1393     if (prevVisiblePos.isNull())
1394         return VisiblePosition();
1395
1396     return startOfWord(prevVisiblePos, RightWordIfOnBoundary);
1397 }
1398
1399 VisiblePosition AccessibilityObject::nextLineEndPosition(const VisiblePosition& visiblePos) const
1400 {
1401     if (visiblePos.isNull())
1402         return VisiblePosition();
1403
1404     // to make sure we move off of a line end
1405     VisiblePosition nextVisiblePos = visiblePos.next();
1406     if (nextVisiblePos.isNull())
1407         return VisiblePosition();
1408
1409     VisiblePosition endPosition = endOfLine(nextVisiblePos);
1410
1411     // as long as the position hasn't reached the end of the doc,  keep searching for a valid line end position
1412     // 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.
1413     while (endPosition.isNull() && nextVisiblePos.isNotNull()) {
1414         nextVisiblePos = nextVisiblePos.next();
1415         endPosition = endOfLine(nextVisiblePos);
1416     }
1417
1418     return endPosition;
1419 }
1420
1421 VisiblePosition AccessibilityObject::previousLineStartPosition(const VisiblePosition& visiblePos) const
1422 {
1423     if (visiblePos.isNull())
1424         return VisiblePosition();
1425
1426     // make sure we move off of a line start
1427     VisiblePosition prevVisiblePos = visiblePos.previous();
1428     if (prevVisiblePos.isNull())
1429         return VisiblePosition();
1430
1431     VisiblePosition startPosition = startOfLine(prevVisiblePos);
1432
1433     // as long as the position hasn't reached the beginning of the doc,  keep searching for a valid line start position
1434     // 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.
1435     if (startPosition.isNull()) {
1436         while (startPosition.isNull() && prevVisiblePos.isNotNull()) {
1437             prevVisiblePos = prevVisiblePos.previous();
1438             startPosition = startOfLine(prevVisiblePos);
1439         }
1440     } else
1441         startPosition = updateAXLineStartForVisiblePosition(startPosition);
1442
1443     return startPosition;
1444 }
1445
1446 VisiblePosition AccessibilityObject::nextSentenceEndPosition(const VisiblePosition& visiblePos) const
1447 {
1448     // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
1449     // Related? <rdar://problem/3927736> Text selection broken in 8A336
1450     if (visiblePos.isNull())
1451         return VisiblePosition();
1452
1453     // make sure we move off of a sentence end
1454     VisiblePosition nextVisiblePos = visiblePos.next();
1455     if (nextVisiblePos.isNull())
1456         return VisiblePosition();
1457
1458     // an empty line is considered a sentence. If it's skipped, then the sentence parser will not
1459     // see this empty line.  Instead, return the end position of the empty line.
1460     VisiblePosition endPosition;
1461     
1462     String lineString = plainText(makeRange(startOfLine(nextVisiblePos), endOfLine(nextVisiblePos)).get());
1463     if (lineString.isEmpty())
1464         endPosition = nextVisiblePos;
1465     else
1466         endPosition = endOfSentence(nextVisiblePos);
1467
1468     return endPosition;
1469 }
1470
1471 VisiblePosition AccessibilityObject::previousSentenceStartPosition(const VisiblePosition& visiblePos) const
1472 {
1473     // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
1474     // Related? <rdar://problem/3927736> Text selection broken in 8A336
1475     if (visiblePos.isNull())
1476         return VisiblePosition();
1477
1478     // make sure we move off of a sentence start
1479     VisiblePosition previousVisiblePos = visiblePos.previous();
1480     if (previousVisiblePos.isNull())
1481         return VisiblePosition();
1482
1483     // treat empty line as a separate sentence.
1484     VisiblePosition startPosition;
1485     
1486     String lineString = plainText(makeRange(startOfLine(previousVisiblePos), endOfLine(previousVisiblePos)).get());
1487     if (lineString.isEmpty())
1488         startPosition = previousVisiblePos;
1489     else
1490         startPosition = startOfSentence(previousVisiblePos);
1491
1492     return startPosition;
1493 }
1494
1495 VisiblePosition AccessibilityObject::nextParagraphEndPosition(const VisiblePosition& visiblePos) const
1496 {
1497     if (visiblePos.isNull())
1498         return VisiblePosition();
1499
1500     // make sure we move off of a paragraph end
1501     VisiblePosition nextPos = visiblePos.next();
1502     if (nextPos.isNull())
1503         return VisiblePosition();
1504
1505     return endOfParagraph(nextPos);
1506 }
1507
1508 VisiblePosition AccessibilityObject::previousParagraphStartPosition(const VisiblePosition& visiblePos) const
1509 {
1510     if (visiblePos.isNull())
1511         return VisiblePosition();
1512
1513     // make sure we move off of a paragraph start
1514     VisiblePosition previousPos = visiblePos.previous();
1515     if (previousPos.isNull())
1516         return VisiblePosition();
1517
1518     return startOfParagraph(previousPos);
1519 }
1520
1521 AccessibilityObject* AccessibilityObject::accessibilityObjectForPosition(const VisiblePosition& visiblePos) const
1522 {
1523     if (visiblePos.isNull())
1524         return nullptr;
1525
1526     RenderObject* obj = visiblePos.deepEquivalent().deprecatedNode()->renderer();
1527     if (!obj)
1528         return nullptr;
1529
1530     return obj->document().axObjectCache()->getOrCreate(obj);
1531 }
1532     
1533 // If you call node->hasEditableStyle() since that will return true if an ancestor is editable.
1534 // This only returns true if this is the element that actually has the contentEditable attribute set.
1535 bool AccessibilityObject::hasContentEditableAttributeSet() const
1536 {
1537     return contentEditableAttributeIsEnabled(element());
1538 }
1539
1540 bool AccessibilityObject::supportsReadOnly() const
1541 {
1542     AccessibilityRole role = roleValue();
1543
1544     return role == AccessibilityRole::CheckBox
1545         || role == AccessibilityRole::ColumnHeader
1546         || role == AccessibilityRole::ComboBox
1547         || role == AccessibilityRole::Grid
1548         || role == AccessibilityRole::GridCell
1549         || role == AccessibilityRole::ListBox
1550         || role == AccessibilityRole::MenuItemCheckbox
1551         || role == AccessibilityRole::MenuItemRadio
1552         || role == AccessibilityRole::RadioGroup
1553         || role == AccessibilityRole::RowHeader
1554         || role == AccessibilityRole::SearchField
1555         || role == AccessibilityRole::Slider
1556         || role == AccessibilityRole::SpinButton
1557         || role == AccessibilityRole::Switch
1558         || role == AccessibilityRole::TextField
1559         || role == AccessibilityRole::TreeGrid
1560         || isPasswordField();
1561 }
1562
1563 String AccessibilityObject::readOnlyValue() const
1564 {
1565     if (!hasAttribute(aria_readonlyAttr))
1566         return ariaRoleAttribute() != AccessibilityRole::Unknown && supportsReadOnly() ? "false" : String();
1567
1568     return getAttribute(aria_readonlyAttr).string().convertToASCIILowercase();
1569 }
1570
1571 bool AccessibilityObject::supportsAutoComplete() const
1572 {
1573     return (isComboBox() || isARIATextControl()) && hasAttribute(aria_autocompleteAttr);
1574 }
1575
1576 String AccessibilityObject::autoCompleteValue() const
1577 {
1578     const AtomString& autoComplete = getAttribute(aria_autocompleteAttr);
1579     if (equalLettersIgnoringASCIICase(autoComplete, "inline")
1580         || equalLettersIgnoringASCIICase(autoComplete, "list")
1581         || equalLettersIgnoringASCIICase(autoComplete, "both"))
1582         return autoComplete;
1583
1584     return "none";
1585 }
1586
1587 bool AccessibilityObject::contentEditableAttributeIsEnabled(Element* element)
1588 {
1589     if (!element)
1590         return false;
1591     
1592     const AtomString& contentEditableValue = element->attributeWithoutSynchronization(contenteditableAttr);
1593     if (contentEditableValue.isNull())
1594         return false;
1595     
1596     // Both "true" (case-insensitive) and the empty string count as true.
1597     return contentEditableValue.isEmpty() || equalLettersIgnoringASCIICase(contentEditableValue, "true");
1598 }
1599     
1600 #if ENABLE(ACCESSIBILITY)
1601 int AccessibilityObject::lineForPosition(const VisiblePosition& visiblePos) const
1602 {
1603     if (visiblePos.isNull() || !node())
1604         return -1;
1605
1606     // If the position is not in the same editable region as this AX object, return -1.
1607     Node* containerNode = visiblePos.deepEquivalent().containerNode();
1608     if (!containerNode->containsIncludingShadowDOM(node()) && !node()->containsIncludingShadowDOM(containerNode))
1609         return -1;
1610
1611     int lineCount = -1;
1612     VisiblePosition currentVisiblePos = visiblePos;
1613     VisiblePosition savedVisiblePos;
1614
1615     // move up until we get to the top
1616     // FIXME: This only takes us to the top of the rootEditableElement, not the top of the
1617     // top document.
1618     do {
1619         savedVisiblePos = currentVisiblePos;
1620         VisiblePosition prevVisiblePos = previousLinePosition(currentVisiblePos, 0, HasEditableAXRole);
1621         currentVisiblePos = prevVisiblePos;
1622         ++lineCount;
1623     }  while (currentVisiblePos.isNotNull() && !(inSameLine(currentVisiblePos, savedVisiblePos)));
1624
1625     return lineCount;
1626 }
1627 #endif
1628
1629 // NOTE: Consider providing this utility method as AX API
1630 PlainTextRange AccessibilityObject::plainTextRangeForVisiblePositionRange(const VisiblePositionRange& positionRange) const
1631 {
1632     int index1 = index(positionRange.start);
1633     int index2 = index(positionRange.end);
1634     if (index1 < 0 || index2 < 0 || index1 > index2)
1635         return PlainTextRange();
1636
1637     return PlainTextRange(index1, index2 - index1);
1638 }
1639
1640 // The composed character range in the text associated with this accessibility object that
1641 // is specified by the given screen coordinates. This parameterized attribute returns the
1642 // complete range of characters (including surrogate pairs of multi-byte glyphs) at the given
1643 // screen coordinates.
1644 // NOTE: This varies from AppKit when the point is below the last line. AppKit returns an
1645 // an error in that case. We return textControl->text().length(), 1. Does this matter?
1646 PlainTextRange AccessibilityObject::doAXRangeForPosition(const IntPoint& point) const
1647 {
1648     int i = index(visiblePositionForPoint(point));
1649     if (i < 0)
1650         return PlainTextRange();
1651
1652     return PlainTextRange(i, 1);
1653 }
1654
1655 // Given a character index, the range of text associated with this accessibility object
1656 // over which the style in effect at that character index applies.
1657 PlainTextRange AccessibilityObject::doAXStyleRangeForIndex(unsigned index) const
1658 {
1659     VisiblePositionRange range = styleRangeForPosition(visiblePositionForIndex(index, false));
1660     return plainTextRangeForVisiblePositionRange(range);
1661 }
1662
1663 // Given an indexed character, the line number of the text associated with this accessibility
1664 // object that contains the character.
1665 unsigned AccessibilityObject::doAXLineForIndex(unsigned index)
1666 {
1667     return lineForPosition(visiblePositionForIndex(index, false));
1668 }
1669
1670 #if ENABLE(ACCESSIBILITY)
1671 void AccessibilityObject::updateBackingStore()
1672 {
1673     if (!axObjectCache())
1674         return;
1675     
1676     // Updating the layout may delete this object.
1677     RefPtr<AccessibilityObject> protectedThis(this);
1678     if (auto* document = this->document()) {
1679         if (!document->view()->layoutContext().isInRenderTreeLayout() && !document->inRenderTreeUpdate() && !document->inStyleRecalc())
1680             document->updateLayoutIgnorePendingStylesheets();
1681     }
1682
1683     if (auto cache = axObjectCache())
1684         cache->performDeferredCacheUpdate();
1685     
1686     updateChildrenIfNecessary();
1687 }
1688 #endif
1689
1690 const AccessibilityScrollView* AccessibilityObject::ancestorAccessibilityScrollView(bool includeSelf) const
1691 {
1692     return downcast<AccessibilityScrollView>(Accessibility::findAncestor<AccessibilityObject>(*this, includeSelf, [] (const auto& object) {
1693         return is<AccessibilityScrollView>(object);
1694     }));
1695 }
1696
1697 ScrollView* AccessibilityObject::scrollViewAncestor() const
1698 {
1699     if (auto parentScrollView = ancestorAccessibilityScrollView(true/* includeSelf */))
1700         return parentScrollView->scrollView();
1701     
1702     return nullptr;
1703 }
1704     
1705 Document* AccessibilityObject::document() const
1706 {
1707     FrameView* frameView = documentFrameView();
1708     if (!frameView)
1709         return nullptr;
1710     
1711     return frameView->frame().document();
1712 }
1713     
1714 Page* AccessibilityObject::page() const
1715 {
1716     Document* document = this->document();
1717     if (!document)
1718         return nullptr;
1719     return document->page();
1720 }
1721
1722 FrameView* AccessibilityObject::documentFrameView() const 
1723
1724     const AccessibilityObject* object = this;
1725     while (object && !object->isAccessibilityRenderObject()) 
1726         object = object->parentObject();
1727         
1728     if (!object)
1729         return nullptr;
1730
1731     return object->documentFrameView();
1732 }
1733
1734 #if ENABLE(ACCESSIBILITY)
1735 const AccessibilityObject::AccessibilityChildrenVector& AccessibilityObject::children(bool updateChildrenIfNeeded)
1736 {
1737     if (updateChildrenIfNeeded)
1738         updateChildrenIfNecessary();
1739
1740     return m_children;
1741 }
1742 #endif
1743
1744 void AccessibilityObject::updateChildrenIfNecessary()
1745 {
1746     if (!hasChildren()) {
1747         // Enable the cache in case we end up adding a lot of children, we don't want to recompute axIsIgnored each time.
1748         AXAttributeCacheEnabler enableCache(axObjectCache());
1749         addChildren();
1750     }
1751 }
1752     
1753 void AccessibilityObject::clearChildren()
1754 {
1755     // Some objects have weak pointers to their parents and those associations need to be detached.
1756     for (const auto& child : m_children)
1757         child->detachFromParent();
1758     
1759     m_children.clear();
1760     m_haveChildren = false;
1761 }
1762
1763 AccessibilityObject* AccessibilityObject::anchorElementForNode(Node* node)
1764 {
1765     RenderObject* obj = node->renderer();
1766     if (!obj)
1767         return nullptr;
1768     
1769     RefPtr<AccessibilityObject> axObj = obj->document().axObjectCache()->getOrCreate(obj);
1770     Element* anchor = axObj->anchorElement();
1771     if (!anchor)
1772         return nullptr;
1773     
1774     RenderObject* anchorRenderer = anchor->renderer();
1775     if (!anchorRenderer)
1776         return nullptr;
1777     
1778     return anchorRenderer->document().axObjectCache()->getOrCreate(anchorRenderer);
1779 }
1780
1781 AccessibilityObject* AccessibilityObject::headingElementForNode(Node* node)
1782 {
1783     if (!node)
1784         return nullptr;
1785
1786     RenderObject* renderObject = node->renderer();
1787     if (!renderObject)
1788         return nullptr;
1789
1790     AccessibilityObject* axObject = renderObject->document().axObjectCache()->getOrCreate(renderObject);
1791
1792     return Accessibility::findAncestor<AccessibilityObject>(*axObject, true, [] (const AccessibilityObject& object) {
1793         return object.roleValue() == AccessibilityRole::Heading;
1794     });
1795 }
1796
1797 void AccessibilityObject::ariaTreeRows(AccessibilityChildrenVector& result)
1798 {
1799     for (const auto& child : children()) {
1800         // Add tree items as the rows.
1801         if (child->roleValue() == AccessibilityRole::TreeItem)
1802             result.append(child);
1803
1804         // Now see if this item also has rows hiding inside of it.
1805         child->ariaTreeRows(result);
1806     }
1807 }
1808     
1809 void AccessibilityObject::ariaTreeItemContent(AccessibilityChildrenVector& result)
1810 {
1811     // The ARIA tree item content are the item that are not other tree items or their containing groups.
1812     for (const auto& child : children()) {
1813         if (!child->isGroup() && child->roleValue() != AccessibilityRole::TreeItem)
1814             result.append(child);
1815     }
1816 }
1817
1818 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::disclosedRows()
1819 {
1820     AccessibilityChildrenVector result;
1821
1822     for (const auto& obj : children()) {
1823         // Add tree items as the rows.
1824         if (obj->roleValue() == AccessibilityRole::TreeItem)
1825             result.append(obj);
1826         // If it's not a tree item, then descend into the group to find more tree items.
1827         else 
1828             obj->ariaTreeRows(result);
1829     }
1830
1831     return result;
1832 }
1833
1834 const String AccessibilityObject::defaultLiveRegionStatusForRole(AccessibilityRole role)
1835 {
1836     switch (role) {
1837     case AccessibilityRole::ApplicationAlertDialog:
1838     case AccessibilityRole::ApplicationAlert:
1839         return "assertive"_s;
1840     case AccessibilityRole::ApplicationLog:
1841     case AccessibilityRole::ApplicationStatus:
1842         return "polite"_s;
1843     case AccessibilityRole::ApplicationTimer:
1844     case AccessibilityRole::ApplicationMarquee:
1845         return "off"_s;
1846     default:
1847         return nullAtom();
1848     }
1849 }
1850     
1851 #if ENABLE(ACCESSIBILITY)
1852 String AccessibilityObject::actionVerb() const
1853 {
1854 #if !PLATFORM(IOS_FAMILY)
1855     // FIXME: Need to add verbs for select elements.
1856     static NeverDestroyed<const String> buttonAction(AXButtonActionVerb());
1857     static NeverDestroyed<const String> textFieldAction(AXTextFieldActionVerb());
1858     static NeverDestroyed<const String> radioButtonAction(AXRadioButtonActionVerb());
1859     static NeverDestroyed<const String> checkedCheckBoxAction(AXCheckedCheckBoxActionVerb());
1860     static NeverDestroyed<const String> uncheckedCheckBoxAction(AXUncheckedCheckBoxActionVerb());
1861     static NeverDestroyed<const String> linkAction(AXLinkActionVerb());
1862     static NeverDestroyed<const String> menuListAction(AXMenuListActionVerb());
1863     static NeverDestroyed<const String> menuListPopupAction(AXMenuListPopupActionVerb());
1864     static NeverDestroyed<const String> listItemAction(AXListItemActionVerb());
1865
1866     switch (roleValue()) {
1867     case AccessibilityRole::Button:
1868     case AccessibilityRole::ToggleButton:
1869         return buttonAction;
1870     case AccessibilityRole::TextField:
1871     case AccessibilityRole::TextArea:
1872         return textFieldAction;
1873     case AccessibilityRole::RadioButton:
1874         return radioButtonAction;
1875     case AccessibilityRole::CheckBox:
1876     case AccessibilityRole::Switch:
1877         return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction;
1878     case AccessibilityRole::Link:
1879     case AccessibilityRole::WebCoreLink:
1880         return linkAction;
1881     case AccessibilityRole::PopUpButton:
1882         return menuListAction;
1883     case AccessibilityRole::MenuListPopup:
1884         return menuListPopupAction;
1885     case AccessibilityRole::ListItem:
1886         return listItemAction;
1887     default:
1888         return nullAtom();
1889     }
1890 #else
1891     return nullAtom();
1892 #endif
1893 }
1894 #endif
1895
1896 bool AccessibilityObject::ariaIsMultiline() const
1897 {
1898     return equalLettersIgnoringASCIICase(getAttribute(aria_multilineAttr), "true");
1899 }
1900
1901 String AccessibilityObject::invalidStatus() const
1902 {
1903     String grammarValue = "grammar"_s;
1904     String falseValue = "false"_s;
1905     String spellingValue = "spelling"_s;
1906     String trueValue = "true"_s;
1907     String undefinedValue = "undefined"_s;
1908
1909     // aria-invalid can return false (default), grammar, spelling, or true.
1910     String ariaInvalid = stripLeadingAndTrailingHTMLSpaces(getAttribute(aria_invalidAttr));
1911     
1912     if (ariaInvalid.isEmpty()) {
1913         // We should expose invalid status for input types.
1914         Node* node = this->node();
1915         if (node && is<HTMLInputElement>(*node)) {
1916             HTMLInputElement& input = downcast<HTMLInputElement>(*node);
1917             if (input.hasBadInput() || input.typeMismatch())
1918                 return trueValue;
1919         }
1920         return falseValue;
1921     }
1922     
1923     // If "false", "undefined" [sic, string value], empty, or missing, return "false".
1924     if (ariaInvalid == falseValue || ariaInvalid == undefinedValue)
1925         return falseValue;
1926     // Besides true/false/undefined, the only tokens defined by WAI-ARIA 1.0...
1927     // ...for @aria-invalid are "grammar" and "spelling".
1928     if (ariaInvalid == grammarValue)
1929         return grammarValue;
1930     if (ariaInvalid == spellingValue)
1931         return spellingValue;
1932     // Any other non empty string should be treated as "true".
1933     return trueValue;
1934 }
1935
1936 bool AccessibilityObject::supportsCurrent() const
1937 {
1938     return hasAttribute(aria_currentAttr);
1939 }
1940  
1941 AccessibilityCurrentState AccessibilityObject::currentState() const
1942 {
1943     // aria-current can return false (default), true, page, step, location, date or time.
1944     String currentStateValue = stripLeadingAndTrailingHTMLSpaces(getAttribute(aria_currentAttr));
1945     
1946     // If "false", empty, or missing, return false state.
1947     if (currentStateValue.isEmpty() || currentStateValue == "false")
1948         return AccessibilityCurrentState::False;
1949     
1950     if (currentStateValue == "page")
1951         return AccessibilityCurrentState::Page;
1952     if (currentStateValue == "step")
1953         return AccessibilityCurrentState::Step;
1954     if (currentStateValue == "location")
1955         return AccessibilityCurrentState::Location;
1956     if (currentStateValue == "date")
1957         return AccessibilityCurrentState::Date;
1958     if (currentStateValue == "time")
1959         return AccessibilityCurrentState::Time;
1960     
1961     // Any value not included in the list of allowed values should be treated as "true".
1962     return AccessibilityCurrentState::True;
1963 }
1964
1965 String AccessibilityObject::currentValue() const
1966 {
1967     switch (currentState()) {
1968     case AccessibilityCurrentState::False:
1969         return "false";
1970     case AccessibilityCurrentState::Page:
1971         return "page";
1972     case AccessibilityCurrentState::Step:
1973         return "step";
1974     case AccessibilityCurrentState::Location:
1975         return "location";
1976     case AccessibilityCurrentState::Time:
1977         return "time";
1978     case AccessibilityCurrentState::Date:
1979         return "date";
1980     default:
1981     case AccessibilityCurrentState::True:
1982         return "true";
1983     }
1984 }
1985
1986 bool AccessibilityObject::isModalDescendant(Node* modalNode) const
1987 {
1988     Node* node = this->node();
1989     if (!modalNode || !node)
1990         return false;
1991     
1992     if (node == modalNode)
1993         return true;
1994     
1995     // ARIA 1.1 aria-modal, indicates whether an element is modal when displayed.
1996     // For the decendants of the modal object, they should also be considered as aria-modal=true.
1997     return node->isDescendantOf(*modalNode);
1998 }
1999
2000 bool AccessibilityObject::isModalNode() const
2001 {
2002     if (AXObjectCache* cache = axObjectCache())
2003         return node() && cache->modalNode() == node();
2004
2005     return false;
2006 }
2007
2008 bool AccessibilityObject::ignoredFromModalPresence() const
2009 {
2010     // We shouldn't ignore the top node.
2011     if (!node() || !node()->parentNode())
2012         return false;
2013     
2014     AXObjectCache* cache = axObjectCache();
2015     if (!cache)
2016         return false;
2017     
2018     // modalNode is the current displayed modal dialog.
2019     Node* modalNode = cache->modalNode();
2020     if (!modalNode)
2021         return false;
2022     
2023     // We only want to ignore the objects within the same frame as the modal dialog.
2024     if (modalNode->document().frame() != this->frame())
2025         return false;
2026     
2027     return !isModalDescendant(modalNode);
2028 }
2029
2030 bool AccessibilityObject::hasTagName(const QualifiedName& tagName) const
2031 {
2032     Node* node = this->node();
2033     return is<Element>(node) && downcast<Element>(*node).hasTagName(tagName);
2034 }
2035     
2036 bool AccessibilityObject::hasAttribute(const QualifiedName& attribute) const
2037 {
2038     Node* node = this->node();
2039     if (!is<Element>(node))
2040         return false;
2041     
2042     return downcast<Element>(*node).hasAttributeWithoutSynchronization(attribute);
2043 }
2044     
2045 const AtomString& AccessibilityObject::getAttribute(const QualifiedName& attribute) const
2046 {
2047     if (auto* element = this->element())
2048         return element->attributeWithoutSynchronization(attribute);
2049     return nullAtom();
2050 }
2051
2052 bool AccessibilityObject::replaceTextInRange(const String& replacementString, const PlainTextRange& range)
2053 {
2054     // If this is being called on the web area, redirect it to be on the body, which will have a renderer associated with it.
2055     if (is<Document>(node())) {
2056         if (auto bodyObject = axObjectCache()->getOrCreate(downcast<Document>(node())->body()))
2057             return bodyObject->replaceTextInRange(replacementString, range);
2058         return false;
2059     }
2060     
2061     if (!renderer() || !is<Element>(node()))
2062         return false;
2063
2064     auto& element = downcast<Element>(*renderer()->node());
2065
2066     // We should use the editor's insertText to mimic typing into the field.
2067     // Also only do this when the field is in editing mode.
2068     auto& frame = renderer()->frame();
2069     if (element.shouldUseInputMethod()) {
2070         frame.selection().setSelectedRange(rangeForPlainTextRange(range).get(), DOWNSTREAM, FrameSelection::ShouldCloseTyping::Yes);
2071         frame.editor().replaceSelectionWithText(replacementString, Editor::SelectReplacement::No, Editor::SmartReplace::No);
2072         return true;
2073     }
2074     
2075     if (is<HTMLInputElement>(element)) {
2076         downcast<HTMLInputElement>(element).setRangeText(replacementString, range.start, range.length, "");
2077         return true;
2078     }
2079     if (is<HTMLTextAreaElement>(element)) {
2080         downcast<HTMLTextAreaElement>(element).setRangeText(replacementString, range.start, range.length, "");
2081         return true;
2082     }
2083
2084     return false;
2085 }
2086
2087 bool AccessibilityObject::insertText(const String& text)
2088 {
2089     if (!renderer() || !is<Element>(node()))
2090         return false;
2091
2092     auto& element = downcast<Element>(*renderer()->node());
2093
2094     // Only try to insert text if the field is in editing mode.
2095     if (!element.shouldUseInputMethod())
2096         return false;
2097
2098     // Use Editor::insertText to mimic typing into the field.
2099     auto& editor = renderer()->frame().editor();
2100     return editor.insertText(text, nullptr);
2101 }
2102
2103 // Lacking concrete evidence of orientation, horizontal means width > height. vertical is height > width;
2104 AccessibilityOrientation AccessibilityObject::orientation() const
2105 {
2106     LayoutRect bounds = elementRect();
2107     if (bounds.size().width() > bounds.size().height())
2108         return AccessibilityOrientation::Horizontal;
2109     if (bounds.size().height() > bounds.size().width())
2110         return AccessibilityOrientation::Vertical;
2111
2112     return AccessibilityOrientation::Undefined;
2113 }    
2114
2115 AccessibilityObject* AccessibilityObject::firstAnonymousBlockChild() const
2116 {
2117     for (AccessibilityObject* child = firstChild(); child; child = child->nextSibling()) {
2118         if (child->renderer() && child->renderer()->isAnonymousBlock())
2119             return child;
2120     }
2121     return nullptr;
2122 }
2123
2124 using ARIARoleMap = HashMap<String, AccessibilityRole, ASCIICaseInsensitiveHash>;
2125 using ARIAReverseRoleMap = HashMap<AccessibilityRole, String, DefaultHash<int>::Hash, WTF::UnsignedWithZeroKeyHashTraits<int>>;
2126
2127 static ARIARoleMap* gAriaRoleMap = nullptr;
2128 static ARIAReverseRoleMap* gAriaReverseRoleMap = nullptr;
2129
2130 struct RoleEntry {
2131     String ariaRole;
2132     AccessibilityRole webcoreRole;
2133 };
2134
2135 static void initializeRoleMap()
2136 {
2137     if (gAriaRoleMap)
2138         return;
2139     ASSERT(!gAriaReverseRoleMap);
2140
2141     const RoleEntry roles[] = {
2142         { "alert", AccessibilityRole::ApplicationAlert },
2143         { "alertdialog", AccessibilityRole::ApplicationAlertDialog },
2144         { "application", AccessibilityRole::WebApplication },
2145         { "article", AccessibilityRole::DocumentArticle },
2146         { "banner", AccessibilityRole::LandmarkBanner },
2147         { "blockquote", AccessibilityRole::Blockquote },
2148         { "button", AccessibilityRole::Button },
2149         { "caption", AccessibilityRole::Caption },
2150         { "checkbox", AccessibilityRole::CheckBox },
2151         { "complementary", AccessibilityRole::LandmarkComplementary },
2152         { "contentinfo", AccessibilityRole::LandmarkContentInfo },
2153         { "deletion", AccessibilityRole::Deletion },
2154         { "dialog", AccessibilityRole::ApplicationDialog },
2155         { "directory", AccessibilityRole::Directory },
2156         // The 'doc-*' roles are defined the ARIA DPUB mobile: https://www.w3.org/TR/dpub-aam-1.0/ 
2157         // Editor's draft is currently at https://rawgit.com/w3c/aria/master/dpub-aam/dpub-aam.html 
2158         { "doc-abstract", AccessibilityRole::ApplicationTextGroup },
2159         { "doc-acknowledgments", AccessibilityRole::LandmarkDocRegion },
2160         { "doc-afterword", AccessibilityRole::LandmarkDocRegion },
2161         { "doc-appendix", AccessibilityRole::LandmarkDocRegion },
2162         { "doc-backlink", AccessibilityRole::WebCoreLink },
2163         { "doc-biblioentry", AccessibilityRole::ListItem },
2164         { "doc-bibliography", AccessibilityRole::LandmarkDocRegion },
2165         { "doc-biblioref", AccessibilityRole::WebCoreLink },
2166         { "doc-chapter", AccessibilityRole::LandmarkDocRegion },
2167         { "doc-colophon", AccessibilityRole::ApplicationTextGroup },
2168         { "doc-conclusion", AccessibilityRole::LandmarkDocRegion },
2169         { "doc-cover", AccessibilityRole::Image },
2170         { "doc-credit", AccessibilityRole::ApplicationTextGroup },
2171         { "doc-credits", AccessibilityRole::LandmarkDocRegion },
2172         { "doc-dedication", AccessibilityRole::ApplicationTextGroup },
2173         { "doc-endnote", AccessibilityRole::ListItem },
2174         { "doc-endnotes", AccessibilityRole::LandmarkDocRegion },
2175         { "doc-epigraph", AccessibilityRole::ApplicationTextGroup },
2176         { "doc-epilogue", AccessibilityRole::LandmarkDocRegion },
2177         { "doc-errata", AccessibilityRole::LandmarkDocRegion },
2178         { "doc-example", AccessibilityRole::ApplicationTextGroup },
2179         { "doc-footnote", AccessibilityRole::Footnote },
2180         { "doc-foreword", AccessibilityRole::LandmarkDocRegion },
2181         { "doc-glossary", AccessibilityRole::LandmarkDocRegion },
2182         { "doc-glossref", AccessibilityRole::WebCoreLink },
2183         { "doc-index", AccessibilityRole::LandmarkNavigation },
2184         { "doc-introduction", AccessibilityRole::LandmarkDocRegion },
2185         { "doc-noteref", AccessibilityRole::WebCoreLink },
2186         { "doc-notice", AccessibilityRole::DocumentNote },
2187         { "doc-pagebreak", AccessibilityRole::Splitter },
2188         { "doc-pagelist", AccessibilityRole::LandmarkNavigation },
2189         { "doc-part", AccessibilityRole::LandmarkDocRegion },
2190         { "doc-preface", AccessibilityRole::LandmarkDocRegion },
2191         { "doc-prologue", AccessibilityRole::LandmarkDocRegion },
2192         { "doc-pullquote", AccessibilityRole::ApplicationTextGroup },
2193         { "doc-qna", AccessibilityRole::ApplicationTextGroup },
2194         { "doc-subtitle", AccessibilityRole::Heading },
2195         { "doc-tip", AccessibilityRole::DocumentNote },
2196         { "doc-toc", AccessibilityRole::LandmarkNavigation },
2197         { "figure", AccessibilityRole::Figure },
2198         // The mappings for 'graphics-*' roles are defined in this spec: https://w3c.github.io/graphics-aam/
2199         { "graphics-document", AccessibilityRole::GraphicsDocument },
2200         { "graphics-object", AccessibilityRole::GraphicsObject },
2201         { "graphics-symbol", AccessibilityRole::GraphicsSymbol },
2202         { "grid", AccessibilityRole::Grid },
2203         { "gridcell", AccessibilityRole::GridCell },
2204         { "table", AccessibilityRole::Table },
2205         { "cell", AccessibilityRole::Cell },
2206         { "columnheader", AccessibilityRole::ColumnHeader },
2207         { "combobox", AccessibilityRole::ComboBox },
2208         { "definition", AccessibilityRole::Definition },
2209         { "document", AccessibilityRole::Document },
2210         { "feed", AccessibilityRole::Feed },
2211         { "form", AccessibilityRole::Form },
2212         { "rowheader", AccessibilityRole::RowHeader },
2213         { "group", AccessibilityRole::ApplicationGroup },
2214         { "heading", AccessibilityRole::Heading },
2215         { "img", AccessibilityRole::Image },
2216         { "insertion", AccessibilityRole::Insertion },
2217         { "link", AccessibilityRole::WebCoreLink },
2218         { "list", AccessibilityRole::List },
2219         { "listitem", AccessibilityRole::ListItem },
2220         { "listbox", AccessibilityRole::ListBox },
2221         { "log", AccessibilityRole::ApplicationLog },
2222         { "main", AccessibilityRole::LandmarkMain },
2223         { "marquee", AccessibilityRole::ApplicationMarquee },
2224         { "math", AccessibilityRole::DocumentMath },
2225         { "menu", AccessibilityRole::Menu },
2226         { "menubar", AccessibilityRole::MenuBar },
2227         { "menuitem", AccessibilityRole::MenuItem },
2228         { "menuitemcheckbox", AccessibilityRole::MenuItemCheckbox },
2229         { "menuitemradio", AccessibilityRole::MenuItemRadio },
2230         { "meter", AccessibilityRole::Meter },
2231         { "none", AccessibilityRole::Presentational },
2232         { "note", AccessibilityRole::DocumentNote },
2233         { "navigation", AccessibilityRole::LandmarkNavigation },
2234         { "option", AccessibilityRole::ListBoxOption },
2235         { "paragraph", AccessibilityRole::Paragraph },
2236         { "presentation", AccessibilityRole::Presentational },
2237         { "progressbar", AccessibilityRole::ProgressIndicator },
2238         { "radio", AccessibilityRole::RadioButton },
2239         { "radiogroup", AccessibilityRole::RadioGroup },
2240         { "region", AccessibilityRole::LandmarkRegion },
2241         { "row", AccessibilityRole::Row },
2242         { "rowgroup", AccessibilityRole::RowGroup },
2243         { "scrollbar", AccessibilityRole::ScrollBar },
2244         { "search", AccessibilityRole::LandmarkSearch },
2245         { "searchbox", AccessibilityRole::SearchField },
2246         { "separator", AccessibilityRole::Splitter },
2247         { "slider", AccessibilityRole::Slider },
2248         { "spinbutton", AccessibilityRole::SpinButton },
2249         { "status", AccessibilityRole::ApplicationStatus },
2250         { "subscript", AccessibilityRole::Subscript },
2251         { "superscript", AccessibilityRole::Superscript },
2252         { "switch", AccessibilityRole::Switch },
2253         { "tab", AccessibilityRole::Tab },
2254         { "tablist", AccessibilityRole::TabList },
2255         { "tabpanel", AccessibilityRole::TabPanel },
2256         { "text", AccessibilityRole::StaticText },
2257         { "textbox", AccessibilityRole::TextArea },
2258         { "term", AccessibilityRole::Term },
2259         { "time", AccessibilityRole::Time },
2260         { "timer", AccessibilityRole::ApplicationTimer },
2261         { "toolbar", AccessibilityRole::Toolbar },
2262         { "tooltip", AccessibilityRole::UserInterfaceTooltip },
2263         { "tree", AccessibilityRole::Tree },
2264         { "treegrid", AccessibilityRole::TreeGrid },
2265         { "treeitem", AccessibilityRole::TreeItem }
2266     };
2267
2268     gAriaRoleMap = new ARIARoleMap;
2269     gAriaReverseRoleMap = new ARIAReverseRoleMap;
2270     size_t roleLength = WTF_ARRAY_LENGTH(roles);
2271     for (size_t i = 0; i < roleLength; ++i) {
2272         gAriaRoleMap->set(roles[i].ariaRole, roles[i].webcoreRole);
2273         gAriaReverseRoleMap->set(static_cast<int>(roles[i].webcoreRole), roles[i].ariaRole);
2274     }
2275 }
2276
2277 static ARIARoleMap& ariaRoleMap()
2278 {
2279     initializeRoleMap();
2280     return *gAriaRoleMap;
2281 }
2282
2283 static ARIAReverseRoleMap& reverseAriaRoleMap()
2284 {
2285     initializeRoleMap();
2286     return *gAriaReverseRoleMap;
2287 }
2288
2289 AccessibilityRole AccessibilityObject::ariaRoleToWebCoreRole(const String& value)
2290 {
2291     if (value.isNull() || value.isEmpty())
2292         return AccessibilityRole::Unknown;
2293
2294     for (auto roleName : StringView(value).split(' ')) {
2295         AccessibilityRole role = ariaRoleMap().get<ASCIICaseInsensitiveStringViewHashTranslator>(roleName);
2296         if (static_cast<int>(role))
2297             return role;
2298     }
2299     return AccessibilityRole::Unknown;
2300 }
2301
2302 String AccessibilityObject::computedRoleString() const
2303 {
2304     // FIXME: Need a few special cases that aren't in the RoleMap: option, etc. http://webkit.org/b/128296
2305     AccessibilityRole role = roleValue();
2306
2307     if (role == AccessibilityRole::Image && accessibilityIsIgnored())
2308         return reverseAriaRoleMap().get(static_cast<int>(AccessibilityRole::Presentational));
2309
2310     // We do not compute a role string for generic block elements with user-agent assigned roles.
2311     if (role == AccessibilityRole::Group || role == AccessibilityRole::TextGroup)
2312         return "";
2313
2314     // We do compute a role string for block elements with author-provided roles.
2315     if (role == AccessibilityRole::ApplicationTextGroup
2316         || role == AccessibilityRole::Footnote
2317         || role == AccessibilityRole::GraphicsObject)
2318         return reverseAriaRoleMap().get(static_cast<int>(AccessibilityRole::ApplicationGroup));
2319
2320     if (role == AccessibilityRole::GraphicsDocument)
2321         return reverseAriaRoleMap().get(static_cast<int>(AccessibilityRole::Document));
2322
2323     if (role == AccessibilityRole::GraphicsSymbol)
2324         return reverseAriaRoleMap().get(static_cast<int>(AccessibilityRole::Image));
2325
2326     if (role == AccessibilityRole::HorizontalRule)
2327         return reverseAriaRoleMap().get(static_cast<int>(AccessibilityRole::Splitter));
2328
2329     if (role == AccessibilityRole::PopUpButton || role == AccessibilityRole::ToggleButton)
2330         return reverseAriaRoleMap().get(static_cast<int>(AccessibilityRole::Button));
2331
2332     if (role == AccessibilityRole::LandmarkDocRegion)
2333         return reverseAriaRoleMap().get(static_cast<int>(AccessibilityRole::LandmarkRegion));
2334
2335     return reverseAriaRoleMap().get(static_cast<int>(role));
2336 }
2337
2338 bool AccessibilityObject::hasHighlighting() const
2339 {
2340     for (Node* node = this->node(); node; node = node->parentNode()) {
2341         if (node->hasTagName(markTag))
2342             return true;
2343     }
2344     
2345     return false;
2346 }
2347
2348 #if !PLATFORM(MAC)
2349 String AccessibilityObject::rolePlatformString() const
2350 {
2351     // FIXME: implement in other platforms.
2352     return String();
2353 }
2354
2355 String AccessibilityObject::rolePlatformDescription() const
2356 {
2357     // FIXME: implement in other platforms.
2358     return String();
2359 }
2360 #endif
2361
2362 String AccessibilityObject::ariaLandmarkRoleDescription() const
2363 {
2364     switch (roleValue()) {
2365     case AccessibilityRole::LandmarkBanner:
2366         return AXARIAContentGroupText("ARIALandmarkBanner");
2367     case AccessibilityRole::LandmarkComplementary:
2368         return AXARIAContentGroupText("ARIALandmarkComplementary");
2369     case AccessibilityRole::LandmarkContentInfo:
2370         return AXARIAContentGroupText("ARIALandmarkContentInfo");
2371     case AccessibilityRole::LandmarkMain:
2372         return AXARIAContentGroupText("ARIALandmarkMain");
2373     case AccessibilityRole::LandmarkNavigation:
2374         return AXARIAContentGroupText("ARIALandmarkNavigation");
2375     case AccessibilityRole::LandmarkDocRegion:
2376     case AccessibilityRole::LandmarkRegion:
2377         return AXARIAContentGroupText("ARIALandmarkRegion");
2378     case AccessibilityRole::LandmarkSearch:
2379         return AXARIAContentGroupText("ARIALandmarkSearch");
2380     case AccessibilityRole::ApplicationAlert:
2381         return AXARIAContentGroupText("ARIAApplicationAlert");
2382     case AccessibilityRole::ApplicationAlertDialog:
2383         return AXARIAContentGroupText("ARIAApplicationAlertDialog");
2384     case AccessibilityRole::ApplicationDialog:
2385         return AXARIAContentGroupText("ARIAApplicationDialog");
2386     case AccessibilityRole::ApplicationLog:
2387         return AXARIAContentGroupText("ARIAApplicationLog");
2388     case AccessibilityRole::ApplicationMarquee:
2389         return AXARIAContentGroupText("ARIAApplicationMarquee");
2390     case AccessibilityRole::ApplicationStatus:
2391         return AXARIAContentGroupText("ARIAApplicationStatus");
2392     case AccessibilityRole::ApplicationTimer:
2393         return AXARIAContentGroupText("ARIAApplicationTimer");
2394     case AccessibilityRole::Document:
2395         return AXARIAContentGroupText("ARIADocument");
2396     case AccessibilityRole::DocumentArticle:
2397         return AXARIAContentGroupText("ARIADocumentArticle");
2398     case AccessibilityRole::DocumentMath:
2399         return AXARIAContentGroupText("ARIADocumentMath");
2400     case AccessibilityRole::DocumentNote:
2401         return AXARIAContentGroupText("ARIADocumentNote");
2402     case AccessibilityRole::UserInterfaceTooltip:
2403         return AXARIAContentGroupText("ARIAUserInterfaceTooltip");
2404     case AccessibilityRole::TabPanel:
2405         return AXARIAContentGroupText("ARIATabPanel");
2406     case AccessibilityRole::WebApplication:
2407         return AXARIAContentGroupText("ARIAWebApplication");
2408     default:
2409         return String();
2410     }
2411 }
2412
2413 String AccessibilityObject::roleDescription() const
2414 {
2415     // aria-roledescription takes precedence over any other rule.
2416     String roleDescription = stripLeadingAndTrailingHTMLSpaces(getAttribute(aria_roledescriptionAttr));
2417     if (!roleDescription.isEmpty())
2418         return roleDescription;
2419
2420     roleDescription = rolePlatformDescription();
2421     if (!roleDescription.isEmpty())
2422         return roleDescription;
2423
2424     if (roleValue() == AccessibilityRole::Figure)
2425         return AXFigureText();
2426
2427     return roleDescription;
2428 }
2429
2430 bool nodeHasPresentationRole(Node* node)
2431 {
2432     return nodeHasRole(node, "presentation") || nodeHasRole(node, "none");
2433 }
2434     
2435 bool AccessibilityObject::supportsPressAction() const
2436 {
2437     if (isButton())
2438         return true;
2439     if (roleValue() == AccessibilityRole::Details)
2440         return true;
2441     
2442     Element* actionElement = this->actionElement();
2443     if (!actionElement)
2444         return false;
2445     
2446     // [Bug: 136247] Heuristic: element handlers that have more than one accessible descendant should not be exposed as supporting press.
2447     if (actionElement != element()) {
2448         if (AccessibilityObject* axObj = axObjectCache()->getOrCreate(actionElement)) {
2449             AccessibilityChildrenVector results;
2450             // Search within for immediate descendants that are static text. If we find more than one
2451             // then this is an event delegator actionElement and we should expose the press action.
2452             Vector<AccessibilitySearchKey> keys({ AccessibilitySearchKey::StaticText, AccessibilitySearchKey::Control, AccessibilitySearchKey::Graphic, AccessibilitySearchKey::Heading, AccessibilitySearchKey::Link });
2453             AccessibilitySearchCriteria criteria(axObj, AccessibilitySearchDirection::Next, emptyString(), 2, false, false);
2454             criteria.searchKeys = keys;
2455             axObj->findMatchingObjects(&criteria, results);
2456             if (results.size() > 1)
2457                 return false;
2458         }
2459     }
2460     
2461     // [Bug: 133613] Heuristic: If the action element is presentational, we shouldn't expose press as a supported action.
2462     return !nodeHasPresentationRole(actionElement);
2463 }
2464
2465 bool AccessibilityObject::supportsDatetimeAttribute() const
2466 {
2467     return hasTagName(insTag) || hasTagName(delTag) || hasTagName(timeTag);
2468 }
2469
2470 String AccessibilityObject::datetimeAttributeValue() const
2471 {
2472     return getAttribute(datetimeAttr);
2473 }
2474     
2475 String AccessibilityObject::linkRelValue() const
2476 {
2477     return getAttribute(relAttr);
2478 }
2479     
2480 bool AccessibilityObject::isInlineText() const
2481 {
2482     return is<RenderInline>(renderer());
2483 }
2484
2485 const String AccessibilityObject::keyShortcutsValue() const
2486 {
2487     return getAttribute(aria_keyshortcutsAttr);
2488 }
2489
2490 Element* AccessibilityObject::element() const
2491 {
2492     Node* node = this->node();
2493     if (is<Element>(node))
2494         return downcast<Element>(node);
2495     return nullptr;
2496 }
2497     
2498 bool AccessibilityObject::isValueAutofillAvailable() const
2499 {
2500     if (!isNativeTextControl())
2501         return false;
2502     
2503     Node* node = this->node();
2504     if (!is<HTMLInputElement>(node))
2505         return false;
2506     
2507     return downcast<HTMLInputElement>(*node).isAutoFillAvailable() || downcast<HTMLInputElement>(*node).autoFillButtonType() != AutoFillButtonType::None;
2508 }
2509
2510 AutoFillButtonType AccessibilityObject::valueAutofillButtonType() const
2511 {
2512     if (!isValueAutofillAvailable())
2513         return AutoFillButtonType::None;
2514     
2515     return downcast<HTMLInputElement>(*this->node()).autoFillButtonType();
2516 }
2517     
2518 bool AccessibilityObject::isValueAutofilled() const
2519 {
2520     if (!isNativeTextControl())
2521         return false;
2522     
2523     Node* node = this->node();
2524     if (!is<HTMLInputElement>(node))
2525         return false;
2526     
2527     return downcast<HTMLInputElement>(*node).isAutoFilled();
2528 }
2529
2530 const String AccessibilityObject::placeholderValue() const
2531 {
2532     const AtomString& placeholder = getAttribute(placeholderAttr);
2533     if (!placeholder.isEmpty())
2534         return placeholder;
2535     
2536     const AtomString& ariaPlaceholder = getAttribute(aria_placeholderAttr);
2537     if (!ariaPlaceholder.isEmpty())
2538         return ariaPlaceholder;
2539     
2540     return nullAtom();
2541 }
2542     
2543 bool AccessibilityObject::isInsideLiveRegion(bool excludeIfOff) const
2544 {
2545     return liveRegionAncestor(excludeIfOff);
2546 }
2547     
2548 AccessibilityObject* AccessibilityObject::liveRegionAncestor(bool excludeIfOff) const
2549 {
2550     return Accessibility::findAncestor<AccessibilityObject>(*this, true, [excludeIfOff] (const AccessibilityObject& object) {
2551         return object.supportsLiveRegion(excludeIfOff);
2552     });
2553 }
2554
2555 bool AccessibilityObject::supportsARIAAttributes() const
2556 {
2557     // This returns whether the element supports any global ARIA attributes.
2558     return supportsLiveRegion()
2559         || supportsARIADragging()
2560         || supportsARIADropping()
2561         || supportsARIAOwns()
2562         || hasAttribute(aria_atomicAttr)
2563         || hasAttribute(aria_busyAttr)
2564         || hasAttribute(aria_controlsAttr)
2565         || hasAttribute(aria_currentAttr)
2566         || hasAttribute(aria_describedbyAttr)
2567         || hasAttribute(aria_detailsAttr)
2568         || hasAttribute(aria_disabledAttr)
2569         || hasAttribute(aria_errormessageAttr)
2570         || hasAttribute(aria_flowtoAttr)
2571         || hasAttribute(aria_haspopupAttr)
2572         || hasAttribute(aria_invalidAttr)
2573         || hasAttribute(aria_labelAttr)
2574         || hasAttribute(aria_labelledbyAttr)
2575         || hasAttribute(aria_relevantAttr);
2576 }
2577     
2578 bool AccessibilityObject::liveRegionStatusIsEnabled(const AtomString& liveRegionStatus)
2579 {
2580     return equalLettersIgnoringASCIICase(liveRegionStatus, "polite") || equalLettersIgnoringASCIICase(liveRegionStatus, "assertive");
2581 }
2582     
2583 bool AccessibilityObject::supportsLiveRegion(bool excludeIfOff) const
2584 {
2585     const AtomString& liveRegionStatusValue = liveRegionStatus();
2586     return excludeIfOff ? liveRegionStatusIsEnabled(liveRegionStatusValue) : !liveRegionStatusValue.isEmpty();
2587 }
2588
2589 AXCoreObject* AccessibilityObject::elementAccessibilityHitTest(const IntPoint& point) const
2590
2591     // Send the hit test back into the sub-frame if necessary.
2592     if (isAttachment()) {
2593         Widget* widget = widgetForAttachmentView();
2594         // Normalize the point for the widget's bounds.
2595         if (widget && widget->isFrameView()) {
2596             if (AXObjectCache* cache = axObjectCache())
2597                 return cache->getOrCreate(widget)->accessibilityHitTest(IntPoint(point - widget->frameRect().location()));
2598         }
2599     }
2600     
2601     // Check if there are any mock elements that need to be handled.
2602     for (const auto& child : m_children) {
2603         if (child->isMockObject() && child->elementRect().contains(point))
2604             return child->elementAccessibilityHitTest(point);
2605     }
2606
2607     return const_cast<AccessibilityObject*>(this);
2608 }
2609     
2610 AXObjectCache* AccessibilityObject::axObjectCache() const
2611 {
2612     auto* document = this->document();
2613     return document ? document->axObjectCache() : nullptr;
2614 }
2615     
2616 AXCoreObject* AccessibilityObject::focusedUIElement() const
2617 {
2618     auto* page = this->page();
2619     auto* axObjectCache = this->axObjectCache();
2620     return page && axObjectCache ? axObjectCache->focusedUIElementForPage(page) : nullptr;
2621 }
2622     
2623 AccessibilitySortDirection AccessibilityObject::sortDirection() const
2624 {
2625     AccessibilityRole role = roleValue();
2626     if (role != AccessibilityRole::RowHeader && role != AccessibilityRole::ColumnHeader)
2627         return AccessibilitySortDirection::Invalid;
2628
2629     const AtomString& sortAttribute = getAttribute(aria_sortAttr);
2630     if (equalLettersIgnoringASCIICase(sortAttribute, "ascending"))
2631         return AccessibilitySortDirection::Ascending;
2632     if (equalLettersIgnoringASCIICase(sortAttribute, "descending"))
2633         return AccessibilitySortDirection::Descending;
2634     if (equalLettersIgnoringASCIICase(sortAttribute, "other"))
2635         return AccessibilitySortDirection::Other;
2636     
2637     return AccessibilitySortDirection::None;
2638 }
2639
2640 bool AccessibilityObject::supportsRangeValue() const
2641 {
2642     return isProgressIndicator()
2643         || isSlider()
2644         || isScrollbar()
2645         || isSpinButton()
2646         || (isSplitter() && canSetFocusAttribute())
2647         || isAttachmentElement();
2648 }
2649     
2650 bool AccessibilityObject::supportsHasPopup() const
2651 {
2652     return hasAttribute(aria_haspopupAttr) || isComboBox();
2653 }
2654
2655 String AccessibilityObject::popupValue() const
2656 {
2657     static const NeverDestroyed<HashSet<String>> allowedPopupValues(std::initializer_list<String> {
2658         "menu", "listbox", "tree", "grid", "dialog"
2659     });
2660
2661     auto hasPopup = getAttribute(aria_haspopupAttr).convertToASCIILowercase();
2662     if (hasPopup.isNull() || hasPopup.isEmpty()) {
2663         // In ARIA 1.1, the implicit value for combobox became "listbox."
2664         if (isComboBox() || hasDatalist())
2665             return "listbox";
2666         return "false";
2667     }
2668
2669     if (allowedPopupValues->contains(hasPopup))
2670         return hasPopup;
2671
2672     // aria-haspopup specification states that true must be treated as menu.
2673     if (hasPopup == "true")
2674         return "menu";
2675
2676     // The spec states that "User agents must treat any value of aria-haspopup that is not
2677     // included in the list of allowed values, including an empty string, as if the value
2678     // false had been provided."
2679     return "false";
2680 }
2681
2682 bool AccessibilityObject::hasDatalist() const
2683 {
2684 #if ENABLE(DATALIST_ELEMENT)
2685     auto datalistId = getAttribute(listAttr);
2686     if (datalistId.isNull() || datalistId.isEmpty())
2687         return false;
2688
2689     auto element = this->element();
2690     if (!element)
2691         return false;
2692
2693     auto datalist = element->treeScope().getElementById(datalistId);
2694     return is<HTMLDataListElement>(datalist);
2695 #else
2696     return false;
2697 #endif
2698 }
2699
2700 bool AccessibilityObject::supportsSetSize() const
2701 {
2702     return hasAttribute(aria_setsizeAttr);
2703 }
2704
2705 bool AccessibilityObject::supportsPosInSet() const
2706 {
2707     return hasAttribute(aria_posinsetAttr);
2708 }
2709     
2710 int AccessibilityObject::setSize() const
2711 {
2712     return getAttribute(aria_setsizeAttr).toInt();
2713 }
2714
2715 int AccessibilityObject::posInSet() const
2716 {
2717     return getAttribute(aria_posinsetAttr).toInt();
2718 }
2719     
2720 String AccessibilityObject::identifierAttribute() const
2721 {
2722     return getAttribute(idAttr);
2723 }
2724     
2725 void AccessibilityObject::classList(Vector<String>& classList) const
2726 {
2727     Node* node = this->node();
2728     if (!is<Element>(node))
2729         return;
2730     
2731     Element* element = downcast<Element>(node);
2732     DOMTokenList& list = element->classList();
2733     unsigned length = list.length();
2734     for (unsigned k = 0; k < length; k++)
2735         classList.append(list.item(k).string());
2736 }
2737
2738 bool AccessibilityObject::supportsPressed() const
2739 {
2740     const AtomString& expanded = getAttribute(aria_pressedAttr);
2741     return equalLettersIgnoringASCIICase(expanded, "true") || equalLettersIgnoringASCIICase(expanded, "false");
2742 }
2743     
2744 bool AccessibilityObject::supportsExpanded() const
2745 {
2746     // Undefined values should not result in this attribute being exposed to ATs according to ARIA.
2747     const AtomString& expanded = getAttribute(aria_expandedAttr);
2748     if (equalLettersIgnoringASCIICase(expanded, "true") || equalLettersIgnoringASCIICase(expanded, "false"))
2749         return true;
2750     switch (roleValue()) {
2751     case AccessibilityRole::ComboBox:
2752     case AccessibilityRole::DisclosureTriangle:
2753     case AccessibilityRole::Details:
2754         return true;
2755     default:
2756         return false;
2757     }
2758 }
2759     
2760 bool AccessibilityObject::isExpanded() const
2761 {
2762     if (equalLettersIgnoringASCIICase(getAttribute(aria_expandedAttr), "true"))
2763         return true;
2764     
2765     if (is<HTMLDetailsElement>(node()))
2766         return downcast<HTMLDetailsElement>(node())->isOpen();
2767     
2768     // Summary element should use its details parent's expanded status.
2769     if (isSummary()) {
2770         if (const AccessibilityObject* parent = Accessibility::findAncestor<AccessibilityObject>(*this, false, [] (const AccessibilityObject& object) {
2771             return is<HTMLDetailsElement>(object.node());
2772         }))
2773             return parent->isExpanded();
2774     }
2775
2776     return false;  
2777 }
2778
2779 bool AccessibilityObject::supportsChecked() const
2780 {
2781     switch (roleValue()) {
2782     case AccessibilityRole::CheckBox:
2783     case AccessibilityRole::MenuItemCheckbox:
2784     case AccessibilityRole::MenuItemRadio:
2785     case AccessibilityRole::RadioButton:
2786     case AccessibilityRole::Switch:
2787         return true;
2788     default:
2789         return false;
2790     }
2791 }
2792
2793 AccessibilityButtonState AccessibilityObject::checkboxOrRadioValue() const
2794 {
2795     // If this is a real checkbox or radio button, AccessibilityRenderObject will handle.
2796     // If it's an ARIA checkbox, radio, or switch the aria-checked attribute should be used.
2797     // If it's a toggle button, the aria-pressed attribute is consulted.
2798
2799     if (isToggleButton()) {
2800         const AtomString& ariaPressed = getAttribute(aria_pressedAttr);
2801         if (equalLettersIgnoringASCIICase(ariaPressed, "true"))
2802             return AccessibilityButtonState::On;
2803         if (equalLettersIgnoringASCIICase(ariaPressed, "mixed"))
2804             return AccessibilityButtonState::Mixed;
2805         return AccessibilityButtonState::Off;
2806     }
2807     
2808     const AtomString& result = getAttribute(aria_checkedAttr);
2809     if (equalLettersIgnoringASCIICase(result, "true"))
2810         return AccessibilityButtonState::On;
2811     if (equalLettersIgnoringASCIICase(result, "mixed")) {
2812         // ARIA says that radio, menuitemradio, and switch elements must NOT expose button state mixed.
2813         AccessibilityRole ariaRole = ariaRoleAttribute();
2814         if (ariaRole == AccessibilityRole::RadioButton || ariaRole == AccessibilityRole::MenuItemRadio || ariaRole == AccessibilityRole::Switch)
2815             return AccessibilityButtonState::Off;
2816         return AccessibilityButtonState::Mixed;
2817     }
2818     
2819     if (isIndeterminate())
2820         return AccessibilityButtonState::Mixed;
2821     
2822     return AccessibilityButtonState::Off;
2823 }
2824
2825 // This is a 1-dimensional scroll offset helper function that's applied
2826 // separately in the horizontal and vertical directions, because the
2827 // logic is the same. The goal is to compute the best scroll offset
2828 // in order to make an object visible within a viewport.
2829 //
2830 // If the object is already fully visible, returns the same scroll
2831 // offset.
2832 //
2833 // In case the whole object cannot fit, you can specify a
2834 // subfocus - a smaller region within the object that should
2835 // be prioritized. If the whole object can fit, the subfocus is
2836 // ignored.
2837 //
2838 // If possible, the object and subfocus are centered within the
2839 // viewport.
2840 //
2841 // Example 1: the object is already visible, so nothing happens.
2842 //   +----------Viewport---------+
2843 //                 +---Object---+
2844 //                 +--SubFocus--+
2845 //
2846 // Example 2: the object is not fully visible, so it's centered
2847 // within the viewport.
2848 //   Before:
2849 //   +----------Viewport---------+
2850 //                         +---Object---+
2851 //                         +--SubFocus--+
2852 //
2853 //   After:
2854 //                 +----------Viewport---------+
2855 //                         +---Object---+
2856 //                         +--SubFocus--+
2857 //
2858 // Example 3: the object is larger than the viewport, so the
2859 // viewport moves to show as much of the object as possible,
2860 // while also trying to center the subfocus.
2861 //   Before:
2862 //   +----------Viewport---------+
2863 //     +---------------Object--------------+
2864 //                         +-SubFocus-+
2865 //
2866 //   After:
2867 //             +----------Viewport---------+
2868 //     +---------------Object--------------+
2869 //                         +-SubFocus-+
2870 //
2871 // When constraints cannot be fully satisfied, the min
2872 // (left/top) position takes precedence over the max (right/bottom).
2873 //
2874 // Note that the return value represents the ideal new scroll offset.
2875 // This may be out of range - the calling function should clip this
2876 // to the available range.
2877 static int computeBestScrollOffset(int currentScrollOffset, int subfocusMin, int subfocusMax, int objectMin, int objectMax, int viewportMin, int viewportMax)
2878 {
2879     int viewportSize = viewportMax - viewportMin;
2880     
2881     // If the object size is larger than the viewport size, consider
2882     // only a portion that's as large as the viewport, centering on
2883     // the subfocus as much as possible.
2884     if (objectMax - objectMin > viewportSize) {
2885         // Since it's impossible to fit the whole object in the
2886         // viewport, exit now if the subfocus is already within the viewport.
2887         if (subfocusMin - currentScrollOffset >= viewportMin && subfocusMax - currentScrollOffset <= viewportMax)
2888             return currentScrollOffset;
2889         
2890         // Subfocus must be within focus.
2891         subfocusMin = std::max(subfocusMin, objectMin);
2892         subfocusMax = std::min(subfocusMax, objectMax);
2893         
2894         // Subfocus must be no larger than the viewport size; favor top/left.
2895         if (subfocusMax - subfocusMin > viewportSize)
2896             subfocusMax = subfocusMin + viewportSize;
2897         
2898         // Compute the size of an object centered on the subfocus, the size of the viewport.
2899         int centeredObjectMin = (subfocusMin + subfocusMax - viewportSize) / 2;
2900         int centeredObjectMax = centeredObjectMin + viewportSize;
2901
2902         objectMin = std::max(objectMin, centeredObjectMin);
2903         objectMax = std::min(objectMax, centeredObjectMax);
2904     }
2905
2906     // Exit now if the focus is already within the viewport.
2907     if (objectMin - currentScrollOffset >= viewportMin
2908         && objectMax - currentScrollOffset <= viewportMax)
2909         return currentScrollOffset;
2910     
2911     // Center the object in the viewport.
2912     return (objectMin + objectMax - viewportMin - viewportMax) / 2;
2913 }
2914
2915 bool AccessibilityObject::isOnScreen() const
2916 {   
2917     bool isOnscreen = true;
2918
2919     // To figure out if the element is onscreen, we start by building of a stack starting with the
2920     // element, and then include every scrollable parent in the hierarchy.
2921     Vector<const AccessibilityObject*> objects;
2922     
2923     objects.append(this);
2924     for (AccessibilityObject* parentObject = this->parentObject(); parentObject; parentObject = parentObject->parentObject()) {
2925         if (parentObject->getScrollableAreaIfScrollable())
2926             objects.append(parentObject);
2927     }
2928
2929     // Now, go back through that chain and make sure each inner object is within the
2930     // visible bounds of the outer object.
2931     size_t levels = objects.size() - 1;
2932     
2933     for (size_t i = levels; i >= 1; i--) {
2934         const AccessibilityObject* outer = objects[i];
2935         const AccessibilityObject* inner = objects[i - 1];
2936         // FIXME: unclear if we need LegacyIOSDocumentVisibleRect.
2937         const IntRect outerRect = i < levels ? snappedIntRect(outer->boundingBoxRect()) : outer->getScrollableAreaIfScrollable()->visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
2938         const IntRect innerRect = snappedIntRect(inner->isScrollView() ? inner->parentObject()->boundingBoxRect() : inner->boundingBoxRect());
2939         
2940         if (!outerRect.intersects(innerRect)) {
2941             isOnscreen = false;
2942             break;
2943         }
2944     }
2945     
2946     return isOnscreen;
2947 }
2948
2949 void AccessibilityObject::scrollToMakeVisible() const
2950 {
2951     scrollToMakeVisible({ SelectionRevealMode::Reveal, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded, ShouldAllowCrossOriginScrolling::Yes });
2952 }
2953
2954 void AccessibilityObject::scrollToMakeVisible(const ScrollRectToVisibleOptions& options) const
2955 {
2956     if (isScrollView() && parentObject())
2957         parentObject()->scrollToMakeVisible();
2958
2959     if (auto* renderer = this->renderer())
2960         renderer->scrollRectToVisible(boundingBoxRect(), false, options);
2961 }
2962
2963 void AccessibilityObject::scrollToMakeVisibleWithSubFocus(const IntRect& subfocus) const
2964 {
2965     // Search up the parent chain until we find the first one that's scrollable.
2966     AccessibilityObject* scrollParent = parentObject();
2967     ScrollableArea* scrollableArea;
2968     for (scrollableArea = nullptr;
2969          scrollParent && !(scrollableArea = scrollParent->getScrollableAreaIfScrollable());
2970          scrollParent = scrollParent->parentObject()) { }
2971     if (!scrollableArea)
2972         return;
2973
2974     LayoutRect objectRect = boundingBoxRect();
2975     IntPoint scrollPosition = scrollableArea->scrollPosition();
2976     // FIXME: unclear if we need LegacyIOSDocumentVisibleRect.
2977     IntRect scrollVisibleRect = scrollableArea->visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
2978
2979     if (!scrollParent->isScrollView()) {
2980         objectRect.moveBy(scrollPosition);
2981         objectRect.moveBy(-snappedIntRect(scrollParent->elementRect()).location());
2982     }
2983     
2984     int desiredX = computeBestScrollOffset(
2985         scrollPosition.x(),
2986         objectRect.x() + subfocus.x(), objectRect.x() + subfocus.maxX(),
2987         objectRect.x(), objectRect.maxX(),
2988         0, scrollVisibleRect.width());
2989     int desiredY = computeBestScrollOffset(
2990         scrollPosition.y(),
2991         objectRect.y() + subfocus.y(), objectRect.y() + subfocus.maxY(),
2992         objectRect.y(), objectRect.maxY(),
2993         0, scrollVisibleRect.height());
2994
2995     scrollParent->scrollTo(IntPoint(desiredX, desiredY));
2996
2997     // Convert the subfocus into the coordinates of the scroll parent.
2998     IntRect newSubfocus = subfocus;
2999     IntRect newElementRect = snappedIntRect(elementRect());
3000     IntRect scrollParentRect = snappedIntRect(scrollParent->elementRect());
3001     newSubfocus.move(newElementRect.x(), newElementRect.y());
3002     newSubfocus.move(-scrollParentRect.x(), -scrollParentRect.y());
3003     
3004     // Recursively make sure the scroll parent itself is visible.
3005     if (scrollParent->parentObject())
3006         scrollParent->scrollToMakeVisibleWithSubFocus(newSubfocus);
3007 }
3008
3009 void AccessibilityObject::scrollToGlobalPoint(const IntPoint& globalPoint) const
3010 {
3011     // Search up the parent chain and create a vector of all scrollable parent objects
3012     // and ending with this object itself.
3013     Vector<const AccessibilityObject*> objects;
3014
3015     objects.append(this);
3016     for (AccessibilityObject* parentObject = this->parentObject(); parentObject; parentObject = parentObject->parentObject()) {
3017         if (parentObject->getScrollableAreaIfScrollable())
3018             objects.append(parentObject);
3019     }
3020
3021     objects.reverse();
3022
3023     // Start with the outermost scrollable (the main window) and try to scroll the
3024     // next innermost object to the given point.
3025     int offsetX = 0, offsetY = 0;
3026     IntPoint point = globalPoint;
3027     size_t levels = objects.size() - 1;
3028     for (size_t i = 0; i < levels; i++) {
3029         const AccessibilityObject* outer = objects[i];
3030         const AccessibilityObject* inner = objects[i + 1];
3031
3032         ScrollableArea* scrollableArea = outer->getScrollableAreaIfScrollable();
3033
3034         LayoutRect innerRect = inner->isScrollView() ? inner->parentObject()->boundingBoxRect() : inner->boundingBoxRect();
3035         LayoutRect objectRect = innerRect;
3036         IntPoint scrollPosition = scrollableArea->scrollPosition();
3037
3038         // Convert the object rect into local coordinates.
3039         objectRect.move(offsetX, offsetY);
3040         if (!outer->isScrollView())
3041             objectRect.move(scrollPosition.x(), scrollPosition.y());
3042
3043         int desiredX = computeBestScrollOffset(
3044             0,
3045             objectRect.x(), objectRect.maxX(),
3046             objectRect.x(), objectRect.maxX(),
3047             point.x(), point.x());
3048         int desiredY = computeBestScrollOffset(
3049             0,
3050             objectRect.y(), objectRect.maxY(),
3051             objectRect.y(), objectRect.maxY(),
3052             point.y(), point.y());
3053         outer->scrollTo(IntPoint(desiredX, desiredY));
3054
3055         if (outer->isScrollView() && !inner->isScrollView()) {
3056             // If outer object we just scrolled is a scroll view (main window or iframe) but the
3057             // inner object is not, keep track of the coordinate transformation to apply to
3058             // future nested calculations.
3059             scrollPosition = scrollableArea->scrollPosition();
3060             offsetX -= (scrollPosition.x() + point.x());
3061             offsetY -= (scrollPosition.y() + point.y());
3062             point.move(scrollPosition.x() - innerRect.x(),
3063                        scrollPosition.y() - innerRect.y());
3064         } else if (inner->isScrollView()) {
3065             // Otherwise, if the inner object is a scroll view, reset the coordinate transformation.
3066             offsetX = 0;
3067             offsetY = 0;
3068         }
3069     }
3070 }
3071     
3072 void AccessibilityObject::scrollAreaAndAncestor(std::pair<ScrollableArea*, AccessibilityObject*>& scrollers) const
3073 {
3074     // Search up the parent chain until we find the first one that's scrollable.
3075     scrollers.first = nullptr;
3076     for (scrollers.second = parentObject(); scrollers.second; scrollers.second = scrollers.second->parentObject()) {
3077         if ((scrollers.first = scrollers.second->getScrollableAreaIfScrollable()))
3078             break;
3079     }
3080 }
3081     
3082 ScrollableArea* AccessibilityObject::scrollableAreaAncestor() const
3083 {
3084     std::pair<ScrollableArea*, AccessibilityObject*> scrollers;
3085     scrollAreaAndAncestor(scrollers);
3086     return scrollers.first;
3087 }
3088     
3089 IntPoint AccessibilityObject::scrollPosition() const
3090 {
3091     if (auto scroller = scrollableAreaAncestor())
3092         return scroller->scrollPosition();
3093
3094     return IntPoint();
3095 }
3096
3097 IntRect AccessibilityObject::scrollVisibleContentRect() const
3098 {
3099     if (auto scroller = scrollableAreaAncestor())
3100         return scroller->visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
3101     
3102     return IntRect();
3103 }
3104     
3105 IntSize AccessibilityObject::scrollContentsSize() const
3106 {
3107     if (auto scroller = scrollableAreaAncestor())
3108         return scroller->contentsSize();
3109
3110     return IntSize();
3111 }
3112     
3113 bool AccessibilityObject::scrollByPage(ScrollByPageDirection direction) const
3114 {
3115     std::pair<ScrollableArea*, AccessibilityObject*> scrollers;
3116     scrollAreaAndAncestor(scrollers);
3117     ScrollableArea* scrollableArea = scrollers.first;
3118     AccessibilityObject* scrollParent = scrollers.second;
3119     
3120     if (!scrollableArea)
3121         return false;
3122     
3123     IntPoint scrollPosition = scrollableArea->scrollPosition();
3124     IntPoint newScrollPosition = scrollPosition;
3125     IntSize scrollSize = scrollableArea->contentsSize();
3126     IntRect scrollVisibleRect = scrollableArea->visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
3127     switch (direction) {
3128     case ScrollByPageDirection::Right: {
3129         int scrollAmount = scrollVisibleRect.size().width();
3130         int newX = scrollPosition.x() - scrollAmount;
3131         newScrollPosition.setX(std::max(newX, 0));
3132         break;
3133     }
3134     case ScrollByPageDirection::Left: {
3135         int scrollAmount = scrollVisibleRect.size().width();
3136         int newX = scrollAmount + scrollPosition.x();
3137         int maxX = scrollSize.width() - scrollAmount;
3138         newScrollPosition.setX(std::min(newX, maxX));
3139         break;
3140     }
3141     case ScrollByPageDirection::Up: {
3142         int scrollAmount = scrollVisibleRect.size().height();
3143         int newY = scrollPosition.y() - scrollAmount;
3144         newScrollPosition.setY(std::max(newY, 0));
3145         break;
3146     }
3147     case ScrollByPageDirection::Down: {
3148         int scrollAmount = scrollVisibleRect.size().height();
3149         int newY = scrollAmount + scrollPosition.y();
3150         int maxY = scrollSize.height() - scrollAmount;
3151         newScrollPosition.setY(std::min(newY, maxY));
3152         break;
3153     }
3154     }
3155     
3156     if (newScrollPosition != scrollPosition) {
3157         scrollParent->scrollTo(newScrollPosition);
3158         document()->updateLayoutIgnorePendingStylesheets();
3159         return true;
3160     }
3161     
3162     return false;
3163 }
3164
3165
3166 bool AccessibilityObject::lastKnownIsIgnoredValue()
3167 {
3168     if (m_lastKnownIsIgnoredValue == AccessibilityObjectInclusion::DefaultBehavior)
3169         m_lastKnownIsIgnoredValue = accessibilityIsIgnored() ? AccessibilityObjectInclusion::IgnoreObject : AccessibilityObjectInclusion::IncludeObject;
3170
3171     return m_lastKnownIsIgnoredValue == AccessibilityObjectInclusion::IgnoreObject;
3172 }
3173
3174 void AccessibilityObject::setLastKnownIsIgnoredValue(bool isIgnored)
3175 {
3176     m_lastKnownIsIgnoredValue = isIgnored ? AccessibilityObjectInclusion::IgnoreObject : AccessibilityObjectInclusion::IncludeObject;
3177 }
3178
3179 void AccessibilityObject::notifyIfIgnoredValueChanged()
3180 {
3181     bool isIgnored = accessibilityIsIgnored();
3182     if (lastKnownIsIgnoredValue() != isIgnored) {
3183         if (AXObjectCache* cache = axObjectCache())
3184             cache->childrenChanged(parentObject());
3185         setLastKnownIsIgnoredValue(isIgnored);
3186     }
3187 }
3188
3189 bool AccessibilityObject::pressedIsPresent() const
3190 {
3191     return !getAttribute(aria_pressedAttr).isEmpty();
3192 }
3193
3194 TextIteratorBehavior AccessibilityObject::textIteratorBehaviorForTextRange() const
3195 {
3196     TextIteratorBehavior behavior = TextIteratorIgnoresStyleVisibility;
3197     
3198 #if USE(ATK)
3199     // We need to emit replaced elements for GTK, and present
3200     // them with the 'object replacement character' (0xFFFC).
3201     behavior = static_cast<TextIteratorBehavior>(behavior | TextIteratorEmitsObjectReplacementCharacters);
3202 #endif
3203     
3204     return behavior;
3205 }
3206     
3207 AccessibilityRole AccessibilityObject::buttonRoleType() const
3208 {
3209     // If aria-pressed is present, then it should be exposed as a toggle button.
3210     // http://www.w3.org/TR/wai-aria/states_and_properties#aria-pressed
3211     if (pressedIsPresent())
3212         return AccessibilityRole::ToggleButton;
3213     if (hasPopup())
3214         return AccessibilityRole::PopUpButton;
3215     // We don't contemplate AccessibilityRole::RadioButton, as it depends on the input
3216     // type.
3217
3218     return AccessibilityRole::Button;
3219 }
3220
3221 bool AccessibilityObject::isButton() const
3222 {
3223     AccessibilityRole role = roleValue();
3224
3225     return role == AccessibilityRole::Button || role == AccessibilityRole::PopUpButton || role == AccessibilityRole::ToggleButton;
3226 }
3227
3228 bool AccessibilityObject::accessibilityIsIgnoredByDefault() const
3229 {
3230     return defaultObjectInclusion() == AccessibilityObjectInclusion::IgnoreObject;
3231 }
3232
3233 // ARIA component of hidden definition.
3234 // http://www.w3.org/TR/wai-aria/terms#def_hidden
3235 bool AccessibilityObject::isAXHidden() const
3236 {
3237     return Accessibility::findAncestor<AccessibilityObject>(*this, true, [] (const AccessibilityObject& object) {
3238         return equalLettersIgnoringASCIICase(object.getAttribute(aria_hiddenAttr), "true");
3239     }) != nullptr;
3240 }
3241
3242 // DOM component of hidden definition.
3243 // http://www.w3.org/TR/wai-aria/terms#def_hidden
3244 bool AccessibilityObject::isDOMHidden() const
3245 {
3246     RenderObject* renderer = this->renderer();
3247     if (!renderer)
3248         return true;
3249     
3250     const RenderStyle& style = renderer->style();
3251     return style.display() == DisplayType::None || style.visibility() != Visibility::Visible;
3252 }
3253
3254 bool AccessibilityObject::isShowingValidationMessage() const
3255 {
3256     if (is<HTMLFormControlElement>(node()))
3257         return downcast<HTMLFormControlElement>(*node()).isShowingValidationMessage();
3258     return false;
3259 }
3260
3261 String AccessibilityObject::validationMessage() const
3262 {
3263     if (is<HTMLFormControlElement>(node()))
3264         return downcast<HTMLFormControlElement>(*node()).validationMessage();
3265     return String();
3266 }
3267
3268 AccessibilityObjectInclusion AccessibilityObject::defaultObjectInclusion() const
3269 {
3270     bool useParentData = !m_isIgnoredFromParentData.isNull();
3271     
3272     if (useParentData ? m_isIgnoredFromParentData.isAXHidden : isAXHidden())
3273         return AccessibilityObjectInclusion::IgnoreObject;
3274     
3275     if (ignoredFromModalPresence())
3276         return AccessibilityObjectInclusion::IgnoreObject;
3277     
3278     if (useParentData ? m_isIgnoredFromParentData.isPresentationalChildOfAriaRole : isPresentationalChildOfAriaRole())
3279         return AccessibilityObjectInclusion::IgnoreObject;
3280     
3281     return accessibilityPlatformIncludesObject();
3282 }
3283     
3284 bool AccessibilityObject::accessibilityIsIgnored() const
3285 {
3286     AXComputedObjectAttributeCache* attributeCache = nullptr;
3287     AXObjectCache* cache = axObjectCache();
3288     if (cache)
3289         attributeCache = cache->computedObjectAttributeCache();
3290     
3291     if (attributeCache) {
3292         AccessibilityObjectInclusion ignored = attributeCache->getIgnored(objectID());
3293         switch (ignored) {
3294         case AccessibilityObjectInclusion::IgnoreObject:
3295             return true;
3296         case AccessibilityObjectInclusion::IncludeObject:
3297             return false;
3298         case AccessibilityObjectInclusion::DefaultBehavior:
3299             break;
3300         }
3301     }
3302
3303     bool result = computeAccessibilityIsIgnored();
3304
3305     // In case computing axIsIgnored disables attribute caching, we should refetch the object to see if it exists.
3306     if (cache && (attributeCache = cache->computedObjectAttributeCache()))
3307         attributeCache->setIgnored(objectID(), result ? AccessibilityObjectInclusion::IgnoreObject : AccessibilityObjectInclusion::IncludeObject);
3308
3309     return result;
3310 }
3311
3312 void AccessibilityObject::elementsFromAttribute(Vector<Element*>& elements, const QualifiedName& attribute) const
3313 {
3314     Node* node = this->node();
3315     if (!node || !node->isElementNode())