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