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