2b1919a6b5c3505d3038d2b7693a72b2dd8e272e
[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() ? toAccessibilityTable(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     if (Document* document = this->document()) {
849         HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::AccessibilityHitTest);
850         HitTestResult hitTestResult(clickPoint());
851         document->renderView()->hitTest(request, hitTestResult);
852         if (hitTestResult.innerNode()) {
853             Node* innerNode = hitTestResult.innerNode()->deprecatedShadowAncestorNode();
854             if (is<Element>(*innerNode))
855                 hitTestElement = downcast<Element>(innerNode);
856         }
857     }
858     
859     
860     // Prefer the actionElement instead of this node, if the actionElement is inside this node.
861     Element* pressElement = this->element();
862     if (!pressElement || actionElem->isDescendantOf(pressElement))
863         pressElement = actionElem;
864     
865     // Prefer the hit test element, if it is inside the target element.
866     if (hitTestElement && hitTestElement->isDescendantOf(pressElement))
867         pressElement = hitTestElement;
868     
869     UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
870     pressElement->accessKeyAction(true);
871     return true;
872 }
873
874 Frame* AccessibilityObject::frame() const
875 {
876     Node* node = this->node();
877     if (!node)
878         return nullptr;
879     
880     return node->document().frame();
881 }
882
883 MainFrame* AccessibilityObject::mainFrame() const
884 {
885     Document* document = topDocument();
886     if (!document)
887         return nullptr;
888     
889     Frame* frame = document->frame();
890     if (!frame)
891         return nullptr;
892     
893     return &frame->mainFrame();
894 }
895
896 Document* AccessibilityObject::topDocument() const
897 {
898     if (!document())
899         return nullptr;
900     return &document()->topDocument();
901 }
902
903 String AccessibilityObject::language() const
904 {
905     const AtomicString& lang = getAttribute(langAttr);
906     if (!lang.isEmpty())
907         return lang;
908
909     AccessibilityObject* parent = parentObject();
910     
911     // as a last resort, fall back to the content language specified in the meta tag
912     if (!parent) {
913         Document* doc = document();
914         if (doc)
915             return doc->contentLanguage();
916         return nullAtom;
917     }
918     
919     return parent->language();
920 }
921     
922 VisiblePositionRange AccessibilityObject::visiblePositionRangeForUnorderedPositions(const VisiblePosition& visiblePos1, const VisiblePosition& visiblePos2) const
923 {
924     if (visiblePos1.isNull() || visiblePos2.isNull())
925         return VisiblePositionRange();
926
927     // If there's no common tree scope between positions, return early.
928     if (!commonTreeScope(visiblePos1.deepEquivalent().deprecatedNode(), visiblePos2.deepEquivalent().deprecatedNode()))
929         return VisiblePositionRange();
930     
931     VisiblePosition startPos;
932     VisiblePosition endPos;
933     bool alreadyInOrder;
934
935     // upstream is ordered before downstream for the same position
936     if (visiblePos1 == visiblePos2 && visiblePos2.affinity() == UPSTREAM)
937         alreadyInOrder = false;
938
939     // use selection order to see if the positions are in order
940     else
941         alreadyInOrder = VisibleSelection(visiblePos1, visiblePos2).isBaseFirst();
942
943     if (alreadyInOrder) {
944         startPos = visiblePos1;
945         endPos = visiblePos2;
946     } else {
947         startPos = visiblePos2;
948         endPos = visiblePos1;
949     }
950
951     return VisiblePositionRange(startPos, endPos);
952 }
953
954 VisiblePositionRange AccessibilityObject::positionOfLeftWord(const VisiblePosition& visiblePos) const
955 {
956     VisiblePosition startPosition = startOfWord(visiblePos, LeftWordIfOnBoundary);
957     VisiblePosition endPosition = endOfWord(startPosition);
958     return VisiblePositionRange(startPosition, endPosition);
959 }
960
961 VisiblePositionRange AccessibilityObject::positionOfRightWord(const VisiblePosition& visiblePos) const
962 {
963     VisiblePosition startPosition = startOfWord(visiblePos, RightWordIfOnBoundary);
964     VisiblePosition endPosition = endOfWord(startPosition);
965     return VisiblePositionRange(startPosition, endPosition);
966 }
967
968 static VisiblePosition updateAXLineStartForVisiblePosition(const VisiblePosition& visiblePosition)
969 {
970     // A line in the accessibility sense should include floating objects, such as aligned image, as part of a line.
971     // So let's update the position to include that.
972     VisiblePosition tempPosition;
973     VisiblePosition startPosition = visiblePosition;
974     while (true) {
975         tempPosition = startPosition.previous();
976         if (tempPosition.isNull())
977             break;
978         Position p = tempPosition.deepEquivalent();
979         RenderObject* renderer = p.deprecatedNode()->renderer();
980         if (!renderer || (renderer->isRenderBlock() && !p.deprecatedEditingOffset()))
981             break;
982         if (!RenderedPosition(tempPosition).isNull())
983             break;
984         startPosition = tempPosition;
985     }
986
987     return startPosition;
988 }
989
990 VisiblePositionRange AccessibilityObject::leftLineVisiblePositionRange(const VisiblePosition& visiblePos) const
991 {
992     if (visiblePos.isNull())
993         return VisiblePositionRange();
994
995     // make a caret selection for the position before marker position (to make sure
996     // we move off of a line start)
997     VisiblePosition prevVisiblePos = visiblePos.previous();
998     if (prevVisiblePos.isNull())
999         return VisiblePositionRange();
1000
1001     VisiblePosition startPosition = startOfLine(prevVisiblePos);
1002
1003     // keep searching for a valid line start position.  Unless the VisiblePosition is at the very beginning, there should
1004     // always be a valid line range.  However, startOfLine will return null for position next to a floating object,
1005     // since floating object doesn't really belong to any line.
1006     // This check will reposition the marker before the floating object, to ensure we get a line start.
1007     if (startPosition.isNull()) {
1008         while (startPosition.isNull() && prevVisiblePos.isNotNull()) {
1009             prevVisiblePos = prevVisiblePos.previous();
1010             startPosition = startOfLine(prevVisiblePos);
1011         }
1012     } else
1013         startPosition = updateAXLineStartForVisiblePosition(startPosition);
1014
1015     VisiblePosition endPosition = endOfLine(prevVisiblePos);
1016     return VisiblePositionRange(startPosition, endPosition);
1017 }
1018
1019 VisiblePositionRange AccessibilityObject::rightLineVisiblePositionRange(const VisiblePosition& visiblePos) const
1020 {
1021     if (visiblePos.isNull())
1022         return VisiblePositionRange();
1023
1024     // make sure we move off of a line end
1025     VisiblePosition nextVisiblePos = visiblePos.next();
1026     if (nextVisiblePos.isNull())
1027         return VisiblePositionRange();
1028
1029     VisiblePosition startPosition = startOfLine(nextVisiblePos);
1030
1031     // fetch for a valid line start position
1032     if (startPosition.isNull()) {
1033         startPosition = visiblePos;
1034         nextVisiblePos = nextVisiblePos.next();
1035     } else
1036         startPosition = updateAXLineStartForVisiblePosition(startPosition);
1037
1038     VisiblePosition endPosition = endOfLine(nextVisiblePos);
1039
1040     // as long as the position hasn't reached the end of the doc,  keep searching for a valid line end position
1041     // Unless the VisiblePosition is at the very end, there should always be a valid line range.  However, endOfLine will
1042     // return null for position by a floating object, since floating object doesn't really belong to any line.
1043     // This check will reposition the marker after the floating object, to ensure we get a line end.
1044     while (endPosition.isNull() && nextVisiblePos.isNotNull()) {
1045         nextVisiblePos = nextVisiblePos.next();
1046         endPosition = endOfLine(nextVisiblePos);
1047     }
1048
1049     return VisiblePositionRange(startPosition, endPosition);
1050 }
1051
1052 VisiblePositionRange AccessibilityObject::sentenceForPosition(const VisiblePosition& visiblePos) const
1053 {
1054     // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
1055     // Related? <rdar://problem/3927736> Text selection broken in 8A336
1056     VisiblePosition startPosition = startOfSentence(visiblePos);
1057     VisiblePosition endPosition = endOfSentence(startPosition);
1058     return VisiblePositionRange(startPosition, endPosition);
1059 }
1060
1061 VisiblePositionRange AccessibilityObject::paragraphForPosition(const VisiblePosition& visiblePos) const
1062 {
1063     VisiblePosition startPosition = startOfParagraph(visiblePos);
1064     VisiblePosition endPosition = endOfParagraph(startPosition);
1065     return VisiblePositionRange(startPosition, endPosition);
1066 }
1067
1068 static VisiblePosition startOfStyleRange(const VisiblePosition& visiblePos)
1069 {
1070     RenderObject* renderer = visiblePos.deepEquivalent().deprecatedNode()->renderer();
1071     RenderObject* startRenderer = renderer;
1072     RenderStyle* style = &renderer->style();
1073
1074     // traverse backward by renderer to look for style change
1075     for (RenderObject* r = renderer->previousInPreOrder(); r; r = r->previousInPreOrder()) {
1076         // skip non-leaf nodes
1077         if (r->firstChildSlow())
1078             continue;
1079
1080         // stop at style change
1081         if (&r->style() != style)
1082             break;
1083
1084         // remember match
1085         startRenderer = r;
1086     }
1087
1088     return firstPositionInOrBeforeNode(startRenderer->node());
1089 }
1090
1091 static VisiblePosition endOfStyleRange(const VisiblePosition& visiblePos)
1092 {
1093     RenderObject* renderer = visiblePos.deepEquivalent().deprecatedNode()->renderer();
1094     RenderObject* endRenderer = renderer;
1095     const RenderStyle& style = renderer->style();
1096
1097     // traverse forward by renderer to look for style change
1098     for (RenderObject* r = renderer->nextInPreOrder(); r; r = r->nextInPreOrder()) {
1099         // skip non-leaf nodes
1100         if (r->firstChildSlow())
1101             continue;
1102
1103         // stop at style change
1104         if (&r->style() != &style)
1105             break;
1106
1107         // remember match
1108         endRenderer = r;
1109     }
1110
1111     return lastPositionInOrAfterNode(endRenderer->node());
1112 }
1113
1114 VisiblePositionRange AccessibilityObject::styleRangeForPosition(const VisiblePosition& visiblePos) const
1115 {
1116     if (visiblePos.isNull())
1117         return VisiblePositionRange();
1118
1119     return VisiblePositionRange(startOfStyleRange(visiblePos), endOfStyleRange(visiblePos));
1120 }
1121
1122 // NOTE: Consider providing this utility method as AX API
1123 VisiblePositionRange AccessibilityObject::visiblePositionRangeForRange(const PlainTextRange& range) const
1124 {
1125     unsigned textLength = getLengthForTextRange();
1126     if (range.start + range.length > textLength)
1127         return VisiblePositionRange();
1128
1129     VisiblePosition startPosition = visiblePositionForIndex(range.start);
1130     startPosition.setAffinity(DOWNSTREAM);
1131     VisiblePosition endPosition = visiblePositionForIndex(range.start + range.length);
1132     return VisiblePositionRange(startPosition, endPosition);
1133 }
1134
1135 VisiblePositionRange AccessibilityObject::lineRangeForPosition(const VisiblePosition& visiblePosition) const
1136 {
1137     VisiblePosition startPosition = startOfLine(visiblePosition);
1138     VisiblePosition endPosition = endOfLine(visiblePosition);
1139     return VisiblePositionRange(startPosition, endPosition);
1140 }
1141
1142 static bool replacedNodeNeedsCharacter(Node* replacedNode)
1143 {
1144     // we should always be given a rendered node and a replaced node, but be safe
1145     // replaced nodes are either attachments (widgets) or images
1146     if (!replacedNode || !isRendererReplacedElement(replacedNode->renderer()) || replacedNode->isTextNode())
1147         return false;
1148
1149     // create an AX object, but skip it if it is not supposed to be seen
1150     AccessibilityObject* object = replacedNode->renderer()->document().axObjectCache()->getOrCreate(replacedNode);
1151     if (object->accessibilityIsIgnored())
1152         return false;
1153
1154     return true;
1155 }
1156
1157 // Finds a RenderListItem parent give a node.
1158 static RenderListItem* renderListItemContainerForNode(Node* node)
1159 {
1160     for (; node; node = node->parentNode()) {
1161         RenderBoxModelObject* renderer = node->renderBoxModelObject();
1162         if (renderer && renderer->isListItem())
1163             return toRenderListItem(renderer);
1164     }
1165     return nullptr;
1166 }
1167     
1168 // Returns the text associated with a list marker if this node is contained within a list item.
1169 String AccessibilityObject::listMarkerTextForNodeAndPosition(Node* node, const VisiblePosition& visiblePositionStart) const
1170 {
1171     // If the range does not contain the start of the line, the list marker text should not be included.
1172     if (!isStartOfLine(visiblePositionStart))
1173         return String();
1174
1175     RenderListItem* listItem = renderListItemContainerForNode(node);
1176     if (!listItem)
1177         return String();
1178         
1179     // If this is in a list item, we need to manually add the text for the list marker 
1180     // because a RenderListMarker does not have a Node equivalent and thus does not appear
1181     // when iterating text.
1182     return listItem->markerTextWithSuffix();
1183 }
1184
1185 String AccessibilityObject::stringForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const
1186 {
1187     if (visiblePositionRange.isNull())
1188         return String();
1189
1190     StringBuilder builder;
1191     RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end);
1192     for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
1193         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
1194         if (it.text().length()) {
1195             // Add a textual representation for list marker text.
1196             builder.append(listMarkerTextForNodeAndPosition(it.node(), visiblePositionRange.start));
1197             it.appendTextToStringBuilder(builder);
1198         } else {
1199             // locate the node and starting offset for this replaced range
1200             Node* node = it.range()->startContainer();
1201             ASSERT(node == it.range()->endContainer());
1202             int offset = it.range()->startOffset();
1203             if (replacedNodeNeedsCharacter(node->traverseToChildAt(offset)))
1204                 builder.append(objectReplacementCharacter);
1205         }
1206     }
1207
1208     return builder.toString();
1209 }
1210
1211 int AccessibilityObject::lengthForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const
1212 {
1213     // FIXME: Multi-byte support
1214     if (visiblePositionRange.isNull())
1215         return -1;
1216     
1217     int length = 0;
1218     RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end);
1219     for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
1220         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
1221         if (it.text().length())
1222             length += it.text().length();
1223         else {
1224             // locate the node and starting offset for this replaced range
1225             int exception = 0;
1226             Node* node = it.range()->startContainer(exception);
1227             ASSERT(node == it.range()->endContainer(exception));
1228             int offset = it.range()->startOffset(exception);
1229
1230             if (replacedNodeNeedsCharacter(node->traverseToChildAt(offset)))
1231                 length++;
1232         }
1233     }
1234     
1235     return length;
1236 }
1237
1238 VisiblePosition AccessibilityObject::visiblePositionForBounds(const IntRect& rect, AccessibilityVisiblePositionForBounds visiblePositionForBounds) const
1239 {
1240     if (rect.isEmpty())
1241         return VisiblePosition();
1242     
1243     MainFrame* mainFrame = this->mainFrame();
1244     if (!mainFrame)
1245         return VisiblePosition();
1246     
1247     // FIXME: Add support for right-to-left languages.
1248     IntPoint corner = (visiblePositionForBounds == FirstVisiblePositionForBounds) ? rect.minXMinYCorner() : rect.maxXMaxYCorner();
1249     VisiblePosition position = mainFrame->visiblePositionForPoint(corner);
1250     
1251     if (rect.contains(position.absoluteCaretBounds().center()))
1252         return position;
1253     
1254     // If the initial position is located outside the bounds adjust it incrementally as needed.
1255     VisiblePosition nextPosition = position.next();
1256     VisiblePosition previousPosition = position.previous();
1257     while (nextPosition.isNotNull() || previousPosition.isNotNull()) {
1258         if (rect.contains(nextPosition.absoluteCaretBounds().center()))
1259             return nextPosition;
1260         if (rect.contains(previousPosition.absoluteCaretBounds().center()))
1261             return previousPosition;
1262         
1263         nextPosition = nextPosition.next();
1264         previousPosition = previousPosition.previous();
1265     }
1266     
1267     return VisiblePosition();
1268 }
1269
1270 VisiblePosition AccessibilityObject::nextWordEnd(const VisiblePosition& visiblePos) const
1271 {
1272     if (visiblePos.isNull())
1273         return VisiblePosition();
1274
1275     // make sure we move off of a word end
1276     VisiblePosition nextVisiblePos = visiblePos.next();
1277     if (nextVisiblePos.isNull())
1278         return VisiblePosition();
1279
1280     return endOfWord(nextVisiblePos, LeftWordIfOnBoundary);
1281 }
1282
1283 VisiblePosition AccessibilityObject::previousWordStart(const VisiblePosition& visiblePos) const
1284 {
1285     if (visiblePos.isNull())
1286         return VisiblePosition();
1287
1288     // make sure we move off of a word start
1289     VisiblePosition prevVisiblePos = visiblePos.previous();
1290     if (prevVisiblePos.isNull())
1291         return VisiblePosition();
1292
1293     return startOfWord(prevVisiblePos, RightWordIfOnBoundary);
1294 }
1295
1296 VisiblePosition AccessibilityObject::nextLineEndPosition(const VisiblePosition& visiblePos) const
1297 {
1298     if (visiblePos.isNull())
1299         return VisiblePosition();
1300
1301     // to make sure we move off of a line end
1302     VisiblePosition nextVisiblePos = visiblePos.next();
1303     if (nextVisiblePos.isNull())
1304         return VisiblePosition();
1305
1306     VisiblePosition endPosition = endOfLine(nextVisiblePos);
1307
1308     // as long as the position hasn't reached the end of the doc,  keep searching for a valid line end position
1309     // 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.
1310     while (endPosition.isNull() && nextVisiblePos.isNotNull()) {
1311         nextVisiblePos = nextVisiblePos.next();
1312         endPosition = endOfLine(nextVisiblePos);
1313     }
1314
1315     return endPosition;
1316 }
1317
1318 VisiblePosition AccessibilityObject::previousLineStartPosition(const VisiblePosition& visiblePos) const
1319 {
1320     if (visiblePos.isNull())
1321         return VisiblePosition();
1322
1323     // make sure we move off of a line start
1324     VisiblePosition prevVisiblePos = visiblePos.previous();
1325     if (prevVisiblePos.isNull())
1326         return VisiblePosition();
1327
1328     VisiblePosition startPosition = startOfLine(prevVisiblePos);
1329
1330     // as long as the position hasn't reached the beginning of the doc,  keep searching for a valid line start position
1331     // 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.
1332     if (startPosition.isNull()) {
1333         while (startPosition.isNull() && prevVisiblePos.isNotNull()) {
1334             prevVisiblePos = prevVisiblePos.previous();
1335             startPosition = startOfLine(prevVisiblePos);
1336         }
1337     } else
1338         startPosition = updateAXLineStartForVisiblePosition(startPosition);
1339
1340     return startPosition;
1341 }
1342
1343 VisiblePosition AccessibilityObject::nextSentenceEndPosition(const VisiblePosition& visiblePos) const
1344 {
1345     // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
1346     // Related? <rdar://problem/3927736> Text selection broken in 8A336
1347     if (visiblePos.isNull())
1348         return VisiblePosition();
1349
1350     // make sure we move off of a sentence end
1351     VisiblePosition nextVisiblePos = visiblePos.next();
1352     if (nextVisiblePos.isNull())
1353         return VisiblePosition();
1354
1355     // an empty line is considered a sentence. If it's skipped, then the sentence parser will not
1356     // see this empty line.  Instead, return the end position of the empty line.
1357     VisiblePosition endPosition;
1358     
1359     String lineString = plainText(makeRange(startOfLine(nextVisiblePos), endOfLine(nextVisiblePos)).get());
1360     if (lineString.isEmpty())
1361         endPosition = nextVisiblePos;
1362     else
1363         endPosition = endOfSentence(nextVisiblePos);
1364
1365     return endPosition;
1366 }
1367
1368 VisiblePosition AccessibilityObject::previousSentenceStartPosition(const VisiblePosition& visiblePos) const
1369 {
1370     // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
1371     // Related? <rdar://problem/3927736> Text selection broken in 8A336
1372     if (visiblePos.isNull())
1373         return VisiblePosition();
1374
1375     // make sure we move off of a sentence start
1376     VisiblePosition previousVisiblePos = visiblePos.previous();
1377     if (previousVisiblePos.isNull())
1378         return VisiblePosition();
1379
1380     // treat empty line as a separate sentence.
1381     VisiblePosition startPosition;
1382     
1383     String lineString = plainText(makeRange(startOfLine(previousVisiblePos), endOfLine(previousVisiblePos)).get());
1384     if (lineString.isEmpty())
1385         startPosition = previousVisiblePos;
1386     else
1387         startPosition = startOfSentence(previousVisiblePos);
1388
1389     return startPosition;
1390 }
1391
1392 VisiblePosition AccessibilityObject::nextParagraphEndPosition(const VisiblePosition& visiblePos) const
1393 {
1394     if (visiblePos.isNull())
1395         return VisiblePosition();
1396
1397     // make sure we move off of a paragraph end
1398     VisiblePosition nextPos = visiblePos.next();
1399     if (nextPos.isNull())
1400         return VisiblePosition();
1401
1402     return endOfParagraph(nextPos);
1403 }
1404
1405 VisiblePosition AccessibilityObject::previousParagraphStartPosition(const VisiblePosition& visiblePos) const
1406 {
1407     if (visiblePos.isNull())
1408         return VisiblePosition();
1409
1410     // make sure we move off of a paragraph start
1411     VisiblePosition previousPos = visiblePos.previous();
1412     if (previousPos.isNull())
1413         return VisiblePosition();
1414
1415     return startOfParagraph(previousPos);
1416 }
1417
1418 AccessibilityObject* AccessibilityObject::accessibilityObjectForPosition(const VisiblePosition& visiblePos) const
1419 {
1420     if (visiblePos.isNull())
1421         return nullptr;
1422
1423     RenderObject* obj = visiblePos.deepEquivalent().deprecatedNode()->renderer();
1424     if (!obj)
1425         return nullptr;
1426
1427     return obj->document().axObjectCache()->getOrCreate(obj);
1428 }
1429     
1430 // If you call node->hasEditableStyle() since that will return true if an ancestor is editable.
1431 // This only returns true if this is the element that actually has the contentEditable attribute set.
1432 bool AccessibilityObject::hasContentEditableAttributeSet() const
1433 {
1434     return contentEditableAttributeIsEnabled(element());
1435 }
1436
1437 bool AccessibilityObject::contentEditableAttributeIsEnabled(Element* element)
1438 {
1439     if (!element)
1440         return false;
1441     
1442     const AtomicString& contentEditableValue = element->fastGetAttribute(contenteditableAttr);
1443     if (contentEditableValue.isNull())
1444         return false;
1445     
1446     // Both "true" (case-insensitive) and the empty string count as true.
1447     return contentEditableValue.isEmpty() || equalIgnoringCase(contentEditableValue, "true");
1448 }
1449     
1450 #if HAVE(ACCESSIBILITY)
1451 int AccessibilityObject::lineForPosition(const VisiblePosition& visiblePos) const
1452 {
1453     if (visiblePos.isNull() || !node())
1454         return -1;
1455
1456     // If the position is not in the same editable region as this AX object, return -1.
1457     Node* containerNode = visiblePos.deepEquivalent().containerNode();
1458     if (!containerNode->containsIncludingShadowDOM(node()) && !node()->containsIncludingShadowDOM(containerNode))
1459         return -1;
1460
1461     int lineCount = -1;
1462     VisiblePosition currentVisiblePos = visiblePos;
1463     VisiblePosition savedVisiblePos;
1464
1465     // move up until we get to the top
1466     // FIXME: This only takes us to the top of the rootEditableElement, not the top of the
1467     // top document.
1468     do {
1469         savedVisiblePos = currentVisiblePos;
1470         VisiblePosition prevVisiblePos = previousLinePosition(currentVisiblePos, 0, HasEditableAXRole);
1471         currentVisiblePos = prevVisiblePos;
1472         ++lineCount;
1473     }  while (currentVisiblePos.isNotNull() && !(inSameLine(currentVisiblePos, savedVisiblePos)));
1474
1475     return lineCount;
1476 }
1477 #endif
1478
1479 // NOTE: Consider providing this utility method as AX API
1480 PlainTextRange AccessibilityObject::plainTextRangeForVisiblePositionRange(const VisiblePositionRange& positionRange) const
1481 {
1482     int index1 = index(positionRange.start);
1483     int index2 = index(positionRange.end);
1484     if (index1 < 0 || index2 < 0 || index1 > index2)
1485         return PlainTextRange();
1486
1487     return PlainTextRange(index1, index2 - index1);
1488 }
1489
1490 // The composed character range in the text associated with this accessibility object that
1491 // is specified by the given screen coordinates. This parameterized attribute returns the
1492 // complete range of characters (including surrogate pairs of multi-byte glyphs) at the given
1493 // screen coordinates.
1494 // NOTE: This varies from AppKit when the point is below the last line. AppKit returns an
1495 // an error in that case. We return textControl->text().length(), 1. Does this matter?
1496 PlainTextRange AccessibilityObject::doAXRangeForPosition(const IntPoint& point) const
1497 {
1498     int i = index(visiblePositionForPoint(point));
1499     if (i < 0)
1500         return PlainTextRange();
1501
1502     return PlainTextRange(i, 1);
1503 }
1504
1505 // Given a character index, the range of text associated with this accessibility object
1506 // over which the style in effect at that character index applies.
1507 PlainTextRange AccessibilityObject::doAXStyleRangeForIndex(unsigned index) const
1508 {
1509     VisiblePositionRange range = styleRangeForPosition(visiblePositionForIndex(index, false));
1510     return plainTextRangeForVisiblePositionRange(range);
1511 }
1512
1513 // Given an indexed character, the line number of the text associated with this accessibility
1514 // object that contains the character.
1515 unsigned AccessibilityObject::doAXLineForIndex(unsigned index)
1516 {
1517     return lineForPosition(visiblePositionForIndex(index, false));
1518 }
1519
1520 #if HAVE(ACCESSIBILITY)
1521 void AccessibilityObject::updateBackingStore()
1522 {
1523     // Updating the layout may delete this object.
1524     RefPtr<AccessibilityObject> protector(this);
1525
1526     if (Document* document = this->document()) {
1527         if (!document->view()->isInLayout())
1528             document->updateLayoutIgnorePendingStylesheets();
1529     }
1530     
1531     updateChildrenIfNecessary();
1532 }
1533 #endif
1534     
1535 ScrollView* AccessibilityObject::scrollViewAncestor() const
1536 {
1537     for (const AccessibilityObject* scrollParent = this; scrollParent; scrollParent = scrollParent->parentObject()) {
1538         if (scrollParent->isAccessibilityScrollView())
1539             return toAccessibilityScrollView(scrollParent)->scrollView();
1540     }
1541     
1542     return nullptr;
1543 }
1544     
1545 Document* AccessibilityObject::document() const
1546 {
1547     FrameView* frameView = documentFrameView();
1548     if (!frameView)
1549         return nullptr;
1550     
1551     return frameView->frame().document();
1552 }
1553     
1554 Page* AccessibilityObject::page() const
1555 {
1556     Document* document = this->document();
1557     if (!document)
1558         return nullptr;
1559     return document->page();
1560 }
1561
1562 FrameView* AccessibilityObject::documentFrameView() const 
1563
1564     const AccessibilityObject* object = this;
1565     while (object && !object->isAccessibilityRenderObject()) 
1566         object = object->parentObject();
1567         
1568     if (!object)
1569         return nullptr;
1570
1571     return object->documentFrameView();
1572 }
1573
1574 #if HAVE(ACCESSIBILITY)
1575 const AccessibilityObject::AccessibilityChildrenVector& AccessibilityObject::children(bool updateChildrenIfNeeded)
1576 {
1577     if (updateChildrenIfNeeded)
1578         updateChildrenIfNecessary();
1579
1580     return m_children;
1581 }
1582 #endif
1583
1584 void AccessibilityObject::updateChildrenIfNecessary()
1585 {
1586     if (!hasChildren()) {
1587         // Enable the cache in case we end up adding a lot of children, we don't want to recompute axIsIgnored each time.
1588         AXAttributeCacheEnabler enableCache(axObjectCache());
1589         addChildren();
1590     }
1591 }
1592     
1593 void AccessibilityObject::clearChildren()
1594 {
1595     // Some objects have weak pointers to their parents and those associations need to be detached.
1596     for (const auto& child : m_children)
1597         child->detachFromParent();
1598     
1599     m_children.clear();
1600     m_haveChildren = false;
1601 }
1602
1603 AccessibilityObject* AccessibilityObject::anchorElementForNode(Node* node)
1604 {
1605     RenderObject* obj = node->renderer();
1606     if (!obj)
1607         return nullptr;
1608     
1609     RefPtr<AccessibilityObject> axObj = obj->document().axObjectCache()->getOrCreate(obj);
1610     Element* anchor = axObj->anchorElement();
1611     if (!anchor)
1612         return nullptr;
1613     
1614     RenderObject* anchorRenderer = anchor->renderer();
1615     if (!anchorRenderer)
1616         return nullptr;
1617     
1618     return anchorRenderer->document().axObjectCache()->getOrCreate(anchorRenderer);
1619 }
1620
1621 AccessibilityObject* AccessibilityObject::headingElementForNode(Node* node)
1622 {
1623     if (!node)
1624         return nullptr;
1625     
1626     RenderObject* renderObject = node->renderer();
1627     if (!renderObject)
1628         return nullptr;
1629     
1630     AccessibilityObject* axObject = renderObject->document().axObjectCache()->getOrCreate(renderObject);
1631     for (; axObject && axObject->roleValue() != HeadingRole; axObject = axObject->parentObject()) { }
1632     
1633     return axObject;
1634 }
1635
1636 void AccessibilityObject::ariaTreeRows(AccessibilityChildrenVector& result)
1637 {
1638     for (const auto& child : children()) {
1639         // Add tree items as the rows.
1640         if (child->roleValue() == TreeItemRole)
1641             result.append(child);
1642
1643         // Now see if this item also has rows hiding inside of it.
1644         child->ariaTreeRows(result);
1645     }
1646 }
1647     
1648 void AccessibilityObject::ariaTreeItemContent(AccessibilityChildrenVector& result)
1649 {
1650     // The ARIA tree item content are the item that are not other tree items or their containing groups.
1651     for (const auto& child : children()) {
1652         AccessibilityRole role = child->roleValue();
1653         if (role == TreeItemRole || role == GroupRole)
1654             continue;
1655         
1656         result.append(child);
1657     }
1658 }
1659
1660 void AccessibilityObject::ariaTreeItemDisclosedRows(AccessibilityChildrenVector& result)
1661 {
1662     for (const auto& obj : children()) {
1663         // Add tree items as the rows.
1664         if (obj->roleValue() == TreeItemRole)
1665             result.append(obj);
1666         // If it's not a tree item, then descend into the group to find more tree items.
1667         else 
1668             obj->ariaTreeRows(result);
1669     }    
1670 }
1671     
1672 const String AccessibilityObject::defaultLiveRegionStatusForRole(AccessibilityRole role)
1673 {
1674     switch (role) {
1675     case ApplicationAlertDialogRole:
1676     case ApplicationAlertRole:
1677         return ASCIILiteral("assertive");
1678     case ApplicationLogRole:
1679     case ApplicationStatusRole:
1680         return ASCIILiteral("polite");
1681     case ApplicationTimerRole:
1682     case ApplicationMarqueeRole:
1683         return ASCIILiteral("off");
1684     default:
1685         return nullAtom;
1686     }
1687 }
1688     
1689 #if HAVE(ACCESSIBILITY)
1690 const String& AccessibilityObject::actionVerb() const
1691 {
1692 #if !PLATFORM(IOS)
1693     // FIXME: Need to add verbs for select elements.
1694     static NeverDestroyed<const String> buttonAction(AXButtonActionVerb());
1695     static NeverDestroyed<const String> textFieldAction(AXTextFieldActionVerb());
1696     static NeverDestroyed<const String> radioButtonAction(AXRadioButtonActionVerb());
1697     static NeverDestroyed<const String> checkedCheckBoxAction(AXCheckedCheckBoxActionVerb());
1698     static NeverDestroyed<const String> uncheckedCheckBoxAction(AXUncheckedCheckBoxActionVerb());
1699     static NeverDestroyed<const String> linkAction(AXLinkActionVerb());
1700     static NeverDestroyed<const String> menuListAction(AXMenuListActionVerb());
1701     static NeverDestroyed<const String> menuListPopupAction(AXMenuListPopupActionVerb());
1702     static NeverDestroyed<const String> listItemAction(AXListItemActionVerb());
1703
1704     switch (roleValue()) {
1705     case ButtonRole:
1706     case ToggleButtonRole:
1707         return buttonAction;
1708     case TextFieldRole:
1709     case TextAreaRole:
1710         return textFieldAction;
1711     case RadioButtonRole:
1712         return radioButtonAction;
1713     case CheckBoxRole:
1714         return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction;
1715     case LinkRole:
1716     case WebCoreLinkRole:
1717         return linkAction;
1718     case PopUpButtonRole:
1719         return menuListAction;
1720     case MenuListPopupRole:
1721         return menuListPopupAction;
1722     case ListItemRole:
1723         return listItemAction;
1724     default:
1725         return nullAtom;
1726     }
1727 #else
1728     return nullAtom;
1729 #endif
1730 }
1731 #endif
1732
1733 bool AccessibilityObject::ariaIsMultiline() const
1734 {
1735     return equalIgnoringCase(getAttribute(aria_multilineAttr), "true");
1736 }
1737
1738 String AccessibilityObject::invalidStatus() const
1739 {
1740     String grammarValue = ASCIILiteral("grammar");
1741     String falseValue = ASCIILiteral("false");
1742     String spellingValue = ASCIILiteral("spelling");
1743     String trueValue = ASCIILiteral("true");
1744     String undefinedValue = ASCIILiteral("undefined");
1745
1746     // aria-invalid can return false (default), grammar, spelling, or true.
1747     String ariaInvalid = stripLeadingAndTrailingHTMLSpaces(getAttribute(aria_invalidAttr));
1748     
1749     // If "false", "undefined" [sic, string value], empty, or missing, return "false".
1750     if (ariaInvalid.isEmpty() || ariaInvalid == falseValue || ariaInvalid == undefinedValue)
1751         return falseValue;
1752     // Besides true/false/undefined, the only tokens defined by WAI-ARIA 1.0...
1753     // ...for @aria-invalid are "grammar" and "spelling".
1754     if (ariaInvalid == grammarValue)
1755         return grammarValue;
1756     if (ariaInvalid == spellingValue)
1757         return spellingValue;
1758     // Any other non empty string should be treated as "true".
1759     return trueValue;
1760 }
1761  
1762 bool AccessibilityObject::hasTagName(const QualifiedName& tagName) const
1763 {
1764     Node* node = this->node();
1765     return is<Element>(node) && downcast<Element>(*node).hasTagName(tagName);
1766 }
1767     
1768 bool AccessibilityObject::hasAttribute(const QualifiedName& attribute) const
1769 {
1770     Node* node = this->node();
1771     if (!is<Element>(node))
1772         return false;
1773     
1774     return downcast<Element>(*node).fastHasAttribute(attribute);
1775 }
1776     
1777 const AtomicString& AccessibilityObject::getAttribute(const QualifiedName& attribute) const
1778 {
1779     if (Element* element = this->element())
1780         return element->fastGetAttribute(attribute);
1781     return nullAtom;
1782 }
1783     
1784 // Lacking concrete evidence of orientation, horizontal means width > height. vertical is height > width;
1785 AccessibilityOrientation AccessibilityObject::orientation() const
1786 {
1787     LayoutRect bounds = elementRect();
1788     if (bounds.size().width() > bounds.size().height())
1789         return AccessibilityOrientationHorizontal;
1790     if (bounds.size().height() > bounds.size().width())
1791         return AccessibilityOrientationVertical;
1792
1793     // A tie goes to horizontal.
1794     return AccessibilityOrientationHorizontal;
1795 }    
1796
1797 bool AccessibilityObject::isDescendantOfObject(const AccessibilityObject* axObject) const
1798 {
1799     if (!axObject || !axObject->hasChildren())
1800         return false;
1801
1802     for (const AccessibilityObject* parent = parentObject(); parent; parent = parent->parentObject()) {
1803         if (parent == axObject)
1804             return true;
1805     }
1806     return false;
1807 }
1808
1809 bool AccessibilityObject::isAncestorOfObject(const AccessibilityObject* axObject) const
1810 {
1811     if (!axObject)
1812         return false;
1813
1814     return this == axObject || axObject->isDescendantOfObject(this);
1815 }
1816
1817 AccessibilityObject* AccessibilityObject::firstAnonymousBlockChild() const
1818 {
1819     for (AccessibilityObject* child = firstChild(); child; child = child->nextSibling()) {
1820         if (child->renderer() && child->renderer()->isAnonymousBlock())
1821             return child;
1822     }
1823     return nullptr;
1824 }
1825
1826 typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap;
1827 typedef HashMap<AccessibilityRole, String, DefaultHash<int>::Hash, WTF::UnsignedWithZeroKeyHashTraits<int>> ARIAReverseRoleMap;
1828
1829 static ARIARoleMap* gAriaRoleMap = nullptr;
1830 static ARIAReverseRoleMap* gAriaReverseRoleMap = nullptr;
1831
1832 struct RoleEntry {
1833     String ariaRole;
1834     AccessibilityRole webcoreRole;
1835 };
1836
1837 static void initializeRoleMap()
1838 {
1839     if (gAriaRoleMap)
1840         return;
1841     ASSERT(!gAriaReverseRoleMap);
1842
1843     const RoleEntry roles[] = {
1844         { "alert", ApplicationAlertRole },
1845         { "alertdialog", ApplicationAlertDialogRole },
1846         { "application", LandmarkApplicationRole },
1847         { "article", DocumentArticleRole },
1848         { "banner", LandmarkBannerRole },
1849         { "button", ButtonRole },
1850         { "checkbox", CheckBoxRole },
1851         { "complementary", LandmarkComplementaryRole },
1852         { "contentinfo", LandmarkContentInfoRole },
1853         { "dialog", ApplicationDialogRole },
1854         { "directory", DirectoryRole },
1855         { "grid", TableRole },
1856         { "gridcell", CellRole },
1857         { "columnheader", ColumnHeaderRole },
1858         { "combobox", ComboBoxRole },
1859         { "definition", DefinitionRole },
1860         { "document", DocumentRole },
1861         { "form", FormRole },
1862         { "rowheader", RowHeaderRole },
1863         { "group", GroupRole },
1864         { "heading", HeadingRole },
1865         { "img", ImageRole },
1866         { "link", WebCoreLinkRole },
1867         { "list", ListRole },        
1868         { "listitem", ListItemRole },        
1869         { "listbox", ListBoxRole },
1870         { "log", ApplicationLogRole },
1871         // "option" isn't here because it may map to different roles depending on the parent element's role
1872         { "main", LandmarkMainRole },
1873         { "marquee", ApplicationMarqueeRole },
1874         { "math", DocumentMathRole },
1875         { "menu", MenuRole },
1876         { "menubar", MenuBarRole },
1877         { "menuitem", MenuItemRole },
1878         { "menuitemcheckbox", MenuItemCheckboxRole },
1879         { "menuitemradio", MenuItemRadioRole },
1880         { "none", PresentationalRole },
1881         { "note", DocumentNoteRole },
1882         { "navigation", LandmarkNavigationRole },
1883         { "option", ListBoxOptionRole },
1884         { "presentation", PresentationalRole },
1885         { "progressbar", ProgressIndicatorRole },
1886         { "radio", RadioButtonRole },
1887         { "radiogroup", RadioGroupRole },
1888         { "region", DocumentRegionRole },
1889         { "row", RowRole },
1890         { "scrollbar", ScrollBarRole },
1891         { "search", LandmarkSearchRole },
1892         { "separator", SplitterRole },
1893         { "slider", SliderRole },
1894         { "spinbutton", SpinButtonRole },
1895         { "status", ApplicationStatusRole },
1896         { "tab", TabRole },
1897         { "tablist", TabListRole },
1898         { "tabpanel", TabPanelRole },
1899         { "text", StaticTextRole },
1900         { "textbox", TextAreaRole },
1901         { "timer", ApplicationTimerRole },
1902         { "toolbar", ToolbarRole },
1903         { "tooltip", UserInterfaceTooltipRole },
1904         { "tree", TreeRole },
1905         { "treegrid", TreeGridRole },
1906         { "treeitem", TreeItemRole }
1907     };
1908
1909     gAriaRoleMap = new ARIARoleMap;
1910     gAriaReverseRoleMap = new ARIAReverseRoleMap;
1911     size_t roleLength = WTF_ARRAY_LENGTH(roles);
1912     for (size_t i = 0; i < roleLength; ++i) {
1913         gAriaRoleMap->set(roles[i].ariaRole, roles[i].webcoreRole);
1914         gAriaReverseRoleMap->set(roles[i].webcoreRole, roles[i].ariaRole);
1915     }
1916 }
1917
1918 static ARIARoleMap& ariaRoleMap()
1919 {
1920     initializeRoleMap();
1921     return *gAriaRoleMap;
1922 }
1923
1924 static ARIAReverseRoleMap& reverseAriaRoleMap()
1925 {
1926     initializeRoleMap();
1927     return *gAriaReverseRoleMap;
1928 }
1929
1930 AccessibilityRole AccessibilityObject::ariaRoleToWebCoreRole(const String& value)
1931 {
1932     ASSERT(!value.isEmpty());
1933     
1934     Vector<String> roleVector;
1935     value.split(' ', roleVector);
1936     AccessibilityRole role = UnknownRole;
1937     for (const auto& roleName : roleVector) {
1938         role = ariaRoleMap().get(roleName);
1939         if (role)
1940             return role;
1941     }
1942     
1943     return role;
1944 }
1945
1946 String AccessibilityObject::computedRoleString() const
1947 {
1948     // FIXME: Need a few special cases that aren't in the RoleMap: option, etc. http://webkit.org/b/128296
1949     AccessibilityRole role = roleValue();
1950     if (role == HorizontalRuleRole)
1951         role = SplitterRole;
1952     
1953     return reverseAriaRoleMap().get(role);
1954 }
1955
1956 bool AccessibilityObject::hasHighlighting() const
1957 {
1958     for (Node* node = this->node(); node; node = node->parentNode()) {
1959         if (node->hasTagName(markTag))
1960             return true;
1961     }
1962     
1963     return false;
1964 }
1965
1966 Element* AccessibilityObject::element() const
1967 {
1968     Node* node = this->node();
1969     if (is<Element>(node))
1970         return downcast<Element>(node);
1971     return nullptr;
1972 }
1973
1974 const AtomicString& AccessibilityObject::placeholderValue() const
1975 {
1976     const AtomicString& placeholder = getAttribute(placeholderAttr);
1977     if (!placeholder.isEmpty())
1978         return placeholder;
1979     
1980     return nullAtom;
1981 }
1982     
1983 bool AccessibilityObject::isInsideARIALiveRegion() const
1984 {
1985     if (supportsARIALiveRegion())
1986         return true;
1987     
1988     for (AccessibilityObject* axParent = parentObject(); axParent; axParent = axParent->parentObject()) {
1989         if (axParent->supportsARIALiveRegion())
1990             return true;
1991     }
1992     
1993     return false;
1994 }
1995
1996 bool AccessibilityObject::supportsARIAAttributes() const
1997 {
1998     // This returns whether the element supports any global ARIA attributes.
1999     return supportsARIALiveRegion()
2000         || supportsARIADragging()
2001         || supportsARIADropping()
2002         || supportsARIAFlowTo()
2003         || supportsARIAOwns()
2004         || hasAttribute(aria_atomicAttr)
2005         || hasAttribute(aria_busyAttr)
2006         || hasAttribute(aria_controlsAttr)
2007         || hasAttribute(aria_describedbyAttr)
2008         || hasAttribute(aria_disabledAttr)
2009         || hasAttribute(aria_haspopupAttr)
2010         || hasAttribute(aria_invalidAttr)
2011         || hasAttribute(aria_labelAttr)
2012         || hasAttribute(aria_labelledbyAttr)
2013         || hasAttribute(aria_relevantAttr);
2014 }
2015     
2016 bool AccessibilityObject::liveRegionStatusIsEnabled(const AtomicString& liveRegionStatus)
2017 {
2018     return equalIgnoringCase(liveRegionStatus, "polite") || equalIgnoringCase(liveRegionStatus, "assertive");
2019 }
2020     
2021 bool AccessibilityObject::supportsARIALiveRegion() const
2022 {
2023     return liveRegionStatusIsEnabled(ariaLiveRegionStatus());
2024 }
2025
2026 AccessibilityObject* AccessibilityObject::elementAccessibilityHitTest(const IntPoint& point) const
2027
2028     // Send the hit test back into the sub-frame if necessary.
2029     if (isAttachment()) {
2030         Widget* widget = widgetForAttachmentView();
2031         // Normalize the point for the widget's bounds.
2032         if (widget && widget->isFrameView()) {
2033             if (AXObjectCache* cache = axObjectCache())
2034                 return cache->getOrCreate(widget)->accessibilityHitTest(IntPoint(point - widget->frameRect().location()));
2035         }
2036     }
2037     
2038     // Check if there are any mock elements that need to be handled.
2039     for (const auto& child : m_children) {
2040         if (child->isMockObject() && child->elementRect().contains(point))
2041             return child->elementAccessibilityHitTest(point);
2042     }
2043
2044     return const_cast<AccessibilityObject*>(this); 
2045 }
2046     
2047 AXObjectCache* AccessibilityObject::axObjectCache() const
2048 {
2049     Document* doc = document();
2050     if (doc)
2051         return doc->axObjectCache();
2052     return nullptr;
2053 }
2054     
2055 AccessibilityObject* AccessibilityObject::focusedUIElement() const
2056 {
2057     Document* doc = document();
2058     if (!doc)
2059         return nullptr;
2060     
2061     Page* page = doc->page();
2062     if (!page)
2063         return nullptr;
2064     
2065     return AXObjectCache::focusedUIElementForPage(page);
2066 }
2067     
2068 AccessibilitySortDirection AccessibilityObject::sortDirection() const
2069 {
2070     const AtomicString& sortAttribute = getAttribute(aria_sortAttr);
2071     if (equalIgnoringCase(sortAttribute, "ascending"))
2072         return SortDirectionAscending;
2073     if (equalIgnoringCase(sortAttribute, "descending"))
2074         return SortDirectionDescending;
2075     if (equalIgnoringCase(sortAttribute, "other"))
2076         return SortDirectionOther;
2077     
2078     return SortDirectionNone;
2079 }
2080
2081 bool AccessibilityObject::supportsRangeValue() const
2082 {
2083     return isProgressIndicator()
2084         || isSlider()
2085         || isScrollbar()
2086         || isSpinButton();
2087 }
2088     
2089 bool AccessibilityObject::supportsARIASetSize() const
2090 {
2091     return hasAttribute(aria_setsizeAttr);
2092 }
2093
2094 bool AccessibilityObject::supportsARIAPosInSet() const
2095 {
2096     return hasAttribute(aria_posinsetAttr);
2097 }
2098     
2099 int AccessibilityObject::ariaSetSize() const
2100 {
2101     return getAttribute(aria_setsizeAttr).toInt();
2102 }
2103
2104 int AccessibilityObject::ariaPosInSet() const
2105 {
2106     return getAttribute(aria_posinsetAttr).toInt();
2107 }
2108     
2109 String AccessibilityObject::identifierAttribute() const
2110 {
2111     return getAttribute(idAttr);
2112 }
2113     
2114 void AccessibilityObject::classList(Vector<String>& classList) const
2115 {
2116     Node* node = this->node();
2117     if (!is<Element>(node))
2118         return;
2119     
2120     Element* element = downcast<Element>(node);
2121     DOMTokenList& list = element->classList();
2122     unsigned length = list.length();
2123     for (unsigned k = 0; k < length; k++)
2124         classList.append(list.item(k).string());
2125 }
2126
2127     
2128 bool AccessibilityObject::supportsARIAExpanded() const
2129 {
2130     // Undefined values should not result in this attribute being exposed to ATs according to ARIA.
2131     const AtomicString& expanded = getAttribute(aria_expandedAttr);
2132     if (equalIgnoringCase(expanded, "true") || equalIgnoringCase(expanded, "false"))
2133         return true;
2134     switch (roleValue()) {
2135     case ComboBoxRole:
2136     case DisclosureTriangleRole:
2137         return true;
2138     default:
2139         return false;
2140     }
2141 }
2142     
2143 bool AccessibilityObject::isExpanded() const
2144 {
2145     if (equalIgnoringCase(getAttribute(aria_expandedAttr), "true"))
2146         return true;
2147     
2148     return false;  
2149 }
2150
2151 bool AccessibilityObject::supportsChecked() const
2152 {
2153     switch (roleValue()) {
2154     case CheckBoxRole:
2155     case MenuItemCheckboxRole:
2156     case MenuItemRadioRole:
2157     case RadioButtonRole:
2158         return true;
2159     default:
2160         return false;
2161     }
2162 }
2163
2164 AccessibilityButtonState AccessibilityObject::checkboxOrRadioValue() const
2165 {
2166     // If this is a real checkbox or radio button, AccessibilityRenderObject will handle.
2167     // If it's an ARIA checkbox or radio, the aria-checked attribute should be used.
2168
2169     const AtomicString& result = getAttribute(aria_checkedAttr);
2170     if (equalIgnoringCase(result, "true"))
2171         return ButtonStateOn;
2172     if (equalIgnoringCase(result, "mixed")) {
2173         // ARIA says that radio and menuitemradio elements must NOT expose button state mixed.
2174         AccessibilityRole ariaRole = ariaRoleAttribute();
2175         if (ariaRole == RadioButtonRole || ariaRole == MenuItemRadioRole)
2176             return ButtonStateOff;
2177         return ButtonStateMixed;
2178     }
2179     
2180     if (equalIgnoringCase(getAttribute(indeterminateAttr), "true"))
2181         return ButtonStateMixed;
2182     
2183     return ButtonStateOff;
2184 }
2185
2186 // This is a 1-dimensional scroll offset helper function that's applied
2187 // separately in the horizontal and vertical directions, because the
2188 // logic is the same. The goal is to compute the best scroll offset
2189 // in order to make an object visible within a viewport.
2190 //
2191 // In case the whole object cannot fit, you can specify a
2192 // subfocus - a smaller region within the object that should
2193 // be prioritized. If the whole object can fit, the subfocus is
2194 // ignored.
2195 //
2196 // Example: the viewport is scrolled to the right just enough
2197 // that the object is in view.
2198 //   Before:
2199 //   +----------Viewport---------+
2200 //                         +---Object---+
2201 //                         +--SubFocus--+
2202 //
2203 //   After:
2204 //          +----------Viewport---------+
2205 //                         +---Object---+
2206 //                         +--SubFocus--+
2207 //
2208 // When constraints cannot be fully satisfied, the min
2209 // (left/top) position takes precedence over the max (right/bottom).
2210 //
2211 // Note that the return value represents the ideal new scroll offset.
2212 // This may be out of range - the calling function should clip this
2213 // to the available range.
2214 static int computeBestScrollOffset(int currentScrollOffset,
2215                                    int subfocusMin, int subfocusMax,
2216                                    int objectMin, int objectMax,
2217                                    int viewportMin, int viewportMax) {
2218     int viewportSize = viewportMax - viewportMin;
2219
2220     // If the focus size is larger than the viewport size, shrink it in the
2221     // direction of subfocus.
2222     if (objectMax - objectMin > viewportSize) {
2223         // Subfocus must be within focus:
2224         subfocusMin = std::max(subfocusMin, objectMin);
2225         subfocusMax = std::min(subfocusMax, objectMax);
2226
2227         // Subfocus must be no larger than the viewport size; favor top/left.
2228         if (subfocusMax - subfocusMin > viewportSize)
2229             subfocusMax = subfocusMin + viewportSize;
2230
2231         if (subfocusMin + viewportSize > objectMax)
2232             objectMin = objectMax - viewportSize;
2233         else {
2234             objectMin = subfocusMin;
2235             objectMax = subfocusMin + viewportSize;
2236         }
2237     }
2238
2239     // Exit now if the focus is already within the viewport.
2240     if (objectMin - currentScrollOffset >= viewportMin
2241         && objectMax - currentScrollOffset <= viewportMax)
2242         return currentScrollOffset;
2243
2244     // Scroll left if we're too far to the right.
2245     if (objectMax - currentScrollOffset > viewportMax)
2246         return objectMax - viewportMax;
2247
2248     // Scroll right if we're too far to the left.
2249     if (objectMin - currentScrollOffset < viewportMin)
2250         return objectMin - viewportMin;
2251
2252     ASSERT_NOT_REACHED();
2253
2254     // This shouldn't happen.
2255     return currentScrollOffset;
2256 }
2257
2258 bool AccessibilityObject::isOnscreen() const
2259 {   
2260     bool isOnscreen = true;
2261
2262     // To figure out if the element is onscreen, we start by building of a stack starting with the
2263     // element, and then include every scrollable parent in the hierarchy.
2264     Vector<const AccessibilityObject*> objects;
2265     
2266     objects.append(this);
2267     for (AccessibilityObject* parentObject = this->parentObject(); parentObject; parentObject = parentObject->parentObject()) {
2268         if (parentObject->getScrollableAreaIfScrollable())
2269             objects.append(parentObject);
2270     }
2271
2272     // Now, go back through that chain and make sure each inner object is within the
2273     // visible bounds of the outer object.
2274     size_t levels = objects.size() - 1;
2275     
2276     for (size_t i = levels; i >= 1; i--) {
2277         const AccessibilityObject* outer = objects[i];
2278         const AccessibilityObject* inner = objects[i - 1];
2279         // FIXME: unclear if we need LegacyIOSDocumentVisibleRect.
2280         const IntRect outerRect = i < levels ? snappedIntRect(outer->boundingBoxRect()) : outer->getScrollableAreaIfScrollable()->visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
2281         const IntRect innerRect = snappedIntRect(inner->isAccessibilityScrollView() ? inner->parentObject()->boundingBoxRect() : inner->boundingBoxRect());
2282         
2283         if (!outerRect.intersects(innerRect)) {
2284             isOnscreen = false;
2285             break;
2286         }
2287     }
2288     
2289     return isOnscreen;
2290 }
2291
2292 void AccessibilityObject::scrollToMakeVisible() const
2293 {
2294     IntRect objectRect = snappedIntRect(boundingBoxRect());
2295     objectRect.setLocation(IntPoint());
2296     scrollToMakeVisibleWithSubFocus(objectRect);
2297 }
2298
2299 void AccessibilityObject::scrollToMakeVisibleWithSubFocus(const IntRect& subfocus) const
2300 {
2301     // Search up the parent chain until we find the first one that's scrollable.
2302     AccessibilityObject* scrollParent = parentObject();
2303     ScrollableArea* scrollableArea;
2304     for (scrollableArea = nullptr;
2305          scrollParent && !(scrollableArea = scrollParent->getScrollableAreaIfScrollable());
2306          scrollParent = scrollParent->parentObject()) { }
2307     if (!scrollableArea)
2308         return;
2309
2310     LayoutRect objectRect = boundingBoxRect();
2311     IntPoint scrollPosition = scrollableArea->scrollPosition();
2312     // FIXME: unclear if we need LegacyIOSDocumentVisibleRect.
2313     IntRect scrollVisibleRect = scrollableArea->visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
2314
2315     int desiredX = computeBestScrollOffset(
2316         scrollPosition.x(),
2317         objectRect.x() + subfocus.x(), objectRect.x() + subfocus.maxX(),
2318         objectRect.x(), objectRect.maxX(),
2319         0, scrollVisibleRect.width());
2320     int desiredY = computeBestScrollOffset(
2321         scrollPosition.y(),
2322         objectRect.y() + subfocus.y(), objectRect.y() + subfocus.maxY(),
2323         objectRect.y(), objectRect.maxY(),
2324         0, scrollVisibleRect.height());
2325
2326     scrollParent->scrollTo(IntPoint(desiredX, desiredY));
2327
2328     // Recursively make sure the scroll parent itself is visible.
2329     if (scrollParent->parentObject())
2330         scrollParent->scrollToMakeVisible();
2331 }
2332
2333 void AccessibilityObject::scrollToGlobalPoint(const IntPoint& globalPoint) const
2334 {
2335     // Search up the parent chain and create a vector of all scrollable parent objects
2336     // and ending with this object itself.
2337     Vector<const AccessibilityObject*> objects;
2338
2339     objects.append(this);
2340     for (AccessibilityObject* parentObject = this->parentObject(); parentObject; parentObject = parentObject->parentObject()) {
2341         if (parentObject->getScrollableAreaIfScrollable())
2342             objects.append(parentObject);
2343     }
2344
2345     objects.reverse();
2346
2347     // Start with the outermost scrollable (the main window) and try to scroll the
2348     // next innermost object to the given point.
2349     int offsetX = 0, offsetY = 0;
2350     IntPoint point = globalPoint;
2351     size_t levels = objects.size() - 1;
2352     for (size_t i = 0; i < levels; i++) {
2353         const AccessibilityObject* outer = objects[i];
2354         const AccessibilityObject* inner = objects[i + 1];
2355
2356         ScrollableArea* scrollableArea = outer->getScrollableAreaIfScrollable();
2357
2358         LayoutRect innerRect = inner->isAccessibilityScrollView() ? inner->parentObject()->boundingBoxRect() : inner->boundingBoxRect();
2359         LayoutRect objectRect = innerRect;
2360         IntPoint scrollPosition = scrollableArea->scrollPosition();
2361
2362         // Convert the object rect into local coordinates.
2363         objectRect.move(offsetX, offsetY);
2364         if (!outer->isAccessibilityScrollView())
2365             objectRect.move(scrollPosition.x(), scrollPosition.y());
2366
2367         int desiredX = computeBestScrollOffset(
2368             0,
2369             objectRect.x(), objectRect.maxX(),
2370             objectRect.x(), objectRect.maxX(),
2371             point.x(), point.x());
2372         int desiredY = computeBestScrollOffset(
2373             0,
2374             objectRect.y(), objectRect.maxY(),
2375             objectRect.y(), objectRect.maxY(),
2376             point.y(), point.y());
2377         outer->scrollTo(IntPoint(desiredX, desiredY));
2378
2379         if (outer->isAccessibilityScrollView() && !inner->isAccessibilityScrollView()) {
2380             // If outer object we just scrolled is a scroll view (main window or iframe) but the
2381             // inner object is not, keep track of the coordinate transformation to apply to
2382             // future nested calculations.
2383             scrollPosition = scrollableArea->scrollPosition();
2384             offsetX -= (scrollPosition.x() + point.x());
2385             offsetY -= (scrollPosition.y() + point.y());
2386             point.move(scrollPosition.x() - innerRect.x(),
2387                        scrollPosition.y() - innerRect.y());
2388         } else if (inner->isAccessibilityScrollView()) {
2389             // Otherwise, if the inner object is a scroll view, reset the coordinate transformation.
2390             offsetX = 0;
2391             offsetY = 0;
2392         }
2393     }
2394 }
2395
2396 bool AccessibilityObject::lastKnownIsIgnoredValue()
2397 {
2398     if (m_lastKnownIsIgnoredValue == DefaultBehavior)
2399         m_lastKnownIsIgnoredValue = accessibilityIsIgnored() ? IgnoreObject : IncludeObject;
2400
2401     return m_lastKnownIsIgnoredValue == IgnoreObject;
2402 }
2403
2404 void AccessibilityObject::setLastKnownIsIgnoredValue(bool isIgnored)
2405 {
2406     m_lastKnownIsIgnoredValue = isIgnored ? IgnoreObject : IncludeObject;
2407 }
2408
2409 void AccessibilityObject::notifyIfIgnoredValueChanged()
2410 {
2411     bool isIgnored = accessibilityIsIgnored();
2412     if (lastKnownIsIgnoredValue() != isIgnored) {
2413         if (AXObjectCache* cache = axObjectCache())
2414             cache->childrenChanged(parentObject());
2415         setLastKnownIsIgnoredValue(isIgnored);
2416     }
2417 }
2418
2419 bool AccessibilityObject::ariaPressedIsPresent() const
2420 {
2421     return !getAttribute(aria_pressedAttr).isEmpty();
2422 }
2423
2424 TextIteratorBehavior AccessibilityObject::textIteratorBehaviorForTextRange() const
2425 {
2426     TextIteratorBehavior behavior = TextIteratorIgnoresStyleVisibility;
2427     
2428 #if PLATFORM(GTK) || PLATFORM(EFL)
2429     // We need to emit replaced elements for GTK, and present
2430     // them with the 'object replacement character' (0xFFFC).
2431     behavior = static_cast<TextIteratorBehavior>(behavior | TextIteratorEmitsObjectReplacementCharacters);
2432 #endif
2433     
2434     return behavior;
2435 }
2436     
2437 AccessibilityRole AccessibilityObject::buttonRoleType() const
2438 {
2439     // If aria-pressed is present, then it should be exposed as a toggle button.
2440     // http://www.w3.org/TR/wai-aria/states_and_properties#aria-pressed
2441     if (ariaPressedIsPresent())
2442         return ToggleButtonRole;
2443     if (ariaHasPopup())
2444         return PopUpButtonRole;
2445     // We don't contemplate RadioButtonRole, as it depends on the input
2446     // type.
2447
2448     return ButtonRole;
2449 }
2450
2451 bool AccessibilityObject::isButton() const
2452 {
2453     AccessibilityRole role = roleValue();
2454
2455     return role == ButtonRole || role == PopUpButtonRole || role == ToggleButtonRole;
2456 }
2457
2458 bool AccessibilityObject::accessibilityIsIgnoredByDefault() const
2459 {
2460     return defaultObjectInclusion() == IgnoreObject;
2461 }
2462
2463 // ARIA component of hidden definition.
2464 // http://www.w3.org/TR/wai-aria/terms#def_hidden
2465 bool AccessibilityObject::isARIAHidden() const
2466 {
2467     for (const AccessibilityObject* object = this; object; object = object->parentObject()) {
2468         if (equalIgnoringCase(object->getAttribute(aria_hiddenAttr), "true"))
2469             return true;
2470     }
2471     return false;
2472 }
2473
2474 // DOM component of hidden definition.
2475 // http://www.w3.org/TR/wai-aria/terms#def_hidden
2476 bool AccessibilityObject::isDOMHidden() const
2477 {
2478     RenderObject* renderer = this->renderer();
2479     if (!renderer)
2480         return true;
2481     
2482     const RenderStyle& style = renderer->style();
2483     return style.display() == NONE || style.visibility() != VISIBLE;
2484 }
2485
2486 AccessibilityObjectInclusion AccessibilityObject::defaultObjectInclusion() const
2487 {
2488     if (isARIAHidden())
2489         return IgnoreObject;
2490     
2491     if (isPresentationalChildOfAriaRole())
2492         return IgnoreObject;
2493     
2494     return accessibilityPlatformIncludesObject();
2495 }
2496     
2497 bool AccessibilityObject::accessibilityIsIgnored() const
2498 {
2499     AXComputedObjectAttributeCache* attributeCache = nullptr;
2500     AXObjectCache* cache = axObjectCache();
2501     if (cache)
2502         attributeCache = cache->computedObjectAttributeCache();
2503     
2504     if (attributeCache) {
2505         AccessibilityObjectInclusion ignored = attributeCache->getIgnored(axObjectID());
2506         switch (ignored) {
2507         case IgnoreObject:
2508             return true;
2509         case IncludeObject:
2510             return false;
2511         case DefaultBehavior:
2512             break;
2513         }
2514     }
2515
2516     bool result = computeAccessibilityIsIgnored();
2517
2518     // In case computing axIsIgnored disables attribute caching, we should refetch the object to see if it exists.
2519     if (cache && (attributeCache = cache->computedObjectAttributeCache()))
2520         attributeCache->setIgnored(axObjectID(), result ? IgnoreObject : IncludeObject);
2521
2522     return result;
2523 }
2524
2525 void AccessibilityObject::elementsFromAttribute(Vector<Element*>& elements, const QualifiedName& attribute) const
2526 {
2527     Node* node = this->node();
2528     if (!node || !node->isElementNode())
2529         return;
2530
2531     TreeScope& treeScope = node->treeScope();
2532
2533     String idList = getAttribute(attribute).string();
2534     if (idList.isEmpty())
2535         return;
2536
2537     idList.replace('\n', ' ');
2538     Vector<String> idVector;
2539     idList.split(' ', idVector);
2540
2541     for (const auto& idName : idVector) {
2542         if (Element* idElement = treeScope.getElementById(idName))
2543             elements.append(idElement);
2544     }
2545 }
2546
2547 } // namespace WebCore