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