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