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