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