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