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