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