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