AX: WebKit doesn't map aria-sort=other on OS X
[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 Computer, 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 "AccessibilityTable.h"
35 #include "DOMTokenList.h"
36 #include "Editor.h"
37 #include "FloatRect.h"
38 #include "FocusController.h"
39 #include "Frame.h"
40 #include "FrameLoader.h"
41 #include "FrameSelection.h"
42 #include "HTMLNames.h"
43 #include "LocalizedStrings.h"
44 #include "NodeList.h"
45 #include "NodeTraversal.h"
46 #include "NotImplemented.h"
47 #include "Page.h"
48 #include "RenderImage.h"
49 #include "RenderListItem.h"
50 #include "RenderListMarker.h"
51 #include "RenderMenuList.h"
52 #include "RenderTextControl.h"
53 #include "RenderTheme.h"
54 #include "RenderView.h"
55 #include "RenderWidget.h"
56 #include "RenderedPosition.h"
57 #include "Settings.h"
58 #include "TextCheckerClient.h"
59 #include "TextCheckingHelper.h"
60 #include "TextIterator.h"
61 #include "UserGestureIndicator.h"
62 #include "VisibleUnits.h"
63 #include "htmlediting.h"
64 #include <wtf/StdLibExtras.h>
65 #include <wtf/text/StringBuilder.h>
66 #include <wtf/text/WTFString.h>
67 #include <wtf/unicode/CharacterNames.h>
68
69 using namespace std;
70
71 namespace WebCore {
72
73 using namespace HTMLNames;
74
75 AccessibilityObject::AccessibilityObject()
76     : m_id(0)
77     , m_haveChildren(false)
78     , m_role(UnknownRole)
79     , m_lastKnownIsIgnoredValue(DefaultBehavior)
80 #if PLATFORM(GTK) || (PLATFORM(EFL) && HAVE(ACCESSIBILITY))
81     , m_wrapper(0)
82 #endif
83 {
84 }
85
86 AccessibilityObject::~AccessibilityObject()
87 {
88     ASSERT(isDetached());
89 }
90
91 void AccessibilityObject::detach()
92 {
93     // Clear any children and call detachFromParent on them so that
94     // no children are left with dangling pointers to their parent.
95     clearChildren();
96
97 #if HAVE(ACCESSIBILITY)
98     setWrapper(0);
99 #endif
100 }
101
102 bool AccessibilityObject::isDetached() const
103 {
104 #if HAVE(ACCESSIBILITY)
105     return !wrapper();
106 #else
107     return true;
108 #endif
109 }
110
111 bool AccessibilityObject::isAccessibilityObjectSearchMatchAtIndex(AccessibilityObject* axObject, AccessibilitySearchCriteria* criteria, size_t index)
112 {
113     switch (criteria->searchKeys[index]) {
114     // The AnyTypeSearchKey matches any non-null AccessibilityObject.
115     case AnyTypeSearchKey:
116         return true;
117         
118     case BlockquoteSameLevelSearchKey:
119         return criteria->startObject
120             && axObject->isBlockquote()
121             && axObject->blockquoteLevel() == criteria->startObject->blockquoteLevel();
122         
123     case BlockquoteSearchKey:
124         return axObject->isBlockquote();
125         
126     case BoldFontSearchKey:
127         return axObject->hasBoldFont();
128         
129     case ButtonSearchKey:
130         return axObject->isButton();
131         
132     case CheckBoxSearchKey:
133         return axObject->isCheckbox();
134         
135     case ControlSearchKey:
136         return axObject->isControl();
137         
138     case DifferentTypeSearchKey:
139         return criteria->startObject
140             && axObject->roleValue() != criteria->startObject->roleValue();
141         
142     case FontChangeSearchKey:
143         return criteria->startObject
144             && !axObject->hasSameFont(criteria->startObject->renderer());
145         
146     case FontColorChangeSearchKey:
147         return criteria->startObject
148             && !axObject->hasSameFontColor(criteria->startObject->renderer());
149         
150     case FrameSearchKey:
151         return axObject->isWebArea();
152         
153     case GraphicSearchKey:
154         return axObject->isImage();
155         
156     case HeadingLevel1SearchKey:
157         return axObject->headingLevel() == 1;
158         
159     case HeadingLevel2SearchKey:
160         return axObject->headingLevel() == 2;
161         
162     case HeadingLevel3SearchKey:
163         return axObject->headingLevel() == 3;
164         
165     case HeadingLevel4SearchKey:
166         return axObject->headingLevel() == 4;
167         
168     case HeadingLevel5SearchKey:
169         return axObject->headingLevel() == 5;
170         
171     case HeadingLevel6SearchKey:
172         return axObject->headingLevel() == 6;
173         
174     case HeadingSameLevelSearchKey:
175         return criteria->startObject
176             && axObject->isHeading()
177             && axObject->headingLevel() == criteria->startObject->headingLevel();
178         
179     case HeadingSearchKey:
180         return axObject->isHeading();
181     
182     case HighlightedSearchKey:
183         return axObject->hasHighlighting();
184             
185     case ItalicFontSearchKey:
186         return axObject->hasItalicFont();
187         
188     case LandmarkSearchKey:
189         return axObject->isLandmark();
190         
191     case LinkSearchKey:
192         return axObject->isLink();
193         
194     case ListSearchKey:
195         return axObject->isList();
196         
197     case LiveRegionSearchKey:
198         return axObject->supportsARIALiveRegion();
199         
200     case MisspelledWordSearchKey:
201         return axObject->hasMisspelling();
202         
203     case PlainTextSearchKey:
204         return axObject->hasPlainText();
205         
206     case RadioGroupSearchKey:
207         return axObject->isRadioGroup();
208         
209     case SameTypeSearchKey:
210         return criteria->startObject
211             && axObject->roleValue() == criteria->startObject->roleValue();
212         
213     case StaticTextSearchKey:
214         return axObject->isStaticText();
215         
216     case StyleChangeSearchKey:
217         return criteria->startObject
218             && !axObject->hasSameStyle(criteria->startObject->renderer());
219         
220     case TableSameLevelSearchKey:
221         return criteria->startObject
222             && axObject->isAccessibilityTable()
223             && axObject->tableLevel() == criteria->startObject->tableLevel();
224         
225     case TableSearchKey:
226         return axObject->isAccessibilityTable();
227         
228     case TextFieldSearchKey:
229         return axObject->isTextControl();
230         
231     case UnderlineSearchKey:
232         return axObject->hasUnderline();
233         
234     case UnvisitedLinkSearchKey:
235         return axObject->isUnvisited();
236         
237     case VisitedLinkSearchKey:
238         return axObject->isVisited();
239         
240     default:
241         return false;
242     }
243 }
244
245 bool AccessibilityObject::isAccessibilityObjectSearchMatch(AccessibilityObject* axObject, AccessibilitySearchCriteria* criteria)
246 {
247     if (!axObject || !criteria)
248         return false;
249     
250     size_t length = criteria->searchKeys.size();
251     for (size_t i = 0; i < length; ++i) {
252         if (isAccessibilityObjectSearchMatchAtIndex(axObject, criteria, i)) {
253             if (criteria->visibleOnly && !axObject->isOnscreen())
254                 return false;
255             return true;
256         }
257     }
258     return false;
259 }
260
261 bool AccessibilityObject::isAccessibilityTextSearchMatch(AccessibilityObject* axObject, AccessibilitySearchCriteria* criteria)
262 {
263     if (!axObject || !criteria)
264         return false;
265     
266     return axObject->accessibilityObjectContainsText(criteria->searchText);
267 }
268
269 bool AccessibilityObject::accessibilityObjectContainsText(String* text) const
270 {
271     // If text is null or empty we return true.
272     return !text
273         || text->isEmpty()
274         || title().contains(*text, false)
275         || accessibilityDescription().contains(*text, false)
276         || stringValue().contains(*text, false);
277 }
278
279 bool AccessibilityObject::isBlockquote() const
280 {
281     return node() && node()->hasTagName(blockquoteTag);
282 }
283
284 bool AccessibilityObject::isTextControl() const
285 {
286     switch (roleValue()) {
287     case TextAreaRole:
288     case TextFieldRole:
289     case ComboBoxRole:
290         return true;
291     default:
292         return false;
293     }
294 }
295     
296 bool AccessibilityObject::isARIATextControl() const
297 {
298     return ariaRoleAttribute() == TextAreaRole || ariaRoleAttribute() == TextFieldRole;
299 }
300
301 bool AccessibilityObject::isLandmark() const
302 {
303     AccessibilityRole role = roleValue();
304     
305     return role == LandmarkApplicationRole
306         || role == LandmarkBannerRole
307         || role == LandmarkComplementaryRole
308         || role == LandmarkContentInfoRole
309         || role == LandmarkMainRole
310         || role == LandmarkNavigationRole
311         || role == LandmarkSearchRole;
312 }
313
314 bool AccessibilityObject::hasMisspelling() const
315 {
316     if (!node())
317         return false;
318     
319     Frame* frame = node()->document().frame();
320     if (!frame)
321         return false;
322     
323     Editor& editor = frame->editor();
324     
325     TextCheckerClient* textChecker = editor.textChecker();
326     if (!textChecker)
327         return false;
328     
329     const UChar* chars = stringValue().characters();
330     int charsLength = stringValue().length();
331     bool isMisspelled = false;
332
333     if (unifiedTextCheckerEnabled(frame)) {
334         Vector<TextCheckingResult> results;
335         checkTextOfParagraph(textChecker, chars, charsLength, TextCheckingTypeSpelling, results);
336         if (!results.isEmpty())
337             isMisspelled = true;
338         return isMisspelled;
339     }
340
341     int misspellingLength = 0;
342     int misspellingLocation = -1;
343     textChecker->checkSpellingOfString(chars, charsLength, &misspellingLocation, &misspellingLength);
344     if (misspellingLength || misspellingLocation != -1)
345         isMisspelled = true;
346     
347     return isMisspelled;
348 }
349
350 int AccessibilityObject::blockquoteLevel() const
351 {
352     int level = 0;
353     for (Node* elementNode = node(); elementNode; elementNode = elementNode->parentNode()) {
354         if (elementNode->hasTagName(blockquoteTag))
355             ++level;
356     }
357     
358     return level;
359 }
360
361 AccessibilityObject* AccessibilityObject::parentObjectUnignored() const
362 {
363     AccessibilityObject* parent;
364     for (parent = parentObject(); parent && parent->accessibilityIsIgnored(); parent = parent->parentObject()) {
365     }
366     
367     return parent;
368 }
369
370 AccessibilityObject* AccessibilityObject::firstAccessibleObjectFromNode(const Node* node)
371 {
372     if (!node)
373         return 0;
374
375     AXObjectCache* cache = node->document().axObjectCache();
376
377     AccessibilityObject* accessibleObject = cache->getOrCreate(node->renderer());
378     while (accessibleObject && accessibleObject->accessibilityIsIgnored()) {
379         node = NodeTraversal::next(node);
380
381         while (node && !node->renderer())
382             node = NodeTraversal::nextSkippingChildren(node);
383
384         if (!node)
385             return 0;
386
387         accessibleObject = cache->getOrCreate(node->renderer());
388     }
389
390     return accessibleObject;
391 }
392
393 static void appendAccessibilityObject(AccessibilityObject* object, AccessibilityObject::AccessibilityChildrenVector& results)
394 {
395     // Find the next descendant of this attachment object so search can continue through frames.
396     if (object->isAttachment()) {
397         Widget* widget = object->widgetForAttachmentView();
398         if (!widget || !widget->isFrameView())
399             return;
400         
401         Document* doc = toFrameView(widget)->frame().document();
402         if (!doc || !doc->hasLivingRenderTree())
403             return;
404         
405         object = object->axObjectCache()->getOrCreate(doc);
406     }
407
408     if (object)
409         results.append(object);
410 }
411     
412 static void appendChildrenToArray(AccessibilityObject* object, bool isForward, AccessibilityObject* startObject, AccessibilityObject::AccessibilityChildrenVector& results)
413 {
414     AccessibilityObject::AccessibilityChildrenVector searchChildren;
415     // A table's children includes elements whose own children are also the table's children (due to the way the Mac exposes tables).
416     // The rows from the table should be queried, since those are direct descendants of the table, and they contain content.
417     if (object->isAccessibilityTable())
418         searchChildren = toAccessibilityTable(object)->rows();
419     else
420         searchChildren = object->children();
421
422     size_t childrenSize = searchChildren.size();
423
424     size_t startIndex = isForward ? childrenSize : 0;
425     size_t endIndex = isForward ? 0 : childrenSize;
426
427     size_t searchPosition = startObject ? searchChildren.find(startObject) : WTF::notFound;
428     if (searchPosition != WTF::notFound) {
429         if (isForward)
430             endIndex = searchPosition + 1;
431         else
432             endIndex = searchPosition;
433     }
434
435     // This is broken into two statements so that it's easier read.
436     if (isForward) {
437         for (size_t i = startIndex; i > endIndex; i--)
438             appendAccessibilityObject(searchChildren.at(i - 1).get(), results);
439     } else {
440         for (size_t i = startIndex; i < endIndex; i++)
441             appendAccessibilityObject(searchChildren.at(i).get(), results);
442     }
443 }
444
445 // Returns true if the number of results is now >= the number of results desired.
446 bool AccessibilityObject::objectMatchesSearchCriteriaWithResultLimit(AccessibilityObject* object, AccessibilitySearchCriteria* criteria, AccessibilityChildrenVector& results)
447 {
448     if (isAccessibilityObjectSearchMatch(object, criteria) && isAccessibilityTextSearchMatch(object, criteria)) {
449         results.append(object);
450         
451         // Enough results were found to stop searching.
452         if (results.size() >= criteria->resultsLimit)
453             return true;
454     }
455     
456     return false;
457 }
458
459 void AccessibilityObject::findMatchingObjects(AccessibilitySearchCriteria* criteria, AccessibilityChildrenVector& results)
460 {
461     ASSERT(criteria);
462     
463     if (!criteria)
464         return;
465
466     axObjectCache()->startCachingComputedObjectAttributesUntilTreeMutates();
467
468     // This search mechanism only searches the elements before/after the starting object.
469     // It does this by stepping up the parent chain and at each level doing a DFS.
470     
471     // If there's no start object, it means we want to search everything.
472     AccessibilityObject* startObject = criteria->startObject;
473     if (!startObject)
474         startObject = this;
475     
476     bool isForward = criteria->searchDirection == SearchDirectionNext;
477     
478     // In the first iteration of the loop, it will examine the children of the start object for matches.
479     // However, when going backwards, those children should not be considered, so the loop is skipped ahead.
480     AccessibilityObject* previousObject = 0;
481     if (!isForward) {
482         previousObject = startObject;
483         startObject = startObject->parentObjectUnignored();
484     }
485     
486     // The outer loop steps up the parent chain each time (unignored is important here because otherwise elements would be searched twice)
487     for (AccessibilityObject* stopSearchElement = parentObjectUnignored(); startObject != stopSearchElement; startObject = startObject->parentObjectUnignored()) {
488
489         // Only append the children after/before the previous element, so that the search does not check elements that are 
490         // already behind/ahead of start element.
491         AccessibilityChildrenVector searchStack;
492         appendChildrenToArray(startObject, isForward, previousObject, searchStack);
493
494         // This now does a DFS at the current level of the parent.
495         while (!searchStack.isEmpty()) {
496             AccessibilityObject* searchObject = searchStack.last().get();
497             searchStack.removeLast();
498             
499             if (objectMatchesSearchCriteriaWithResultLimit(searchObject, criteria, results))
500                 break;
501             
502             appendChildrenToArray(searchObject, isForward, 0, searchStack);
503         }
504         
505         if (results.size() >= criteria->resultsLimit)
506             break;
507
508         // When moving backwards, the parent object needs to be checked, because technically it's "before" the starting element.
509         if (!isForward && objectMatchesSearchCriteriaWithResultLimit(startObject, criteria, results))
510             break;
511
512         previousObject = startObject;
513     }
514 }
515
516 bool AccessibilityObject::isARIAInput(AccessibilityRole ariaRole)
517 {
518     return ariaRole == RadioButtonRole || ariaRole == CheckBoxRole || ariaRole == TextFieldRole;
519 }    
520     
521 bool AccessibilityObject::isARIAControl(AccessibilityRole ariaRole)
522 {
523     return isARIAInput(ariaRole) || ariaRole == TextAreaRole || ariaRole == ButtonRole 
524     || ariaRole == ComboBoxRole || ariaRole == SliderRole; 
525 }
526     
527 bool AccessibilityObject::isRangeControl() const
528 {
529     switch (roleValue()) {
530     case ProgressIndicatorRole:
531     case SliderRole:
532     case ScrollBarRole:
533     case SpinButtonRole:
534         return true;
535     default:
536         return false;
537     }
538 }
539
540 bool AccessibilityObject::isMeter() const
541 {
542 #if ENABLE(METER_ELEMENT)
543     RenderObject* renderer = this->renderer();
544     return renderer && renderer->isMeter();
545 #else
546     return false;
547 #endif
548 }
549
550 IntPoint AccessibilityObject::clickPoint()
551 {
552     LayoutRect rect = elementRect();
553     return roundedIntPoint(LayoutPoint(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2));
554 }
555
556 IntRect AccessibilityObject::boundingBoxForQuads(RenderObject* obj, const Vector<FloatQuad>& quads)
557 {
558     ASSERT(obj);
559     if (!obj)
560         return IntRect();
561     
562     size_t count = quads.size();
563     if (!count)
564         return IntRect();
565     
566     IntRect result;
567     for (size_t i = 0; i < count; ++i) {
568         IntRect r = quads[i].enclosingBoundingBox();
569         if (!r.isEmpty()) {
570             if (obj->style()->hasAppearance())
571                 obj->theme()->adjustRepaintRect(obj, r);
572             result.unite(r);
573         }
574     }
575     return result;
576 }
577     
578 bool AccessibilityObject::press() const
579 {
580     Element* actionElem = actionElement();
581     if (!actionElem)
582         return false;
583     if (Frame* f = actionElem->document().frame())
584         f->loader().resetMultipleFormSubmissionProtection();
585     
586     UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
587     actionElem->accessKeyAction(true);
588     return true;
589 }
590     
591 String AccessibilityObject::language() const
592 {
593     const AtomicString& lang = getAttribute(langAttr);
594     if (!lang.isEmpty())
595         return lang;
596
597     AccessibilityObject* parent = parentObject();
598     
599     // as a last resort, fall back to the content language specified in the meta tag
600     if (!parent) {
601         Document* doc = document();
602         if (doc)
603             return doc->contentLanguage();
604         return nullAtom;
605     }
606     
607     return parent->language();
608 }
609     
610 VisiblePositionRange AccessibilityObject::visiblePositionRangeForUnorderedPositions(const VisiblePosition& visiblePos1, const VisiblePosition& visiblePos2) const
611 {
612     if (visiblePos1.isNull() || visiblePos2.isNull())
613         return VisiblePositionRange();
614
615     VisiblePosition startPos;
616     VisiblePosition endPos;
617     bool alreadyInOrder;
618
619     // upstream is ordered before downstream for the same position
620     if (visiblePos1 == visiblePos2 && visiblePos2.affinity() == UPSTREAM)
621         alreadyInOrder = false;
622
623     // use selection order to see if the positions are in order
624     else
625         alreadyInOrder = VisibleSelection(visiblePos1, visiblePos2).isBaseFirst();
626
627     if (alreadyInOrder) {
628         startPos = visiblePos1;
629         endPos = visiblePos2;
630     } else {
631         startPos = visiblePos2;
632         endPos = visiblePos1;
633     }
634
635     return VisiblePositionRange(startPos, endPos);
636 }
637
638 VisiblePositionRange AccessibilityObject::positionOfLeftWord(const VisiblePosition& visiblePos) const
639 {
640     VisiblePosition startPosition = startOfWord(visiblePos, LeftWordIfOnBoundary);
641     VisiblePosition endPosition = endOfWord(startPosition);
642     return VisiblePositionRange(startPosition, endPosition);
643 }
644
645 VisiblePositionRange AccessibilityObject::positionOfRightWord(const VisiblePosition& visiblePos) const
646 {
647     VisiblePosition startPosition = startOfWord(visiblePos, RightWordIfOnBoundary);
648     VisiblePosition endPosition = endOfWord(startPosition);
649     return VisiblePositionRange(startPosition, endPosition);
650 }
651
652 static VisiblePosition updateAXLineStartForVisiblePosition(const VisiblePosition& visiblePosition)
653 {
654     // A line in the accessibility sense should include floating objects, such as aligned image, as part of a line.
655     // So let's update the position to include that.
656     VisiblePosition tempPosition;
657     VisiblePosition startPosition = visiblePosition;
658     while (true) {
659         tempPosition = startPosition.previous();
660         if (tempPosition.isNull())
661             break;
662         Position p = tempPosition.deepEquivalent();
663         RenderObject* renderer = p.deprecatedNode()->renderer();
664         if (!renderer || (renderer->isRenderBlock() && !p.deprecatedEditingOffset()))
665             break;
666         if (!RenderedPosition(tempPosition).isNull())
667             break;
668         startPosition = tempPosition;
669     }
670
671     return startPosition;
672 }
673
674 VisiblePositionRange AccessibilityObject::leftLineVisiblePositionRange(const VisiblePosition& visiblePos) const
675 {
676     if (visiblePos.isNull())
677         return VisiblePositionRange();
678
679     // make a caret selection for the position before marker position (to make sure
680     // we move off of a line start)
681     VisiblePosition prevVisiblePos = visiblePos.previous();
682     if (prevVisiblePos.isNull())
683         return VisiblePositionRange();
684
685     VisiblePosition startPosition = startOfLine(prevVisiblePos);
686
687     // keep searching for a valid line start position.  Unless the VisiblePosition is at the very beginning, there should
688     // always be a valid line range.  However, startOfLine will return null for position next to a floating object,
689     // since floating object doesn't really belong to any line.
690     // This check will reposition the marker before the floating object, to ensure we get a line start.
691     if (startPosition.isNull()) {
692         while (startPosition.isNull() && prevVisiblePos.isNotNull()) {
693             prevVisiblePos = prevVisiblePos.previous();
694             startPosition = startOfLine(prevVisiblePos);
695         }
696     } else
697         startPosition = updateAXLineStartForVisiblePosition(startPosition);
698
699     VisiblePosition endPosition = endOfLine(prevVisiblePos);
700     return VisiblePositionRange(startPosition, endPosition);
701 }
702
703 VisiblePositionRange AccessibilityObject::rightLineVisiblePositionRange(const VisiblePosition& visiblePos) const
704 {
705     if (visiblePos.isNull())
706         return VisiblePositionRange();
707
708     // make sure we move off of a line end
709     VisiblePosition nextVisiblePos = visiblePos.next();
710     if (nextVisiblePos.isNull())
711         return VisiblePositionRange();
712
713     VisiblePosition startPosition = startOfLine(nextVisiblePos);
714
715     // fetch for a valid line start position
716     if (startPosition.isNull()) {
717         startPosition = visiblePos;
718         nextVisiblePos = nextVisiblePos.next();
719     } else
720         startPosition = updateAXLineStartForVisiblePosition(startPosition);
721
722     VisiblePosition endPosition = endOfLine(nextVisiblePos);
723
724     // as long as the position hasn't reached the end of the doc,  keep searching for a valid line end position
725     // Unless the VisiblePosition is at the very end, there should always be a valid line range.  However, endOfLine will
726     // return null for position by a floating object, since floating object doesn't really belong to any line.
727     // This check will reposition the marker after the floating object, to ensure we get a line end.
728     while (endPosition.isNull() && nextVisiblePos.isNotNull()) {
729         nextVisiblePos = nextVisiblePos.next();
730         endPosition = endOfLine(nextVisiblePos);
731     }
732
733     return VisiblePositionRange(startPosition, endPosition);
734 }
735
736 VisiblePositionRange AccessibilityObject::sentenceForPosition(const VisiblePosition& visiblePos) const
737 {
738     // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
739     // Related? <rdar://problem/3927736> Text selection broken in 8A336
740     VisiblePosition startPosition = startOfSentence(visiblePos);
741     VisiblePosition endPosition = endOfSentence(startPosition);
742     return VisiblePositionRange(startPosition, endPosition);
743 }
744
745 VisiblePositionRange AccessibilityObject::paragraphForPosition(const VisiblePosition& visiblePos) const
746 {
747     VisiblePosition startPosition = startOfParagraph(visiblePos);
748     VisiblePosition endPosition = endOfParagraph(startPosition);
749     return VisiblePositionRange(startPosition, endPosition);
750 }
751
752 static VisiblePosition startOfStyleRange(const VisiblePosition& visiblePos)
753 {
754     RenderObject* renderer = visiblePos.deepEquivalent().deprecatedNode()->renderer();
755     RenderObject* startRenderer = renderer;
756     RenderStyle* style = renderer->style();
757
758     // traverse backward by renderer to look for style change
759     for (RenderObject* r = renderer->previousInPreOrder(); r; r = r->previousInPreOrder()) {
760         // skip non-leaf nodes
761         if (r->firstChildSlow())
762             continue;
763
764         // stop at style change
765         if (r->style() != style)
766             break;
767
768         // remember match
769         startRenderer = r;
770     }
771
772     return firstPositionInOrBeforeNode(startRenderer->node());
773 }
774
775 static VisiblePosition endOfStyleRange(const VisiblePosition& visiblePos)
776 {
777     RenderObject* renderer = visiblePos.deepEquivalent().deprecatedNode()->renderer();
778     RenderObject* endRenderer = renderer;
779     RenderStyle* style = renderer->style();
780
781     // traverse forward by renderer to look for style change
782     for (RenderObject* r = renderer->nextInPreOrder(); r; r = r->nextInPreOrder()) {
783         // skip non-leaf nodes
784         if (r->firstChildSlow())
785             continue;
786
787         // stop at style change
788         if (r->style() != style)
789             break;
790
791         // remember match
792         endRenderer = r;
793     }
794
795     return lastPositionInOrAfterNode(endRenderer->node());
796 }
797
798 VisiblePositionRange AccessibilityObject::styleRangeForPosition(const VisiblePosition& visiblePos) const
799 {
800     if (visiblePos.isNull())
801         return VisiblePositionRange();
802
803     return VisiblePositionRange(startOfStyleRange(visiblePos), endOfStyleRange(visiblePos));
804 }
805
806 // NOTE: Consider providing this utility method as AX API
807 VisiblePositionRange AccessibilityObject::visiblePositionRangeForRange(const PlainTextRange& range) const
808 {
809     unsigned textLength = getLengthForTextRange();
810     if (range.start + range.length > textLength)
811         return VisiblePositionRange();
812
813     VisiblePosition startPosition = visiblePositionForIndex(range.start);
814     startPosition.setAffinity(DOWNSTREAM);
815     VisiblePosition endPosition = visiblePositionForIndex(range.start + range.length);
816     return VisiblePositionRange(startPosition, endPosition);
817 }
818
819 static bool replacedNodeNeedsCharacter(Node* replacedNode)
820 {
821     // we should always be given a rendered node and a replaced node, but be safe
822     // replaced nodes are either attachments (widgets) or images
823     if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode())
824         return false;
825
826     // create an AX object, but skip it if it is not supposed to be seen
827     AccessibilityObject* object = replacedNode->renderer()->document().axObjectCache()->getOrCreate(replacedNode);
828     if (object->accessibilityIsIgnored())
829         return false;
830
831     return true;
832 }
833
834 // Finds a RenderListItem parent give a node.
835 static RenderListItem* renderListItemContainerForNode(Node* node)
836 {
837     for (; node; node = node->parentNode()) {
838         RenderBoxModelObject* renderer = node->renderBoxModelObject();
839         if (renderer && renderer->isListItem())
840             return toRenderListItem(renderer);
841     }
842     return 0;
843 }
844     
845 // Returns the text associated with a list marker if this node is contained within a list item.
846 String AccessibilityObject::listMarkerTextForNodeAndPosition(Node* node, const VisiblePosition& visiblePositionStart) const
847 {
848     // If the range does not contain the start of the line, the list marker text should not be included.
849     if (!isStartOfLine(visiblePositionStart))
850         return String();
851
852     RenderListItem* listItem = renderListItemContainerForNode(node);
853     if (!listItem)
854         return String();
855         
856     // If this is in a list item, we need to manually add the text for the list marker 
857     // because a RenderListMarker does not have a Node equivalent and thus does not appear
858     // when iterating text.
859     return listItem->markerTextWithSuffix();
860 }
861     
862 String AccessibilityObject::stringForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const
863 {
864     if (visiblePositionRange.isNull())
865         return String();
866
867     StringBuilder builder;
868     RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end);
869     for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
870         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
871         if (it.length()) {
872             // Add a textual representation for list marker text
873             String listMarkerText = listMarkerTextForNodeAndPosition(it.node(), visiblePositionRange.start);
874             if (!listMarkerText.isEmpty())
875                 builder.append(listMarkerText);
876
877             it.appendTextToStringBuilder(builder);
878         } else {
879             // locate the node and starting offset for this replaced range
880             int exception = 0;
881             Node* node = it.range()->startContainer(exception);
882             ASSERT(node == it.range()->endContainer(exception));
883             int offset = it.range()->startOffset(exception);
884
885             if (replacedNodeNeedsCharacter(node->childNode(offset)))
886                 builder.append(objectReplacementCharacter);
887         }
888     }
889
890     return builder.toString();
891 }
892
893 int AccessibilityObject::lengthForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const
894 {
895     // FIXME: Multi-byte support
896     if (visiblePositionRange.isNull())
897         return -1;
898     
899     int length = 0;
900     RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end);
901     for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
902         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
903         if (it.length())
904             length += it.length();
905         else {
906             // locate the node and starting offset for this replaced range
907             int exception = 0;
908             Node* node = it.range()->startContainer(exception);
909             ASSERT(node == it.range()->endContainer(exception));
910             int offset = it.range()->startOffset(exception);
911
912             if (replacedNodeNeedsCharacter(node->childNode(offset)))
913                 length++;
914         }
915     }
916     
917     return length;
918 }
919
920 VisiblePosition AccessibilityObject::nextWordEnd(const VisiblePosition& visiblePos) const
921 {
922     if (visiblePos.isNull())
923         return VisiblePosition();
924
925     // make sure we move off of a word end
926     VisiblePosition nextVisiblePos = visiblePos.next();
927     if (nextVisiblePos.isNull())
928         return VisiblePosition();
929
930     return endOfWord(nextVisiblePos, LeftWordIfOnBoundary);
931 }
932
933 VisiblePosition AccessibilityObject::previousWordStart(const VisiblePosition& visiblePos) const
934 {
935     if (visiblePos.isNull())
936         return VisiblePosition();
937
938     // make sure we move off of a word start
939     VisiblePosition prevVisiblePos = visiblePos.previous();
940     if (prevVisiblePos.isNull())
941         return VisiblePosition();
942
943     return startOfWord(prevVisiblePos, RightWordIfOnBoundary);
944 }
945
946 VisiblePosition AccessibilityObject::nextLineEndPosition(const VisiblePosition& visiblePos) const
947 {
948     if (visiblePos.isNull())
949         return VisiblePosition();
950
951     // to make sure we move off of a line end
952     VisiblePosition nextVisiblePos = visiblePos.next();
953     if (nextVisiblePos.isNull())
954         return VisiblePosition();
955
956     VisiblePosition endPosition = endOfLine(nextVisiblePos);
957
958     // as long as the position hasn't reached the end of the doc,  keep searching for a valid line end position
959     // 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.
960     while (endPosition.isNull() && nextVisiblePos.isNotNull()) {
961         nextVisiblePos = nextVisiblePos.next();
962         endPosition = endOfLine(nextVisiblePos);
963     }
964
965     return endPosition;
966 }
967
968 VisiblePosition AccessibilityObject::previousLineStartPosition(const VisiblePosition& visiblePos) const
969 {
970     if (visiblePos.isNull())
971         return VisiblePosition();
972
973     // make sure we move off of a line start
974     VisiblePosition prevVisiblePos = visiblePos.previous();
975     if (prevVisiblePos.isNull())
976         return VisiblePosition();
977
978     VisiblePosition startPosition = startOfLine(prevVisiblePos);
979
980     // as long as the position hasn't reached the beginning of the doc,  keep searching for a valid line start position
981     // 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.
982     if (startPosition.isNull()) {
983         while (startPosition.isNull() && prevVisiblePos.isNotNull()) {
984             prevVisiblePos = prevVisiblePos.previous();
985             startPosition = startOfLine(prevVisiblePos);
986         }
987     } else
988         startPosition = updateAXLineStartForVisiblePosition(startPosition);
989
990     return startPosition;
991 }
992
993 VisiblePosition AccessibilityObject::nextSentenceEndPosition(const VisiblePosition& visiblePos) const
994 {
995     // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
996     // Related? <rdar://problem/3927736> Text selection broken in 8A336
997     if (visiblePos.isNull())
998         return VisiblePosition();
999
1000     // make sure we move off of a sentence end
1001     VisiblePosition nextVisiblePos = visiblePos.next();
1002     if (nextVisiblePos.isNull())
1003         return VisiblePosition();
1004
1005     // an empty line is considered a sentence. If it's skipped, then the sentence parser will not
1006     // see this empty line.  Instead, return the end position of the empty line.
1007     VisiblePosition endPosition;
1008     
1009     String lineString = plainText(makeRange(startOfLine(nextVisiblePos), endOfLine(nextVisiblePos)).get());
1010     if (lineString.isEmpty())
1011         endPosition = nextVisiblePos;
1012     else
1013         endPosition = endOfSentence(nextVisiblePos);
1014
1015     return endPosition;
1016 }
1017
1018 VisiblePosition AccessibilityObject::previousSentenceStartPosition(const VisiblePosition& visiblePos) const
1019 {
1020     // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
1021     // Related? <rdar://problem/3927736> Text selection broken in 8A336
1022     if (visiblePos.isNull())
1023         return VisiblePosition();
1024
1025     // make sure we move off of a sentence start
1026     VisiblePosition previousVisiblePos = visiblePos.previous();
1027     if (previousVisiblePos.isNull())
1028         return VisiblePosition();
1029
1030     // treat empty line as a separate sentence.
1031     VisiblePosition startPosition;
1032     
1033     String lineString = plainText(makeRange(startOfLine(previousVisiblePos), endOfLine(previousVisiblePos)).get());
1034     if (lineString.isEmpty())
1035         startPosition = previousVisiblePos;
1036     else
1037         startPosition = startOfSentence(previousVisiblePos);
1038
1039     return startPosition;
1040 }
1041
1042 VisiblePosition AccessibilityObject::nextParagraphEndPosition(const VisiblePosition& visiblePos) const
1043 {
1044     if (visiblePos.isNull())
1045         return VisiblePosition();
1046
1047     // make sure we move off of a paragraph end
1048     VisiblePosition nextPos = visiblePos.next();
1049     if (nextPos.isNull())
1050         return VisiblePosition();
1051
1052     return endOfParagraph(nextPos);
1053 }
1054
1055 VisiblePosition AccessibilityObject::previousParagraphStartPosition(const VisiblePosition& visiblePos) const
1056 {
1057     if (visiblePos.isNull())
1058         return VisiblePosition();
1059
1060     // make sure we move off of a paragraph start
1061     VisiblePosition previousPos = visiblePos.previous();
1062     if (previousPos.isNull())
1063         return VisiblePosition();
1064
1065     return startOfParagraph(previousPos);
1066 }
1067
1068 AccessibilityObject* AccessibilityObject::accessibilityObjectForPosition(const VisiblePosition& visiblePos) const
1069 {
1070     if (visiblePos.isNull())
1071         return 0;
1072
1073     RenderObject* obj = visiblePos.deepEquivalent().deprecatedNode()->renderer();
1074     if (!obj)
1075         return 0;
1076
1077     return obj->document().axObjectCache()->getOrCreate(obj);
1078 }
1079
1080 #if HAVE(ACCESSIBILITY)
1081 int AccessibilityObject::lineForPosition(const VisiblePosition& visiblePos) const
1082 {
1083     if (visiblePos.isNull() || !node())
1084         return -1;
1085
1086     // If the position is not in the same editable region as this AX object, return -1.
1087     Node* containerNode = visiblePos.deepEquivalent().containerNode();
1088     if (!containerNode->containsIncludingShadowDOM(node()) && !node()->containsIncludingShadowDOM(containerNode))
1089         return -1;
1090
1091     int lineCount = -1;
1092     VisiblePosition currentVisiblePos = visiblePos;
1093     VisiblePosition savedVisiblePos;
1094
1095     // move up until we get to the top
1096     // FIXME: This only takes us to the top of the rootEditableElement, not the top of the
1097     // top document.
1098     do {
1099         savedVisiblePos = currentVisiblePos;
1100         VisiblePosition prevVisiblePos = previousLinePosition(currentVisiblePos, 0, HasEditableAXRole);
1101         currentVisiblePos = prevVisiblePos;
1102         ++lineCount;
1103     }  while (currentVisiblePos.isNotNull() && !(inSameLine(currentVisiblePos, savedVisiblePos)));
1104
1105     return lineCount;
1106 }
1107 #endif
1108
1109 // NOTE: Consider providing this utility method as AX API
1110 PlainTextRange AccessibilityObject::plainTextRangeForVisiblePositionRange(const VisiblePositionRange& positionRange) const
1111 {
1112     int index1 = index(positionRange.start);
1113     int index2 = index(positionRange.end);
1114     if (index1 < 0 || index2 < 0 || index1 > index2)
1115         return PlainTextRange();
1116
1117     return PlainTextRange(index1, index2 - index1);
1118 }
1119
1120 // The composed character range in the text associated with this accessibility object that
1121 // is specified by the given screen coordinates. This parameterized attribute returns the
1122 // complete range of characters (including surrogate pairs of multi-byte glyphs) at the given
1123 // screen coordinates.
1124 // NOTE: This varies from AppKit when the point is below the last line. AppKit returns an
1125 // an error in that case. We return textControl->text().length(), 1. Does this matter?
1126 PlainTextRange AccessibilityObject::doAXRangeForPosition(const IntPoint& point) const
1127 {
1128     int i = index(visiblePositionForPoint(point));
1129     if (i < 0)
1130         return PlainTextRange();
1131
1132     return PlainTextRange(i, 1);
1133 }
1134
1135 // Given a character index, the range of text associated with this accessibility object
1136 // over which the style in effect at that character index applies.
1137 PlainTextRange AccessibilityObject::doAXStyleRangeForIndex(unsigned index) const
1138 {
1139     VisiblePositionRange range = styleRangeForPosition(visiblePositionForIndex(index, false));
1140     return plainTextRangeForVisiblePositionRange(range);
1141 }
1142
1143 // Given an indexed character, the line number of the text associated with this accessibility
1144 // object that contains the character.
1145 unsigned AccessibilityObject::doAXLineForIndex(unsigned index)
1146 {
1147     return lineForPosition(visiblePositionForIndex(index, false));
1148 }
1149
1150 #if HAVE(ACCESSIBILITY)
1151 void AccessibilityObject::updateBackingStore()
1152 {
1153     // Updating the layout may delete this object.
1154     if (Document* document = this->document())
1155         document->updateLayoutIgnorePendingStylesheets();
1156 }
1157 #endif
1158
1159 Document* AccessibilityObject::document() const
1160 {
1161     FrameView* frameView = documentFrameView();
1162     if (!frameView)
1163         return 0;
1164     
1165     return frameView->frame().document();
1166 }
1167     
1168 Page* AccessibilityObject::page() const
1169 {
1170     Document* document = this->document();
1171     if (!document)
1172         return 0;
1173     return document->page();
1174 }
1175
1176 FrameView* AccessibilityObject::documentFrameView() const 
1177
1178     const AccessibilityObject* object = this;
1179     while (object && !object->isAccessibilityRenderObject()) 
1180         object = object->parentObject();
1181         
1182     if (!object)
1183         return 0;
1184
1185     return object->documentFrameView();
1186 }
1187
1188 #if HAVE(ACCESSIBILITY)
1189 const AccessibilityObject::AccessibilityChildrenVector& AccessibilityObject::children()
1190 {
1191     updateChildrenIfNecessary();
1192
1193     return m_children;
1194 }
1195 #endif
1196
1197 void AccessibilityObject::updateChildrenIfNecessary()
1198 {
1199     if (!hasChildren())
1200         addChildren();    
1201 }
1202     
1203 void AccessibilityObject::clearChildren()
1204 {
1205     // Some objects have weak pointers to their parents and those associations need to be detached.
1206     size_t length = m_children.size();
1207     for (size_t i = 0; i < length; i++)
1208         m_children[i]->detachFromParent();
1209     
1210     m_children.clear();
1211     m_haveChildren = false;
1212 }
1213
1214 AccessibilityObject* AccessibilityObject::anchorElementForNode(Node* node)
1215 {
1216     RenderObject* obj = node->renderer();
1217     if (!obj)
1218         return 0;
1219     
1220     RefPtr<AccessibilityObject> axObj = obj->document().axObjectCache()->getOrCreate(obj);
1221     Element* anchor = axObj->anchorElement();
1222     if (!anchor)
1223         return 0;
1224     
1225     RenderObject* anchorRenderer = anchor->renderer();
1226     if (!anchorRenderer)
1227         return 0;
1228     
1229     return anchorRenderer->document().axObjectCache()->getOrCreate(anchorRenderer);
1230 }
1231
1232 AccessibilityObject* AccessibilityObject::headingElementForNode(Node* node)
1233 {
1234     if (!node)
1235         return 0;
1236     
1237     RenderObject* renderObject = node->renderer();
1238     if (!renderObject)
1239         return 0;
1240     
1241     AccessibilityObject* axObject = renderObject->document().axObjectCache()->getOrCreate(renderObject);
1242     for (; axObject && axObject->roleValue() != HeadingRole; axObject = axObject->parentObject()) { }
1243     
1244     return axObject;
1245 }
1246
1247 void AccessibilityObject::ariaTreeRows(AccessibilityChildrenVector& result)
1248 {
1249     AccessibilityChildrenVector axChildren = children();
1250     unsigned count = axChildren.size();
1251     for (unsigned k = 0; k < count; ++k) {
1252         AccessibilityObject* obj = axChildren[k].get();
1253         
1254         // Add tree items as the rows.
1255         if (obj->roleValue() == TreeItemRole) 
1256             result.append(obj);
1257
1258         // Now see if this item also has rows hiding inside of it.
1259         obj->ariaTreeRows(result);
1260     }
1261 }
1262     
1263 void AccessibilityObject::ariaTreeItemContent(AccessibilityChildrenVector& result)
1264 {
1265     // The ARIA tree item content are the item that are not other tree items or their containing groups.
1266     AccessibilityChildrenVector axChildren = children();
1267     unsigned count = axChildren.size();
1268     for (unsigned k = 0; k < count; ++k) {
1269         AccessibilityObject* obj = axChildren[k].get();
1270         AccessibilityRole role = obj->roleValue();
1271         if (role == TreeItemRole || role == GroupRole)
1272             continue;
1273         
1274         result.append(obj);
1275     }
1276 }
1277
1278 void AccessibilityObject::ariaTreeItemDisclosedRows(AccessibilityChildrenVector& result)
1279 {
1280     AccessibilityChildrenVector axChildren = children();
1281     unsigned count = axChildren.size();
1282     for (unsigned k = 0; k < count; ++k) {
1283         AccessibilityObject* obj = axChildren[k].get();
1284         
1285         // Add tree items as the rows.
1286         if (obj->roleValue() == TreeItemRole)
1287             result.append(obj);
1288         // If it's not a tree item, then descend into the group to find more tree items.
1289         else 
1290             obj->ariaTreeRows(result);
1291     }    
1292 }
1293
1294 #if HAVE(ACCESSIBILITY)
1295 const String& AccessibilityObject::actionVerb() const
1296 {
1297 #if !PLATFORM(IOS)
1298     // FIXME: Need to add verbs for select elements.
1299     DEFINE_STATIC_LOCAL(const String, buttonAction, (AXButtonActionVerb()));
1300     DEFINE_STATIC_LOCAL(const String, textFieldAction, (AXTextFieldActionVerb()));
1301     DEFINE_STATIC_LOCAL(const String, radioButtonAction, (AXRadioButtonActionVerb()));
1302     DEFINE_STATIC_LOCAL(const String, checkedCheckBoxAction, (AXCheckedCheckBoxActionVerb()));
1303     DEFINE_STATIC_LOCAL(const String, uncheckedCheckBoxAction, (AXUncheckedCheckBoxActionVerb()));
1304     DEFINE_STATIC_LOCAL(const String, linkAction, (AXLinkActionVerb()));
1305     DEFINE_STATIC_LOCAL(const String, menuListAction, (AXMenuListActionVerb()));
1306     DEFINE_STATIC_LOCAL(const String, menuListPopupAction, (AXMenuListPopupActionVerb()));
1307     DEFINE_STATIC_LOCAL(const String, listItemAction, (AXListItemActionVerb()));
1308
1309     switch (roleValue()) {
1310     case ButtonRole:
1311     case ToggleButtonRole:
1312         return buttonAction;
1313     case TextFieldRole:
1314     case TextAreaRole:
1315         return textFieldAction;
1316     case RadioButtonRole:
1317         return radioButtonAction;
1318     case CheckBoxRole:
1319         return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction;
1320     case LinkRole:
1321     case WebCoreLinkRole:
1322         return linkAction;
1323     case PopUpButtonRole:
1324         return menuListAction;
1325     case MenuListPopupRole:
1326         return menuListPopupAction;
1327     case ListItemRole:
1328         return listItemAction;
1329     default:
1330         return nullAtom;
1331     }
1332 #else
1333     return nullAtom;
1334 #endif
1335 }
1336 #endif
1337
1338 bool AccessibilityObject::ariaIsMultiline() const
1339 {
1340     return equalIgnoringCase(getAttribute(aria_multilineAttr), "true");
1341 }
1342
1343 const AtomicString& AccessibilityObject::invalidStatus() const
1344 {
1345     DEFINE_STATIC_LOCAL(const AtomicString, invalidStatusFalse, ("false", AtomicString::ConstructFromLiteral));
1346     
1347     // aria-invalid can return false (default), grammer, spelling, or true.
1348     const AtomicString& ariaInvalid = getAttribute(aria_invalidAttr);
1349     
1350     // If empty or not present, it should return false.
1351     if (ariaInvalid.isEmpty())
1352         return invalidStatusFalse;
1353     
1354     return ariaInvalid;
1355 }
1356  
1357 bool AccessibilityObject::hasAttribute(const QualifiedName& attribute) const
1358 {
1359     Node* elementNode = node();
1360     if (!elementNode)
1361         return false;
1362     
1363     if (!elementNode->isElementNode())
1364         return false;
1365     
1366     Element* element = toElement(elementNode);
1367     return element->fastHasAttribute(attribute);
1368 }
1369     
1370 const AtomicString& AccessibilityObject::getAttribute(const QualifiedName& attribute) const
1371 {
1372     Node* elementNode = node();
1373     if (!elementNode)
1374         return nullAtom;
1375     
1376     if (!elementNode->isElementNode())
1377         return nullAtom;
1378     
1379     Element* element = toElement(elementNode);
1380     return element->fastGetAttribute(attribute);
1381 }
1382     
1383 // Lacking concrete evidence of orientation, horizontal means width > height. vertical is height > width;
1384 AccessibilityOrientation AccessibilityObject::orientation() const
1385 {
1386     LayoutRect bounds = elementRect();
1387     if (bounds.size().width() > bounds.size().height())
1388         return AccessibilityOrientationHorizontal;
1389     if (bounds.size().height() > bounds.size().width())
1390         return AccessibilityOrientationVertical;
1391
1392     // A tie goes to horizontal.
1393     return AccessibilityOrientationHorizontal;
1394 }    
1395
1396 bool AccessibilityObject::isDescendantOfObject(const AccessibilityObject* axObject) const
1397 {
1398     if (!axObject || !axObject->hasChildren())
1399         return false;
1400
1401     for (const AccessibilityObject* parent = parentObject(); parent; parent = parent->parentObject()) {
1402         if (parent == axObject)
1403             return true;
1404     }
1405     return false;
1406 }
1407
1408 bool AccessibilityObject::isAncestorOfObject(const AccessibilityObject* axObject) const
1409 {
1410     if (!axObject)
1411         return false;
1412
1413     return this == axObject || axObject->isDescendantOfObject(this);
1414 }
1415
1416 AccessibilityObject* AccessibilityObject::firstAnonymousBlockChild() const
1417 {
1418     for (AccessibilityObject* child = firstChild(); child; child = child->nextSibling()) {
1419         if (child->renderer() && child->renderer()->isAnonymousBlock())
1420             return child;
1421     }
1422     return 0;
1423 }
1424
1425 typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap;
1426
1427 struct RoleEntry {
1428     String ariaRole;
1429     AccessibilityRole webcoreRole;
1430 };
1431
1432 static ARIARoleMap* createARIARoleMap()
1433 {
1434     const RoleEntry roles[] = {
1435         { "alert", ApplicationAlertRole },
1436         { "alertdialog", ApplicationAlertDialogRole },
1437         { "application", LandmarkApplicationRole },
1438         { "article", DocumentArticleRole },
1439         { "banner", LandmarkBannerRole },
1440         { "button", ButtonRole },
1441         { "checkbox", CheckBoxRole },
1442         { "complementary", LandmarkComplementaryRole },
1443         { "contentinfo", LandmarkContentInfoRole },
1444         { "dialog", ApplicationDialogRole },
1445         { "directory", DirectoryRole },
1446         { "grid", TableRole },
1447         { "gridcell", CellRole },
1448         { "columnheader", ColumnHeaderRole },
1449         { "combobox", ComboBoxRole },
1450         { "definition", DefinitionRole },
1451         { "document", DocumentRole },
1452         { "rowheader", RowHeaderRole },
1453         { "group", GroupRole },
1454         { "heading", HeadingRole },
1455         { "img", ImageRole },
1456         { "link", WebCoreLinkRole },
1457         { "list", ListRole },        
1458         { "listitem", ListItemRole },        
1459         { "listbox", ListBoxRole },
1460         { "log", ApplicationLogRole },
1461         // "option" isn't here because it may map to different roles depending on the parent element's role
1462         { "main", LandmarkMainRole },
1463         { "marquee", ApplicationMarqueeRole },
1464         { "math", DocumentMathRole },
1465         { "menu", MenuRole },
1466         { "menubar", MenuBarRole },
1467         { "menuitem", MenuItemRole },
1468         { "menuitemcheckbox", MenuItemCheckboxRole },
1469         { "menuitemradio", MenuItemRadioRole },
1470         { "note", DocumentNoteRole },
1471         { "navigation", LandmarkNavigationRole },
1472         { "option", ListBoxOptionRole },
1473         { "presentation", PresentationalRole },
1474         { "progressbar", ProgressIndicatorRole },
1475         { "radio", RadioButtonRole },
1476         { "radiogroup", RadioGroupRole },
1477         { "region", DocumentRegionRole },
1478         { "row", RowRole },
1479         { "scrollbar", ScrollBarRole },
1480         { "search", LandmarkSearchRole },
1481         { "separator", SplitterRole },
1482         { "slider", SliderRole },
1483         { "spinbutton", SpinButtonRole },
1484         { "status", ApplicationStatusRole },
1485         { "tab", TabRole },
1486         { "tablist", TabListRole },
1487         { "tabpanel", TabPanelRole },
1488         { "text", StaticTextRole },
1489         { "textbox", TextAreaRole },
1490         { "timer", ApplicationTimerRole },
1491         { "toolbar", ToolbarRole },
1492         { "tooltip", UserInterfaceTooltipRole },
1493         { "tree", TreeRole },
1494         { "treegrid", TreeGridRole },
1495         { "treeitem", TreeItemRole }
1496     };
1497     ARIARoleMap* roleMap = new ARIARoleMap;
1498
1499     for (size_t i = 0; i < WTF_ARRAY_LENGTH(roles); ++i)
1500         roleMap->set(roles[i].ariaRole, roles[i].webcoreRole);
1501     return roleMap;
1502 }
1503
1504 AccessibilityRole AccessibilityObject::ariaRoleToWebCoreRole(const String& value)
1505 {
1506     ASSERT(!value.isEmpty());
1507     
1508     static const ARIARoleMap* roleMap = createARIARoleMap();
1509
1510     Vector<String> roleVector;
1511     value.split(' ', roleVector);
1512     AccessibilityRole role = UnknownRole;
1513     unsigned size = roleVector.size();
1514     for (unsigned i = 0; i < size; ++i) {
1515         String roleName = roleVector[i];
1516         role = roleMap->get(roleName);
1517         if (role)
1518             return role;
1519     }
1520     
1521     return role;
1522 }
1523
1524 bool AccessibilityObject::hasHighlighting() const
1525 {
1526     for (Node* node = this->node(); node; node = node->parentNode()) {
1527         if (node->hasTagName(markTag))
1528             return true;
1529     }
1530     
1531     return false;
1532 }
1533
1534 const AtomicString& AccessibilityObject::placeholderValue() const
1535 {
1536     const AtomicString& placeholder = getAttribute(placeholderAttr);
1537     if (!placeholder.isEmpty())
1538         return placeholder;
1539     
1540     return nullAtom;
1541 }
1542     
1543 bool AccessibilityObject::isInsideARIALiveRegion() const
1544 {
1545     if (supportsARIALiveRegion())
1546         return true;
1547     
1548     for (AccessibilityObject* axParent = parentObject(); axParent; axParent = axParent->parentObject()) {
1549         if (axParent->supportsARIALiveRegion())
1550             return true;
1551     }
1552     
1553     return false;
1554 }
1555
1556 bool AccessibilityObject::supportsARIAAttributes() const
1557 {
1558     // This returns whether the element supports any global ARIA attributes.
1559     return supportsARIALiveRegion()
1560         || supportsARIADragging()
1561         || supportsARIADropping()
1562         || supportsARIAFlowTo()
1563         || supportsARIAOwns()
1564         || hasAttribute(aria_atomicAttr)
1565         || hasAttribute(aria_busyAttr)
1566         || hasAttribute(aria_controlsAttr)
1567         || hasAttribute(aria_describedbyAttr)
1568         || hasAttribute(aria_disabledAttr)
1569         || hasAttribute(aria_haspopupAttr)
1570         || hasAttribute(aria_invalidAttr)
1571         || hasAttribute(aria_labelAttr)
1572         || hasAttribute(aria_labelledbyAttr)
1573         || hasAttribute(aria_relevantAttr);
1574 }
1575     
1576 bool AccessibilityObject::supportsARIALiveRegion() const
1577 {
1578     const AtomicString& liveRegion = ariaLiveRegionStatus();
1579     return equalIgnoringCase(liveRegion, "polite") || equalIgnoringCase(liveRegion, "assertive");
1580 }
1581
1582 AccessibilityObject* AccessibilityObject::elementAccessibilityHitTest(const IntPoint& point) const
1583
1584     // Send the hit test back into the sub-frame if necessary.
1585     if (isAttachment()) {
1586         Widget* widget = widgetForAttachmentView();
1587         // Normalize the point for the widget's bounds.
1588         if (widget && widget->isFrameView())
1589             return axObjectCache()->getOrCreate(widget)->accessibilityHitTest(IntPoint(point - widget->frameRect().location()));
1590     }
1591     
1592     // Check if there are any mock elements that need to be handled.
1593     size_t count = m_children.size();
1594     for (size_t k = 0; k < count; k++) {
1595         if (m_children[k]->isMockObject() && m_children[k]->elementRect().contains(point))
1596             return m_children[k]->elementAccessibilityHitTest(point);
1597     }
1598
1599     return const_cast<AccessibilityObject*>(this); 
1600 }
1601     
1602 AXObjectCache* AccessibilityObject::axObjectCache() const
1603 {
1604     Document* doc = document();
1605     if (doc)
1606         return doc->axObjectCache();
1607     return 0;
1608 }
1609     
1610 AccessibilityObject* AccessibilityObject::focusedUIElement() const
1611 {
1612     Document* doc = document();
1613     if (!doc)
1614         return 0;
1615     
1616     Page* page = doc->page();
1617     if (!page)
1618         return 0;
1619     
1620     return AXObjectCache::focusedUIElementForPage(page);
1621 }
1622     
1623 AccessibilitySortDirection AccessibilityObject::sortDirection() const
1624 {
1625     const AtomicString& sortAttribute = getAttribute(aria_sortAttr);
1626     if (equalIgnoringCase(sortAttribute, "ascending"))
1627         return SortDirectionAscending;
1628     if (equalIgnoringCase(sortAttribute, "descending"))
1629         return SortDirectionDescending;
1630     if (equalIgnoringCase(sortAttribute, "other"))
1631         return SortDirectionOther;
1632     
1633     return SortDirectionNone;
1634 }
1635
1636 bool AccessibilityObject::supportsRangeValue() const
1637 {
1638     return isProgressIndicator()
1639         || isSlider()
1640         || isScrollbar()
1641         || isSpinButton();
1642 }
1643     
1644 bool AccessibilityObject::supportsARIASetSize() const
1645 {
1646     return hasAttribute(aria_setsizeAttr);
1647 }
1648
1649 bool AccessibilityObject::supportsARIAPosInSet() const
1650 {
1651     return hasAttribute(aria_posinsetAttr);
1652 }
1653     
1654 int AccessibilityObject::ariaSetSize() const
1655 {
1656     return getAttribute(aria_setsizeAttr).toInt();
1657 }
1658
1659 int AccessibilityObject::ariaPosInSet() const
1660 {
1661     return getAttribute(aria_posinsetAttr).toInt();
1662 }
1663     
1664 String AccessibilityObject::identifierAttribute() const
1665 {
1666     return getAttribute(idAttr);
1667 }
1668     
1669 void AccessibilityObject::classList(Vector<String>& classList) const
1670 {
1671     Node* node = this->node();
1672     if (!node || !node->isElementNode())
1673         return;
1674     
1675     Element* element = toElement(node);
1676     DOMTokenList* list = element->classList();
1677     if (!list)
1678         return;
1679     unsigned length = list->length();
1680     for (unsigned k = 0; k < length; k++)
1681         classList.append(list->item(k).string());
1682 }
1683
1684     
1685 bool AccessibilityObject::supportsARIAExpanded() const
1686 {
1687     // Undefined values should not result in this attribute being exposed to ATs according to ARIA.
1688     const AtomicString& expanded = getAttribute(aria_expandedAttr);
1689     return equalIgnoringCase(expanded, "true") || equalIgnoringCase(expanded, "false");
1690 }
1691     
1692 bool AccessibilityObject::isExpanded() const
1693 {
1694     if (equalIgnoringCase(getAttribute(aria_expandedAttr), "true"))
1695         return true;
1696     
1697     return false;  
1698 }
1699     
1700 AccessibilityButtonState AccessibilityObject::checkboxOrRadioValue() const
1701 {
1702     // If this is a real checkbox or radio button, AccessibilityRenderObject will handle.
1703     // If it's an ARIA checkbox or radio, the aria-checked attribute should be used.
1704
1705     const AtomicString& result = getAttribute(aria_checkedAttr);
1706     if (equalIgnoringCase(result, "true"))
1707         return ButtonStateOn;
1708     if (equalIgnoringCase(result, "mixed")) {
1709         // ARIA says that radio and menuitemradio elements must NOT expose button state mixed.
1710         AccessibilityRole ariaRole = ariaRoleAttribute();
1711         if (ariaRole == RadioButtonRole || ariaRole == MenuItemRadioRole)
1712             return ButtonStateOff;
1713         return ButtonStateMixed;
1714     }
1715     
1716     return ButtonStateOff;
1717 }
1718
1719 // This is a 1-dimensional scroll offset helper function that's applied
1720 // separately in the horizontal and vertical directions, because the
1721 // logic is the same. The goal is to compute the best scroll offset
1722 // in order to make an object visible within a viewport.
1723 //
1724 // In case the whole object cannot fit, you can specify a
1725 // subfocus - a smaller region within the object that should
1726 // be prioritized. If the whole object can fit, the subfocus is
1727 // ignored.
1728 //
1729 // Example: the viewport is scrolled to the right just enough
1730 // that the object is in view.
1731 //   Before:
1732 //   +----------Viewport---------+
1733 //                         +---Object---+
1734 //                         +--SubFocus--+
1735 //
1736 //   After:
1737 //          +----------Viewport---------+
1738 //                         +---Object---+
1739 //                         +--SubFocus--+
1740 //
1741 // When constraints cannot be fully satisfied, the min
1742 // (left/top) position takes precedence over the max (right/bottom).
1743 //
1744 // Note that the return value represents the ideal new scroll offset.
1745 // This may be out of range - the calling function should clip this
1746 // to the available range.
1747 static int computeBestScrollOffset(int currentScrollOffset,
1748                                    int subfocusMin, int subfocusMax,
1749                                    int objectMin, int objectMax,
1750                                    int viewportMin, int viewportMax) {
1751     int viewportSize = viewportMax - viewportMin;
1752
1753     // If the focus size is larger than the viewport size, shrink it in the
1754     // direction of subfocus.
1755     if (objectMax - objectMin > viewportSize) {
1756         // Subfocus must be within focus:
1757         subfocusMin = std::max(subfocusMin, objectMin);
1758         subfocusMax = std::min(subfocusMax, objectMax);
1759
1760         // Subfocus must be no larger than the viewport size; favor top/left.
1761         if (subfocusMax - subfocusMin > viewportSize)
1762             subfocusMax = subfocusMin + viewportSize;
1763
1764         if (subfocusMin + viewportSize > objectMax)
1765             objectMin = objectMax - viewportSize;
1766         else {
1767             objectMin = subfocusMin;
1768             objectMax = subfocusMin + viewportSize;
1769         }
1770     }
1771
1772     // Exit now if the focus is already within the viewport.
1773     if (objectMin - currentScrollOffset >= viewportMin
1774         && objectMax - currentScrollOffset <= viewportMax)
1775         return currentScrollOffset;
1776
1777     // Scroll left if we're too far to the right.
1778     if (objectMax - currentScrollOffset > viewportMax)
1779         return objectMax - viewportMax;
1780
1781     // Scroll right if we're too far to the left.
1782     if (objectMin - currentScrollOffset < viewportMin)
1783         return objectMin - viewportMin;
1784
1785     ASSERT_NOT_REACHED();
1786
1787     // This shouldn't happen.
1788     return currentScrollOffset;
1789 }
1790
1791 bool AccessibilityObject::isOnscreen() const
1792 {   
1793     bool isOnscreen = true;
1794
1795     // To figure out if the element is onscreen, we start by building of a stack starting with the
1796     // element, and then include every scrollable parent in the hierarchy.
1797     Vector<const AccessibilityObject*> objects;
1798     
1799     objects.append(this);
1800     for (AccessibilityObject* parentObject = this->parentObject(); parentObject; parentObject = parentObject->parentObject()) {
1801         if (parentObject->getScrollableAreaIfScrollable())
1802             objects.append(parentObject);
1803     }
1804
1805     // Now, go back through that chain and make sure each inner object is within the
1806     // visible bounds of the outer object.
1807     size_t levels = objects.size() - 1;
1808     
1809     for (size_t i = levels; i >= 1; i--) {
1810         const AccessibilityObject* outer = objects[i];
1811         const AccessibilityObject* inner = objects[i - 1];
1812         const IntRect outerRect = i < levels ? pixelSnappedIntRect(outer->boundingBoxRect()) : outer->getScrollableAreaIfScrollable()->visibleContentRect();
1813         const IntRect innerRect = pixelSnappedIntRect(inner->isAccessibilityScrollView() ? inner->parentObject()->boundingBoxRect() : inner->boundingBoxRect());
1814         
1815         if (!outerRect.intersects(innerRect)) {
1816             isOnscreen = false;
1817             break;
1818         }
1819     }
1820     
1821     return isOnscreen;
1822 }
1823
1824 void AccessibilityObject::scrollToMakeVisible() const
1825 {
1826     IntRect objectRect = pixelSnappedIntRect(boundingBoxRect());
1827     objectRect.setLocation(IntPoint());
1828     scrollToMakeVisibleWithSubFocus(objectRect);
1829 }
1830
1831 void AccessibilityObject::scrollToMakeVisibleWithSubFocus(const IntRect& subfocus) const
1832 {
1833     // Search up the parent chain until we find the first one that's scrollable.
1834     AccessibilityObject* scrollParent = parentObject();
1835     ScrollableArea* scrollableArea;
1836     for (scrollableArea = 0;
1837          scrollParent && !(scrollableArea = scrollParent->getScrollableAreaIfScrollable());
1838          scrollParent = scrollParent->parentObject()) { }
1839     if (!scrollableArea)
1840         return;
1841
1842     LayoutRect objectRect = boundingBoxRect();
1843     IntPoint scrollPosition = scrollableArea->scrollPosition();
1844     IntRect scrollVisibleRect = scrollableArea->visibleContentRect();
1845
1846     int desiredX = computeBestScrollOffset(
1847         scrollPosition.x(),
1848         objectRect.x() + subfocus.x(), objectRect.x() + subfocus.maxX(),
1849         objectRect.x(), objectRect.maxX(),
1850         0, scrollVisibleRect.width());
1851     int desiredY = computeBestScrollOffset(
1852         scrollPosition.y(),
1853         objectRect.y() + subfocus.y(), objectRect.y() + subfocus.maxY(),
1854         objectRect.y(), objectRect.maxY(),
1855         0, scrollVisibleRect.height());
1856
1857     scrollParent->scrollTo(IntPoint(desiredX, desiredY));
1858
1859     // Recursively make sure the scroll parent itself is visible.
1860     if (scrollParent->parentObject())
1861         scrollParent->scrollToMakeVisible();
1862 }
1863
1864 void AccessibilityObject::scrollToGlobalPoint(const IntPoint& globalPoint) const
1865 {
1866     // Search up the parent chain and create a vector of all scrollable parent objects
1867     // and ending with this object itself.
1868     Vector<const AccessibilityObject*> objects;
1869
1870     objects.append(this);
1871     for (AccessibilityObject* parentObject = this->parentObject(); parentObject; parentObject = parentObject->parentObject()) {
1872         if (parentObject->getScrollableAreaIfScrollable())
1873             objects.append(parentObject);
1874     }
1875
1876     objects.reverse();
1877
1878     // Start with the outermost scrollable (the main window) and try to scroll the
1879     // next innermost object to the given point.
1880     int offsetX = 0, offsetY = 0;
1881     IntPoint point = globalPoint;
1882     size_t levels = objects.size() - 1;
1883     for (size_t i = 0; i < levels; i++) {
1884         const AccessibilityObject* outer = objects[i];
1885         const AccessibilityObject* inner = objects[i + 1];
1886
1887         ScrollableArea* scrollableArea = outer->getScrollableAreaIfScrollable();
1888
1889         LayoutRect innerRect = inner->isAccessibilityScrollView() ? inner->parentObject()->boundingBoxRect() : inner->boundingBoxRect();
1890         LayoutRect objectRect = innerRect;
1891         IntPoint scrollPosition = scrollableArea->scrollPosition();
1892
1893         // Convert the object rect into local coordinates.
1894         objectRect.move(offsetX, offsetY);
1895         if (!outer->isAccessibilityScrollView())
1896             objectRect.move(scrollPosition.x(), scrollPosition.y());
1897
1898         int desiredX = computeBestScrollOffset(
1899             0,
1900             objectRect.x(), objectRect.maxX(),
1901             objectRect.x(), objectRect.maxX(),
1902             point.x(), point.x());
1903         int desiredY = computeBestScrollOffset(
1904             0,
1905             objectRect.y(), objectRect.maxY(),
1906             objectRect.y(), objectRect.maxY(),
1907             point.y(), point.y());
1908         outer->scrollTo(IntPoint(desiredX, desiredY));
1909
1910         if (outer->isAccessibilityScrollView() && !inner->isAccessibilityScrollView()) {
1911             // If outer object we just scrolled is a scroll view (main window or iframe) but the
1912             // inner object is not, keep track of the coordinate transformation to apply to
1913             // future nested calculations.
1914             scrollPosition = scrollableArea->scrollPosition();
1915             offsetX -= (scrollPosition.x() + point.x());
1916             offsetY -= (scrollPosition.y() + point.y());
1917             point.move(scrollPosition.x() - innerRect.x(),
1918                        scrollPosition.y() - innerRect.y());
1919         } else if (inner->isAccessibilityScrollView()) {
1920             // Otherwise, if the inner object is a scroll view, reset the coordinate transformation.
1921             offsetX = 0;
1922             offsetY = 0;
1923         }
1924     }
1925 }
1926
1927 bool AccessibilityObject::lastKnownIsIgnoredValue()
1928 {
1929     if (m_lastKnownIsIgnoredValue == DefaultBehavior)
1930         m_lastKnownIsIgnoredValue = accessibilityIsIgnored() ? IgnoreObject : IncludeObject;
1931
1932     return m_lastKnownIsIgnoredValue == IgnoreObject;
1933 }
1934
1935 void AccessibilityObject::setLastKnownIsIgnoredValue(bool isIgnored)
1936 {
1937     m_lastKnownIsIgnoredValue = isIgnored ? IgnoreObject : IncludeObject;
1938 }
1939
1940 void AccessibilityObject::notifyIfIgnoredValueChanged()
1941 {
1942     bool isIgnored = accessibilityIsIgnored();
1943     if (lastKnownIsIgnoredValue() != isIgnored) {
1944         axObjectCache()->childrenChanged(parentObject());
1945         setLastKnownIsIgnoredValue(isIgnored);
1946     }
1947 }
1948
1949 bool AccessibilityObject::ariaPressedIsPresent() const
1950 {
1951     return !getAttribute(aria_pressedAttr).isEmpty();
1952 }
1953
1954 TextIteratorBehavior AccessibilityObject::textIteratorBehaviorForTextRange() const
1955 {
1956     TextIteratorBehavior behavior = TextIteratorIgnoresStyleVisibility;
1957     
1958 #if PLATFORM(GTK)
1959     // We need to emit replaced elements for GTK, and present
1960     // them with the 'object replacement character' (0xFFFC).
1961     behavior = static_cast<TextIteratorBehavior>(behavior | TextIteratorEmitsObjectReplacementCharacters);
1962 #endif
1963     
1964     return behavior;
1965 }
1966     
1967 AccessibilityRole AccessibilityObject::buttonRoleType() const
1968 {
1969     // If aria-pressed is present, then it should be exposed as a toggle button.
1970     // http://www.w3.org/TR/wai-aria/states_and_properties#aria-pressed
1971     if (ariaPressedIsPresent())
1972         return ToggleButtonRole;
1973     if (ariaHasPopup())
1974         return PopUpButtonRole;
1975     // We don't contemplate RadioButtonRole, as it depends on the input
1976     // type.
1977
1978     return ButtonRole;
1979 }
1980
1981 bool AccessibilityObject::isButton() const
1982 {
1983     AccessibilityRole role = roleValue();
1984
1985     return role == ButtonRole || role == PopUpButtonRole || role == ToggleButtonRole;
1986 }
1987
1988 bool AccessibilityObject::accessibilityIsIgnoredByDefault() const
1989 {
1990     return defaultObjectInclusion() == IgnoreObject;
1991 }
1992
1993 bool AccessibilityObject::ariaIsHidden() const
1994 {
1995     if (equalIgnoringCase(getAttribute(aria_hiddenAttr), "true"))
1996         return true;
1997     
1998     for (AccessibilityObject* object = parentObject(); object; object = object->parentObject()) {
1999         if (equalIgnoringCase(object->getAttribute(aria_hiddenAttr), "true"))
2000             return true;
2001     }
2002     
2003     return false;
2004 }
2005
2006 AccessibilityObjectInclusion AccessibilityObject::defaultObjectInclusion() const
2007 {
2008     if (ariaIsHidden())
2009         return IgnoreObject;
2010     
2011     if (isPresentationalChildOfAriaRole())
2012         return IgnoreObject;
2013     
2014     return accessibilityPlatformIncludesObject();
2015 }
2016     
2017 bool AccessibilityObject::accessibilityIsIgnored() const
2018 {
2019     AXComputedObjectAttributeCache* attributeCache = axObjectCache()->computedObjectAttributeCache();
2020     if (attributeCache) {
2021         AccessibilityObjectInclusion ignored = attributeCache->getIgnored(axObjectID());
2022         switch (ignored) {
2023         case IgnoreObject:
2024             return true;
2025         case IncludeObject:
2026             return false;
2027         case DefaultBehavior:
2028             break;
2029         }
2030     }
2031
2032     bool result = computeAccessibilityIsIgnored();
2033
2034     if (attributeCache)
2035         attributeCache->setIgnored(axObjectID(), result ? IgnoreObject : IncludeObject);
2036
2037     return result;
2038 }
2039
2040 } // namespace WebCore