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