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