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