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