1/*
2* Copyright (C) 2008 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 "AccessibilityRenderObject.h"
31
32#include "AXObjectCache.h"
33#include "AccessibilityImageMapLink.h"
34#include "AccessibilityListBox.h"
35#include "EventNames.h"
36#include "FloatRect.h"
37#include "Frame.h"
38#include "FrameLoader.h"
39#include "HTMLAreaElement.h"
40#include "HTMLFormElement.h"
41#include "HTMLFrameElementBase.h"
42#include "HTMLImageElement.h"
43#include "HTMLInputElement.h"
44#include "HTMLLabelElement.h"
45#include "HTMLMapElement.h"
46#include "HTMLOptGroupElement.h"
47#include "HTMLOptionElement.h"
48#include "HTMLOptionsCollection.h"
49#include "HTMLSelectElement.h"
50#include "HTMLTextAreaElement.h"
51#include "HitTestRequest.h"
52#include "HitTestResult.h"
53#include "LocalizedStrings.h"
54#include "MathMLNames.h"
55#include "NodeList.h"
56#include "ProgressTracker.h"
57#include "RenderButton.h"
58#include "RenderFieldset.h"
59#include "RenderFileUploadControl.h"
60#include "RenderHTMLCanvas.h"
61#include "RenderImage.h"
62#include "RenderInline.h"
63#include "RenderLayer.h"
64#include "RenderListBox.h"
65#include "RenderListMarker.h"
66#include "RenderMenuList.h"
67#include "RenderText.h"
68#include "RenderTextControl.h"
69#include "RenderTextFragment.h"
70#include "RenderTheme.h"
71#include "RenderView.h"
72#include "RenderWidget.h"
73#include "SelectElement.h"
74#include "SelectionController.h"
75#include "Text.h"
76#include "TextIterator.h"
77#include "htmlediting.h"
78#include "visible_units.h"
79#include <wtf/StdLibExtras.h>
80#include <wtf/text/StringBuilder.h>
81#include <wtf/unicode/CharacterNames.h>
82
83using namespace std;
84
85namespace WebCore {
86
87using namespace HTMLNames;
88
89AccessibilityRenderObject::AccessibilityRenderObject(RenderObject* renderer)
90    : AccessibilityObject()
91    , m_renderer(renderer)
92    , m_ariaRole(UnknownRole)
93    , m_childrenDirty(false)
94    , m_roleForMSAA(UnknownRole)
95{
96    m_role = determineAccessibilityRole();
97
98#ifndef NDEBUG
99    m_renderer->setHasAXObject(true);
100#endif
101}
102
103AccessibilityRenderObject::~AccessibilityRenderObject()
104{
105    ASSERT(isDetached());
106}
107
108PassRefPtr<AccessibilityRenderObject> AccessibilityRenderObject::create(RenderObject* renderer)
109{
110    return adoptRef(new AccessibilityRenderObject(renderer));
111}
112
113void AccessibilityRenderObject::detach()
114{
115    clearChildren();
116    AccessibilityObject::detach();
117
118#ifndef NDEBUG
119    if (m_renderer)
120        m_renderer->setHasAXObject(false);
121#endif
122    m_renderer = 0;
123}
124
125RenderBoxModelObject* AccessibilityRenderObject::renderBoxModelObject() const
126{
127    if (!m_renderer || !m_renderer->isBoxModelObject())
128        return 0;
129    return toRenderBoxModelObject(m_renderer);
130}
131
132static inline bool isInlineWithContinuation(RenderObject* object)
133{
134    if (!object->isBoxModelObject())
135        return false;
136
137    RenderBoxModelObject* renderer = toRenderBoxModelObject(object);
138    if (!renderer->isRenderInline())
139        return false;
140
141    return toRenderInline(renderer)->continuation();
142}
143
144static inline RenderObject* firstChildInContinuation(RenderObject* renderer)
145{
146    RenderObject* r = toRenderInline(renderer)->continuation();
147
148    while (r) {
149        if (r->isRenderBlock())
150            return r;
151        if (RenderObject* child = r->firstChild())
152            return child;
153        r = toRenderInline(r)->continuation();
154    }
155
156    return 0;
157}
158
159static inline RenderObject* firstChildConsideringContinuation(RenderObject* renderer)
160{
161    RenderObject* firstChild = renderer->firstChild();
162
163    if (!firstChild && isInlineWithContinuation(renderer))
164        firstChild = firstChildInContinuation(renderer);
165
166    return firstChild;
167}
168
169
170static inline RenderObject* lastChildConsideringContinuation(RenderObject* renderer)
171{
172    RenderObject* lastChild = renderer->lastChild();
173    RenderObject* prev;
174    RenderObject* cur = renderer;
175
176    if (!cur->isRenderInline() && !cur->isRenderBlock())
177        return renderer;
178
179    while (cur) {
180        prev = cur;
181
182        if (RenderObject* lc = cur->lastChild())
183            lastChild = lc;
184
185        if (cur->isRenderInline()) {
186            cur = toRenderInline(cur)->inlineElementContinuation();
187            ASSERT(cur || !toRenderInline(prev)->continuation());
188        } else
189            cur = toRenderBlock(cur)->inlineElementContinuation();
190    }
191
192    return lastChild;
193}
194
195AccessibilityObject* AccessibilityRenderObject::firstChild() const
196{
197    if (!m_renderer)
198        return 0;
199
200    RenderObject* firstChild = firstChildConsideringContinuation(m_renderer);
201
202    if (!firstChild)
203        return 0;
204
205    return axObjectCache()->getOrCreate(firstChild);
206}
207
208AccessibilityObject* AccessibilityRenderObject::lastChild() const
209{
210    if (!m_renderer)
211        return 0;
212
213    RenderObject* lastChild = lastChildConsideringContinuation(m_renderer);
214
215    if (!lastChild)
216        return 0;
217
218    return axObjectCache()->getOrCreate(lastChild);
219}
220
221static inline RenderInline* startOfContinuations(RenderObject* r)
222{
223    if (r->isInlineElementContinuation())
224        return toRenderInline(r->node()->renderer());
225
226    // Blocks with a previous continuation always have a next continuation
227    if (r->isRenderBlock() && toRenderBlock(r)->inlineElementContinuation())
228        return toRenderInline(toRenderBlock(r)->inlineElementContinuation()->node()->renderer());
229
230    return 0;
231}
232
233static inline RenderObject* endOfContinuations(RenderObject* renderer)
234{
235    RenderObject* prev = renderer;
236    RenderObject* cur = renderer;
237
238    if (!cur->isRenderInline() && !cur->isRenderBlock())
239        return renderer;
240
241    while (cur) {
242        prev = cur;
243        if (cur->isRenderInline()) {
244            cur = toRenderInline(cur)->inlineElementContinuation();
245            ASSERT(cur || !toRenderInline(prev)->continuation());
246        } else
247            cur = toRenderBlock(cur)->inlineElementContinuation();
248    }
249
250    return prev;
251}
252
253
254static inline RenderObject* childBeforeConsideringContinuations(RenderInline* r, RenderObject* child)
255{
256    RenderBoxModelObject* curContainer = r;
257    RenderObject* cur = 0;
258    RenderObject* prev = 0;
259
260    while (curContainer) {
261        if (curContainer->isRenderInline()) {
262            cur = curContainer->firstChild();
263            while (cur) {
264                if (cur == child)
265                    return prev;
266                prev = cur;
267                cur = cur->nextSibling();
268            }
269
270            curContainer = toRenderInline(curContainer)->continuation();
271        } else if (curContainer->isRenderBlock()) {
272            if (curContainer == child)
273                return prev;
274
275            prev = curContainer;
276            curContainer = toRenderBlock(curContainer)->inlineElementContinuation();
277        }
278    }
279
280    ASSERT_NOT_REACHED();
281
282    return 0;
283}
284
285static inline bool firstChildIsInlineContinuation(RenderObject* renderer)
286{
287    return renderer->firstChild() && renderer->firstChild()->isInlineElementContinuation();
288}
289
290AccessibilityObject* AccessibilityRenderObject::previousSibling() const
291{
292    if (!m_renderer)
293        return 0;
294
295    RenderObject* previousSibling = 0;
296
297    // Case 1: The node is a block and is an inline's continuation. In that case, the inline's
298    // last child is our previous sibling (or further back in the continuation chain)
299    RenderInline* startOfConts;
300    if (m_renderer->isRenderBlock() && (startOfConts = startOfContinuations(m_renderer)))
301        previousSibling = childBeforeConsideringContinuations(startOfConts, m_renderer);
302
303    // Case 2: Anonymous block parent of the end of a continuation - skip all the way to before
304    // the parent of the start, since everything in between will be linked up via the continuation.
305    else if (m_renderer->isAnonymousBlock() && firstChildIsInlineContinuation(m_renderer))
306        previousSibling = startOfContinuations(m_renderer->firstChild())->parent()->previousSibling();
307
308    // Case 3: The node has an actual previous sibling
309    else if (RenderObject* ps = m_renderer->previousSibling())
310        previousSibling = ps;
311
312    // Case 4: This node has no previous siblings, but its parent is an inline,
313    // and is another node's inline continutation. Follow the continuation chain.
314    else if (m_renderer->parent()->isRenderInline() && (startOfConts = startOfContinuations(m_renderer->parent())))
315        previousSibling = childBeforeConsideringContinuations(startOfConts, m_renderer->parent()->firstChild());
316
317    if (!previousSibling)
318        return 0;
319
320    return axObjectCache()->getOrCreate(previousSibling);
321}
322
323static inline bool lastChildHasContinuation(RenderObject* renderer)
324{
325    return renderer->lastChild() && isInlineWithContinuation(renderer->lastChild());
326}
327
328AccessibilityObject* AccessibilityRenderObject::nextSibling() const
329{
330    if (!m_renderer)
331        return 0;
332
333    RenderObject* nextSibling = 0;
334
335    // Case 1: node is a block and has an inline continuation. Next sibling is the inline continuation's
336    // first child.
337    RenderInline* inlineContinuation;
338    if (m_renderer->isRenderBlock() && (inlineContinuation = toRenderBlock(m_renderer)->inlineElementContinuation()))
339        nextSibling = firstChildConsideringContinuation(inlineContinuation);
340
341    // Case 2: Anonymous block parent of the start of a continuation - skip all the way to
342    // after the parent of the end, since everything in between will be linked up via the continuation.
343    else if (m_renderer->isAnonymousBlock() && lastChildHasContinuation(m_renderer))
344        nextSibling = endOfContinuations(m_renderer->lastChild())->parent()->nextSibling();
345
346    // Case 3: node has an actual next sibling
347    else if (RenderObject* ns = m_renderer->nextSibling())
348        nextSibling = ns;
349
350    // Case 4: node is an inline with a continuation. Next sibling is the next sibling of the end
351    // of the continuation chain.
352    else if (isInlineWithContinuation(m_renderer))
353        nextSibling = endOfContinuations(m_renderer)->nextSibling();
354
355    // Case 5: node has no next sibling, and its parent is an inline with a continuation.
356    else if (isInlineWithContinuation(m_renderer->parent())) {
357        RenderObject* continuation = toRenderInline(m_renderer->parent())->continuation();
358
359        // Case 5a: continuation is a block - in this case the block itself is the next sibling.
360        if (continuation->isRenderBlock())
361            nextSibling = continuation;
362        // Case 5b: continuation is an inline - in this case the inline's first child is the next sibling
363        else
364            nextSibling = firstChildConsideringContinuation(continuation);
365    }
366
367    if (!nextSibling)
368        return 0;
369
370    return axObjectCache()->getOrCreate(nextSibling);
371}
372
373static RenderBoxModelObject* nextContinuation(RenderObject* renderer)
374{
375    ASSERT(renderer);
376    if (renderer->isRenderInline() && !renderer->isReplaced())
377        return toRenderInline(renderer)->continuation();
378    if (renderer->isRenderBlock())
379        return toRenderBlock(renderer)->inlineElementContinuation();
380    return 0;
381}
382
383RenderObject* AccessibilityRenderObject::renderParentObject() const
384{
385    if (!m_renderer)
386        return 0;
387
388    RenderObject* parent = m_renderer->parent();
389
390    // Case 1: node is a block and is an inline's continuation. Parent
391    // is the start of the continuation chain.
392    RenderObject* startOfConts = 0;
393    RenderObject* firstChild = 0;
394    if (m_renderer->isRenderBlock() && (startOfConts = startOfContinuations(m_renderer)))
395        parent = startOfConts;
396
397    // Case 2: node's parent is an inline which is some node's continuation; parent is
398    // the earliest node in the continuation chain.
399    else if (parent && parent->isRenderInline() && (startOfConts = startOfContinuations(parent)))
400        parent = startOfConts;
401
402    // Case 3: The first sibling is the beginning of a continuation chain. Find the origin of that continuation.
403    else if (parent && (firstChild = parent->firstChild()) && firstChild->node()) {
404        // Get the node's renderer and follow that continuation chain until the first child is found
405        RenderObject* nodeRenderFirstChild = firstChild->node()->renderer();
406        if (nodeRenderFirstChild != firstChild) {
407            for (RenderObject* contsTest = nodeRenderFirstChild; contsTest; contsTest = nextContinuation(contsTest)) {
408                if (contsTest == firstChild) {
409                    parent = nodeRenderFirstChild->parent();
410                    break;
411                }
412            }
413        }
414    }
415
416    return parent;
417}
418
419AccessibilityObject* AccessibilityRenderObject::parentObjectIfExists() const
420{
421    return axObjectCache()->get(renderParentObject());
422}
423
424AccessibilityObject* AccessibilityRenderObject::parentObject() const
425{
426    if (!m_renderer)
427        return 0;
428
429    if (ariaRoleAttribute() == MenuBarRole)
430        return axObjectCache()->getOrCreate(m_renderer->parent());
431
432    // menuButton and its corresponding menu are DOM siblings, but Accessibility needs them to be parent/child
433    if (ariaRoleAttribute() == MenuRole) {
434        AccessibilityObject* parent = menuButtonForMenu();
435        if (parent)
436            return parent;
437    }
438
439    RenderObject* parentObj = renderParentObject();
440    if (parentObj)
441        return axObjectCache()->getOrCreate(parentObj);
442
443    // WebArea's parent should be the scroll view containing it.
444    if (isWebArea())
445        return axObjectCache()->getOrCreate(m_renderer->frame()->view());
446
447    return 0;
448}
449
450bool AccessibilityRenderObject::isWebArea() const
451{
452    return roleValue() == WebAreaRole;
453}
454
455bool AccessibilityRenderObject::isImageButton() const
456{
457    return isNativeImage() && roleValue() == ButtonRole;
458}
459
460bool AccessibilityRenderObject::isAnchor() const
461{
462    return !isNativeImage() && isLink();
463}
464
465bool AccessibilityRenderObject::isNativeTextControl() const
466{
467    return m_renderer->isTextControl();
468}
469
470bool AccessibilityRenderObject::isNativeImage() const
471{
472    return m_renderer->isBoxModelObject() && toRenderBoxModelObject(m_renderer)->isImage();
473}
474
475bool AccessibilityRenderObject::isImage() const
476{
477    return roleValue() == ImageRole;
478}
479
480bool AccessibilityRenderObject::isAttachment() const
481{
482    RenderBoxModelObject* renderer = renderBoxModelObject();
483    if (!renderer)
484        return false;
485    // Widgets are the replaced elements that we represent to AX as attachments
486    bool isWidget = renderer->isWidget();
487    ASSERT(!isWidget || (renderer->isReplaced() && !isImage()));
488    return isWidget && ariaRoleAttribute() == UnknownRole;
489}
490
491bool AccessibilityRenderObject::isPasswordField() const
492{
493    ASSERT(m_renderer);
494    if (!m_renderer->node() || !m_renderer->node()->isHTMLElement())
495        return false;
496    if (ariaRoleAttribute() != UnknownRole)
497        return false;
498
499    InputElement* inputElement = m_renderer->node()->toInputElement();
500    if (!inputElement)
501        return false;
502
503    return inputElement->isPasswordField();
504}
505
506bool AccessibilityRenderObject::isFileUploadButton() const
507{
508    if (m_renderer && m_renderer->node() && m_renderer->node()->hasTagName(inputTag)) {
509        HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->node());
510        return input->isFileUpload();
511    }
512
513    return false;
514}
515
516bool AccessibilityRenderObject::isInputImage() const
517{
518    Node* elementNode = node();
519    if (roleValue() == ButtonRole && elementNode && elementNode->hasTagName(inputTag)) {
520        HTMLInputElement* input = static_cast<HTMLInputElement*>(elementNode);
521        return input->isImageButton();
522    }
523
524    return false;
525}
526
527bool AccessibilityRenderObject::isProgressIndicator() const
528{
529    return roleValue() == ProgressIndicatorRole;
530}
531
532bool AccessibilityRenderObject::isSlider() const
533{
534    return roleValue() == SliderRole;
535}
536
537bool AccessibilityRenderObject::isMenuRelated() const
538{
539    AccessibilityRole role = roleValue();
540    return role == MenuRole
541        || role == MenuBarRole
542        || role == MenuButtonRole
543        || role == MenuItemRole;
544}
545
546bool AccessibilityRenderObject::isMenu() const
547{
548    return roleValue() == MenuRole;
549}
550
551bool AccessibilityRenderObject::isMenuBar() const
552{
553    return roleValue() == MenuBarRole;
554}
555
556bool AccessibilityRenderObject::isMenuButton() const
557{
558    return roleValue() == MenuButtonRole;
559}
560
561bool AccessibilityRenderObject::isMenuItem() const
562{
563    return roleValue() == MenuItemRole;
564}
565
566bool AccessibilityRenderObject::isPressed() const
567{
568    ASSERT(m_renderer);
569    if (roleValue() != ButtonRole)
570        return false;
571
572    Node* node = m_renderer->node();
573    if (!node)
574        return false;
575
576    // If this is an ARIA button, check the aria-pressed attribute rather than node()->active()
577    if (ariaRoleAttribute() == ButtonRole) {
578        if (equalIgnoringCase(getAttribute(aria_pressedAttr), "true"))
579            return true;
580        return false;
581    }
582
583    return node->active();
584}
585
586bool AccessibilityRenderObject::isIndeterminate() const
587{
588    ASSERT(m_renderer);
589    if (!m_renderer->node())
590        return false;
591
592    InputElement* inputElement = m_renderer->node()->toInputElement();
593    if (!inputElement)
594        return false;
595
596    return inputElement->isIndeterminate();
597}
598
599bool AccessibilityRenderObject::isNativeCheckboxOrRadio() const
600{
601    Node* elementNode = node();
602    if (elementNode) {
603        InputElement* input = elementNode->toInputElement();
604        if (input)
605            return input->isCheckbox() || input->isRadioButton();
606    }
607
608    return false;
609}
610
611bool AccessibilityRenderObject::isChecked() const
612{
613    ASSERT(m_renderer);
614    if (!m_renderer->node())
615        return false;
616
617    // First test for native checkedness semantics
618    InputElement* inputElement = m_renderer->node()->toInputElement();
619    if (inputElement)
620        return inputElement->isChecked();
621
622    // Else, if this is an ARIA checkbox or radio, respect the aria-checked attribute
623    AccessibilityRole ariaRole = ariaRoleAttribute();
624    if (ariaRole == RadioButtonRole || ariaRole == CheckBoxRole) {
625        if (equalIgnoringCase(getAttribute(aria_checkedAttr), "true"))
626            return true;
627        return false;
628    }
629
630    // Otherwise it's not checked
631    return false;
632}
633
634bool AccessibilityRenderObject::isHovered() const
635{
636    ASSERT(m_renderer);
637    return m_renderer->node() && m_renderer->node()->hovered();
638}
639
640bool AccessibilityRenderObject::isMultiSelectable() const
641{
642    ASSERT(m_renderer);
643
644    const AtomicString& ariaMultiSelectable = getAttribute(aria_multiselectableAttr);
645    if (equalIgnoringCase(ariaMultiSelectable, "true"))
646        return true;
647    if (equalIgnoringCase(ariaMultiSelectable, "false"))
648        return false;
649
650    if (!m_renderer->isBoxModelObject() || !toRenderBoxModelObject(m_renderer)->isListBox())
651        return false;
652    return m_renderer->node() && static_cast<HTMLSelectElement*>(m_renderer->node())->multiple();
653}
654
655bool AccessibilityRenderObject::isReadOnly() const
656{
657    ASSERT(m_renderer);
658
659    if (isWebArea()) {
660        Document* document = m_renderer->document();
661        if (!document)
662            return true;
663
664        HTMLElement* body = document->body();
665        if (body && body->isContentEditable())
666            return false;
667
668        return !document->rendererIsEditable();
669    }
670
671    if (m_renderer->isBoxModelObject()) {
672        RenderBoxModelObject* box = toRenderBoxModelObject(m_renderer);
673        if (box->isTextField())
674            return static_cast<HTMLInputElement*>(box->node())->readOnly();
675        if (box->isTextArea())
676            return static_cast<HTMLTextAreaElement*>(box->node())->readOnly();
677    }
678
679    return !m_renderer->node() || !m_renderer->node()->rendererIsEditable();
680}
681
682bool AccessibilityRenderObject::isOffScreen() const
683{
684    ASSERT(m_renderer);
685    IntRect contentRect = m_renderer->absoluteClippedOverflowRect();
686    FrameView* view = m_renderer->frame()->view();
687    FloatRect viewRect = view->visibleContentRect();
688    viewRect.intersect(contentRect);
689    return viewRect.isEmpty();
690}
691
692int AccessibilityRenderObject::headingLevel() const
693{
694    // headings can be in block flow and non-block flow
695    Node* element = node();
696    if (!element)
697        return 0;
698
699    if (ariaRoleAttribute() == HeadingRole)
700        return getAttribute(aria_levelAttr).toInt();
701
702    if (element->hasTagName(h1Tag))
703        return 1;
704
705    if (element->hasTagName(h2Tag))
706        return 2;
707
708    if (element->hasTagName(h3Tag))
709        return 3;
710
711    if (element->hasTagName(h4Tag))
712        return 4;
713
714    if (element->hasTagName(h5Tag))
715        return 5;
716
717    if (element->hasTagName(h6Tag))
718        return 6;
719
720    return 0;
721}
722
723bool AccessibilityRenderObject::isHeading() const
724{
725    return roleValue() == HeadingRole;
726}
727
728bool AccessibilityRenderObject::isLink() const
729{
730    return roleValue() == WebCoreLinkRole;
731}
732
733bool AccessibilityRenderObject::isControl() const
734{
735    if (!m_renderer)
736        return false;
737
738    Node* node = m_renderer->node();
739    return node && ((node->isElementNode() && static_cast<Element*>(node)->isFormControlElement())
740                    || AccessibilityObject::isARIAControl(ariaRoleAttribute()));
741}
742
743bool AccessibilityRenderObject::isFieldset() const
744{
745    RenderBoxModelObject* renderer = renderBoxModelObject();
746    if (!renderer)
747        return false;
748    return renderer->isFieldset();
749}
750
751bool AccessibilityRenderObject::isGroup() const
752{
753    return roleValue() == GroupRole;
754}
755
756AccessibilityObject* AccessibilityRenderObject::selectedRadioButton()
757{
758    if (!isRadioGroup())
759        return 0;
760
761    // Find the child radio button that is selected (ie. the intValue == 1).
762    int count = m_children.size();
763    for (int i = 0; i < count; ++i) {
764        AccessibilityObject* object = m_children[i].get();
765        if (object->roleValue() == RadioButtonRole && object->checkboxOrRadioValue() == ButtonStateOn)
766            return object;
767    }
768    return 0;
769}
770
771AccessibilityObject* AccessibilityRenderObject::selectedTabItem()
772{
773    if (!isTabList())
774        return 0;
775
776    // Find the child tab item that is selected (ie. the intValue == 1).
777    AccessibilityObject::AccessibilityChildrenVector tabs;
778    tabChildren(tabs);
779
780    int count = tabs.size();
781    for (int i = 0; i < count; ++i) {
782        AccessibilityObject* object = m_children[i].get();
783        if (object->isTabItem() && object->isChecked())
784            return object;
785    }
786    return 0;
787}
788
789Element* AccessibilityRenderObject::anchorElement() const
790{
791    if (!m_renderer)
792        return 0;
793
794    AXObjectCache* cache = axObjectCache();
795    RenderObject* currRenderer;
796
797    // Search up the render tree for a RenderObject with a DOM node.  Defer to an earlier continuation, though.
798    for (currRenderer = m_renderer; currRenderer && !currRenderer->node(); currRenderer = currRenderer->parent()) {
799        if (currRenderer->isAnonymousBlock()) {
800            RenderObject* continuation = toRenderBlock(currRenderer)->continuation();
801            if (continuation)
802                return cache->getOrCreate(continuation)->anchorElement();
803        }
804    }
805
806    // bail if none found
807    if (!currRenderer)
808        return 0;
809
810    // search up the DOM tree for an anchor element
811    // NOTE: this assumes that any non-image with an anchor is an HTMLAnchorElement
812    Node* node = currRenderer->node();
813    for ( ; node; node = node->parentNode()) {
814        if (node->hasTagName(aTag) || (node->renderer() && cache->getOrCreate(node->renderer())->isAnchor()))
815            return static_cast<Element*>(node);
816    }
817
818    return 0;
819}
820
821Element* AccessibilityRenderObject::actionElement() const
822{
823    if (!m_renderer)
824        return 0;
825
826    Node* node = m_renderer->node();
827    if (node) {
828        if (node->hasTagName(inputTag)) {
829            HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
830            if (!input->disabled() && (isCheckboxOrRadio() || input->isTextButton()))
831                return input;
832        } else if (node->hasTagName(buttonTag))
833            return static_cast<Element*>(node);
834    }
835
836    if (isFileUploadButton())
837        return static_cast<Element*>(m_renderer->node());
838
839    if (AccessibilityObject::isARIAInput(ariaRoleAttribute()))
840        return static_cast<Element*>(m_renderer->node());
841
842    if (isImageButton())
843        return static_cast<Element*>(m_renderer->node());
844
845    if (m_renderer->isBoxModelObject() && toRenderBoxModelObject(m_renderer)->isMenuList())
846        return static_cast<Element*>(m_renderer->node());
847
848    AccessibilityRole role = roleValue();
849    if (role == ButtonRole || role == PopUpButtonRole)
850        return static_cast<Element*>(m_renderer->node());
851
852    Element* elt = anchorElement();
853    if (!elt)
854        elt = mouseButtonListener();
855    return elt;
856}
857
858Element* AccessibilityRenderObject::mouseButtonListener() const
859{
860    Node* node = m_renderer->node();
861    if (!node)
862        return 0;
863
864    // check if our parent is a mouse button listener
865    while (node && !node->isElementNode())
866        node = node->parentNode();
867
868    if (!node)
869        return 0;
870
871    // FIXME: Do the continuation search like anchorElement does
872    for (Element* element = static_cast<Element*>(node); element; element = element->parentElement()) {
873        if (element->getAttributeEventListener(eventNames().clickEvent) || element->getAttributeEventListener(eventNames().mousedownEvent) || element->getAttributeEventListener(eventNames().mouseupEvent))
874            return element;
875    }
876
877    return 0;
878}
879
880void AccessibilityRenderObject::increment()
881{
882    if (roleValue() != SliderRole)
883        return;
884
885    changeValueByPercent(5);
886}
887
888void AccessibilityRenderObject::decrement()
889{
890    if (roleValue() != SliderRole)
891        return;
892
893    changeValueByPercent(-5);
894}
895
896static Element* siblingWithAriaRole(String role, Node* node)
897{
898    Node* sibling = node->parentNode()->firstChild();
899    while (sibling) {
900        if (sibling->isElementNode()) {
901            const AtomicString& siblingAriaRole = static_cast<Element*>(sibling)->getAttribute(roleAttr);
902            if (equalIgnoringCase(siblingAriaRole, role))
903                return static_cast<Element*>(sibling);
904        }
905        sibling = sibling->nextSibling();
906    }
907
908    return 0;
909}
910
911Element* AccessibilityRenderObject::menuElementForMenuButton() const
912{
913    if (ariaRoleAttribute() != MenuButtonRole)
914        return 0;
915
916    return siblingWithAriaRole("menu", renderer()->node());
917}
918
919AccessibilityObject* AccessibilityRenderObject::menuForMenuButton() const
920{
921    Element* menu = menuElementForMenuButton();
922    if (menu && menu->renderer())
923        return axObjectCache()->getOrCreate(menu->renderer());
924    return 0;
925}
926
927Element* AccessibilityRenderObject::menuItemElementForMenu() const
928{
929    if (ariaRoleAttribute() != MenuRole)
930        return 0;
931
932    return siblingWithAriaRole("menuitem", renderer()->node());
933}
934
935AccessibilityObject* AccessibilityRenderObject::menuButtonForMenu() const
936{
937    Element* menuItem = menuItemElementForMenu();
938
939    if (menuItem && menuItem->renderer()) {
940        // ARIA just has generic menu items.  AppKit needs to know if this is a top level items like MenuBarButton or MenuBarItem
941        AccessibilityObject* menuItemAX = axObjectCache()->getOrCreate(menuItem->renderer());
942        if (menuItemAX->isMenuButton())
943            return menuItemAX;
944    }
945    return 0;
946}
947
948String AccessibilityRenderObject::helpText() const
949{
950    if (!m_renderer)
951        return String();
952
953    const AtomicString& ariaHelp = getAttribute(aria_helpAttr);
954    if (!ariaHelp.isEmpty())
955        return ariaHelp;
956
957    for (RenderObject* curr = m_renderer; curr; curr = curr->parent()) {
958        if (curr->node() && curr->node()->isHTMLElement()) {
959            const AtomicString& summary = static_cast<Element*>(curr->node())->getAttribute(summaryAttr);
960            if (!summary.isEmpty())
961                return summary;
962            const AtomicString& title = static_cast<Element*>(curr->node())->getAttribute(titleAttr);
963            if (!title.isEmpty())
964                return title;
965        }
966
967        // Only take help text from an ancestor element if its a group or an unknown role. If help was
968        // added to those kinds of elements, it is likely it was meant for a child element.
969        AccessibilityObject* axObj = axObjectCache()->getOrCreate(curr);
970        if (axObj) {
971            AccessibilityRole role = axObj->roleValue();
972            if (role != GroupRole && role != UnknownRole)
973                break;
974        }
975    }
976
977    return String();
978}
979
980unsigned AccessibilityRenderObject::hierarchicalLevel() const
981{
982    if (!m_renderer)
983        return 0;
984
985    Node* node = m_renderer->node();
986    if (!node || !node->isElementNode())
987        return 0;
988    Element* element = static_cast<Element*>(node);
989    String ariaLevel = element->getAttribute(aria_levelAttr);
990    if (!ariaLevel.isEmpty())
991        return ariaLevel.toInt();
992
993    // Only tree item will calculate its level through the DOM currently.
994    if (roleValue() != TreeItemRole)
995        return 0;
996
997    // Hierarchy leveling starts at 0.
998    // We measure tree hierarchy by the number of groups that the item is within.
999    unsigned level = 0;
1000    AccessibilityObject* parent = parentObject();
1001    while (parent) {
1002        AccessibilityRole parentRole = parent->roleValue();
1003        if (parentRole == GroupRole)
1004            level++;
1005        else if (parentRole == TreeRole)
1006            break;
1007
1008        parent = parent->parentObject();
1009    }
1010
1011    return level;
1012}
1013
1014static TextIteratorBehavior textIteratorBehaviorForTextRange()
1015{
1016    TextIteratorBehavior behavior = TextIteratorIgnoresStyleVisibility;
1017
1018#if PLATFORM(GTK)
1019    // We need to emit replaced elements for GTK, and present
1020    // them with the 'object replacement character' (0xFFFC).
1021    behavior = static_cast<TextIteratorBehavior>(behavior | TextIteratorEmitsObjectReplacementCharacters);
1022#endif
1023
1024    return behavior;
1025}
1026
1027String AccessibilityRenderObject::textUnderElement() const
1028{
1029    if (!m_renderer)
1030        return String();
1031
1032    if (isFileUploadButton())
1033        return toRenderFileUploadControl(m_renderer)->buttonValue();
1034
1035    Node* node = m_renderer->node();
1036    if (node) {
1037        if (Frame* frame = node->document()->frame()) {
1038            // catch stale WebCoreAXObject (see <rdar://problem/3960196>)
1039            if (frame->document() != node->document())
1040                return String();
1041
1042            return plainText(rangeOfContents(node).get(), textIteratorBehaviorForTextRange());
1043        }
1044    }
1045
1046    // Sometimes text fragments don't have Node's associated with them (like when
1047    // CSS content is used to insert text).
1048    if (m_renderer->isText()) {
1049        RenderText* renderTextObject = toRenderText(m_renderer);
1050        if (renderTextObject->isTextFragment())
1051            return String(static_cast<RenderTextFragment*>(m_renderer)->contentString());
1052    }
1053
1054    // return the null string for anonymous text because it is non-trivial to get
1055    // the actual text and, so far, that is not needed
1056    return String();
1057}
1058
1059Node* AccessibilityRenderObject::node() const
1060{
1061    return m_renderer ? m_renderer->node() : 0;
1062}
1063
1064AccessibilityButtonState AccessibilityRenderObject::checkboxOrRadioValue() const
1065{
1066    if (isNativeCheckboxOrRadio())
1067        return isChecked() ? ButtonStateOn : ButtonStateOff;
1068
1069    return AccessibilityObject::checkboxOrRadioValue();
1070}
1071
1072String AccessibilityRenderObject::valueDescription() const
1073{
1074    // Only sliders and progress bars support value descriptions currently.
1075    if (!isProgressIndicator() && !isSlider())
1076        return String();
1077
1078    return getAttribute(aria_valuetextAttr).string();
1079}
1080
1081float AccessibilityRenderObject::valueForRange() const
1082{
1083    if (!isProgressIndicator() && !isSlider() && !isScrollbar())
1084        return 0.0f;
1085
1086    return getAttribute(aria_valuenowAttr).toFloat();
1087}
1088
1089float AccessibilityRenderObject::maxValueForRange() const
1090{
1091    if (!isProgressIndicator() && !isSlider())
1092        return 0.0f;
1093
1094    return getAttribute(aria_valuemaxAttr).toFloat();
1095}
1096
1097float AccessibilityRenderObject::minValueForRange() const
1098{
1099    if (!isProgressIndicator() && !isSlider())
1100        return 0.0f;
1101
1102    return getAttribute(aria_valueminAttr).toFloat();
1103}
1104
1105String AccessibilityRenderObject::stringValue() const
1106{
1107    if (!m_renderer || isPasswordField())
1108        return String();
1109
1110    RenderBoxModelObject* cssBox = renderBoxModelObject();
1111
1112    if (ariaRoleAttribute() == StaticTextRole) {
1113        String staticText = text();
1114        if (!staticText.length())
1115            staticText = textUnderElement();
1116        return staticText;
1117    }
1118
1119    if (m_renderer->isText())
1120        return textUnderElement();
1121
1122    if (cssBox && cssBox->isMenuList()) {
1123        // RenderMenuList will go straight to the text() of its selected item.
1124        // This has to be overriden in the case where the selected item has an aria label
1125        SelectElement* selectNode = toSelectElement(static_cast<Element*>(m_renderer->node()));
1126        int selectedIndex = selectNode->selectedIndex();
1127        const Vector<Element*> listItems = selectNode->listItems();
1128
1129        Element* selectedOption = 0;
1130        if (selectedIndex >= 0 && selectedIndex < (int)listItems.size())
1131            selectedOption = listItems[selectedIndex];
1132        if (selectedOption) {
1133            String overridenDescription = selectedOption->getAttribute(aria_labelAttr);
1134            if (!overridenDescription.isNull())
1135                return overridenDescription;
1136        }
1137
1138        return toRenderMenuList(m_renderer)->text();
1139    }
1140
1141    if (m_renderer->isListMarker())
1142        return toRenderListMarker(m_renderer)->text();
1143
1144    if (cssBox && cssBox->isRenderButton())
1145        return toRenderButton(m_renderer)->text();
1146
1147    if (isWebArea()) {
1148        if (m_renderer->frame())
1149            return String();
1150
1151        // FIXME: should use startOfDocument and endOfDocument (or rangeForDocument?) here
1152        VisiblePosition startVisiblePosition = m_renderer->positionForCoordinates(0, 0);
1153        VisiblePosition endVisiblePosition = m_renderer->positionForCoordinates(INT_MAX, INT_MAX);
1154        if (startVisiblePosition.isNull() || endVisiblePosition.isNull())
1155            return String();
1156
1157        return plainText(makeRange(startVisiblePosition, endVisiblePosition).get(),
1158                         textIteratorBehaviorForTextRange());
1159    }
1160
1161    if (isTextControl())
1162        return text();
1163
1164    if (isFileUploadButton())
1165        return toRenderFileUploadControl(m_renderer)->fileTextValue();
1166
1167    // FIXME: We might need to implement a value here for more types
1168    // FIXME: It would be better not to advertise a value at all for the types for which we don't implement one;
1169    // this would require subclassing or making accessibilityAttributeNames do something other than return a
1170    // single static array.
1171    return String();
1172}
1173
1174// This function implements the ARIA accessible name as described by the Mozilla
1175// ARIA Implementer's Guide.
1176static String accessibleNameForNode(Node* node)
1177{
1178    if (node->isTextNode())
1179        return static_cast<Text*>(node)->data();
1180
1181    if (node->hasTagName(inputTag))
1182        return static_cast<HTMLInputElement*>(node)->value();
1183
1184    if (node->isHTMLElement()) {
1185        const AtomicString& alt = toHTMLElement(node)->getAttribute(altAttr);
1186        if (!alt.isEmpty())
1187            return alt;
1188    }
1189
1190    return String();
1191}
1192
1193String AccessibilityRenderObject::accessibilityDescriptionForElements(Vector<Element*> &elements) const
1194{
1195    StringBuilder builder;
1196    unsigned size = elements.size();
1197    for (unsigned i = 0; i < size; ++i) {
1198        Element* idElement = elements[i];
1199
1200        builder.append(accessibleNameForNode(idElement));
1201        for (Node* n = idElement->firstChild(); n; n = n->traverseNextNode(idElement))
1202            builder.append(accessibleNameForNode(n));
1203
1204        if (i != size - 1)
1205            builder.append(' ');
1206    }
1207    return builder.toString();
1208}
1209
1210void AccessibilityRenderObject::elementsFromAttribute(Vector<Element*>& elements, const QualifiedName& attribute) const
1211{
1212    Node* node = m_renderer->node();
1213    if (!node || !node->isElementNode())
1214        return;
1215
1216    Document* document = m_renderer->document();
1217    if (!document)
1218        return;
1219
1220    String idList = getAttribute(attribute).string();
1221    if (idList.isEmpty())
1222        return;
1223
1224    idList.replace('\n', ' ');
1225    Vector<String> idVector;
1226    idList.split(' ', idVector);
1227
1228    unsigned size = idVector.size();
1229    for (unsigned i = 0; i < size; ++i) {
1230        String idName = idVector[i];
1231        Element* idElement = document->getElementById(idName);
1232        if (idElement)
1233            elements.append(idElement);
1234    }
1235}
1236
1237void AccessibilityRenderObject::ariaLabeledByElements(Vector<Element*>& elements) const
1238{
1239    elementsFromAttribute(elements, aria_labeledbyAttr);
1240    if (!elements.size())
1241        elementsFromAttribute(elements, aria_labelledbyAttr);
1242}
1243
1244String AccessibilityRenderObject::ariaLabeledByAttribute() const
1245{
1246    Vector<Element*> elements;
1247    ariaLabeledByElements(elements);
1248
1249    return accessibilityDescriptionForElements(elements);
1250}
1251
1252static HTMLLabelElement* labelForElement(Element* element)
1253{
1254    RefPtr<NodeList> list = element->document()->getElementsByTagName("label");
1255    unsigned len = list->length();
1256    for (unsigned i = 0; i < len; i++) {
1257        if (list->item(i)->hasTagName(labelTag)) {
1258            HTMLLabelElement* label = static_cast<HTMLLabelElement*>(list->item(i));
1259            if (label->control() == element)
1260                return label;
1261        }
1262    }
1263
1264    return 0;
1265}
1266
1267HTMLLabelElement* AccessibilityRenderObject::labelElementContainer() const
1268{
1269    if (!m_renderer)
1270        return 0;
1271
1272    // the control element should not be considered part of the label
1273    if (isControl())
1274        return 0;
1275
1276    // find if this has a parent that is a label
1277    for (Node* parentNode = m_renderer->node(); parentNode; parentNode = parentNode->parentNode()) {
1278        if (parentNode->hasTagName(labelTag))
1279            return static_cast<HTMLLabelElement*>(parentNode);
1280    }
1281
1282    return 0;
1283}
1284
1285String AccessibilityRenderObject::title() const
1286{
1287    AccessibilityRole ariaRole = ariaRoleAttribute();
1288
1289    if (!m_renderer)
1290        return String();
1291
1292    Node* node = m_renderer->node();
1293    if (!node)
1294        return String();
1295
1296    String ariaLabel = ariaLabeledByAttribute();
1297    if (!ariaLabel.isEmpty())
1298        return ariaLabel;
1299
1300    const AtomicString& title = getAttribute(titleAttr);
1301    if (!title.isEmpty())
1302        return title;
1303
1304    bool isInputTag = node->hasTagName(inputTag);
1305    if (isInputTag) {
1306        HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
1307        if (input->isTextButton())
1308            return input->value();
1309    }
1310
1311    if (isInputTag || AccessibilityObject::isARIAInput(ariaRole) || isControl()) {
1312        HTMLLabelElement* label = labelForElement(static_cast<Element*>(node));
1313        if (label && !titleUIElement())
1314            return label->innerText();
1315    }
1316
1317    if (roleValue() == ButtonRole
1318        || ariaRole == ListBoxOptionRole
1319        || ariaRole == MenuItemRole
1320        || ariaRole == MenuButtonRole
1321        || ariaRole == RadioButtonRole
1322        || ariaRole == CheckBoxRole
1323        || ariaRole == TabRole
1324        || ariaRole == PopUpButtonRole
1325        || isHeading()
1326        || isLink())
1327        return textUnderElement();
1328
1329    return String();
1330}
1331
1332String AccessibilityRenderObject::ariaDescribedByAttribute() const
1333{
1334    Vector<Element*> elements;
1335    elementsFromAttribute(elements, aria_describedbyAttr);
1336
1337    return accessibilityDescriptionForElements(elements);
1338}
1339
1340String AccessibilityRenderObject::ariaAccessibilityDescription() const
1341{
1342    const AtomicString& ariaLabel = getAttribute(aria_labelAttr);
1343    if (!ariaLabel.isEmpty())
1344        return ariaLabel;
1345
1346    String ariaDescription = ariaDescribedByAttribute();
1347    if (!ariaDescription.isEmpty())
1348        return ariaDescription;
1349
1350    return String();
1351}
1352
1353String AccessibilityRenderObject::accessibilityDescription() const
1354{
1355    if (!m_renderer)
1356        return String();
1357
1358    // Static text should not have a description, it should only have a stringValue.
1359    if (roleValue() == StaticTextRole)
1360        return String();
1361
1362    String ariaDescription = ariaAccessibilityDescription();
1363    if (!ariaDescription.isEmpty())
1364        return ariaDescription;
1365
1366    Node* node = m_renderer->node();
1367    if (isImage() || isInputImage() || isNativeImage()) {
1368        if (node && node->isHTMLElement()) {
1369            const AtomicString& alt = toHTMLElement(node)->getAttribute(altAttr);
1370            if (alt.isEmpty())
1371                return String();
1372            return alt;
1373        }
1374    }
1375
1376#if ENABLE(MATHML)
1377    if (node && node->isElementNode() && static_cast<Element*>(node)->isMathMLElement())
1378        return getAttribute(MathMLNames::alttextAttr);
1379#endif
1380
1381    if (isWebArea()) {
1382        Document* document = m_renderer->document();
1383
1384        // Check if the HTML element has an aria-label for the webpage.
1385        Element* documentElement = document->documentElement();
1386        if (documentElement) {
1387            const AtomicString& ariaLabel = documentElement->getAttribute(aria_labelAttr);
1388            if (!ariaLabel.isEmpty())
1389                return ariaLabel;
1390        }
1391
1392        Node* owner = document->ownerElement();
1393        if (owner) {
1394            if (owner->hasTagName(frameTag) || owner->hasTagName(iframeTag)) {
1395                const AtomicString& title = static_cast<HTMLFrameElementBase*>(owner)->getAttribute(titleAttr);
1396                if (!title.isEmpty())
1397                    return title;
1398                return static_cast<HTMLFrameElementBase*>(owner)->getAttribute(nameAttr);
1399            }
1400            if (owner->isHTMLElement())
1401                return toHTMLElement(owner)->getAttribute(nameAttr);
1402        }
1403        owner = document->body();
1404        if (owner && owner->isHTMLElement())
1405            return toHTMLElement(owner)->getAttribute(nameAttr);
1406    }
1407
1408    return String();
1409}
1410
1411IntRect AccessibilityRenderObject::boundingBoxRect() const
1412{
1413    RenderObject* obj = m_renderer;
1414
1415    if (!obj)
1416        return IntRect();
1417
1418    if (obj->node()) // If we are a continuation, we want to make sure to use the primary renderer.
1419        obj = obj->node()->renderer();
1420
1421    // absoluteFocusRingQuads will query the hierarchy below this element, which for large webpages can be very slow.
1422    // For a web area, which will have the most elements of any element, absoluteQuads should be used.
1423    Vector<FloatQuad> quads;
1424    if (obj->isText())
1425        toRenderText(obj)->absoluteQuads(quads, RenderText::ClipToEllipsis);
1426    else if (isWebArea())
1427        obj->absoluteQuads(quads);
1428    else
1429        obj->absoluteFocusRingQuads(quads);
1430    const size_t n = quads.size();
1431    if (!n)
1432        return IntRect();
1433
1434    IntRect result;
1435    for (size_t i = 0; i < n; ++i) {
1436        IntRect r = quads[i].enclosingBoundingBox();
1437        if (!r.isEmpty()) {
1438            if (obj->style()->hasAppearance())
1439                obj->theme()->adjustRepaintRect(obj, r);
1440            result.unite(r);
1441        }
1442    }
1443
1444    // The size of the web area should be the content size, not the clipped size.
1445    if (isWebArea() && obj->frame()->view())
1446        result.setSize(obj->frame()->view()->contentsSize());
1447
1448    return result;
1449}
1450
1451IntRect AccessibilityRenderObject::checkboxOrRadioRect() const
1452{
1453    if (!m_renderer)
1454        return IntRect();
1455
1456    HTMLLabelElement* label = labelForElement(static_cast<Element*>(m_renderer->node()));
1457    if (!label || !label->renderer())
1458        return boundingBoxRect();
1459
1460    IntRect labelRect = axObjectCache()->getOrCreate(label->renderer())->elementRect();
1461    labelRect.unite(boundingBoxRect());
1462    return labelRect;
1463}
1464
1465IntRect AccessibilityRenderObject::elementRect() const
1466{
1467    // a checkbox or radio button should encompass its label
1468    if (isCheckboxOrRadio())
1469        return checkboxOrRadioRect();
1470
1471    return boundingBoxRect();
1472}
1473
1474IntSize AccessibilityRenderObject::size() const
1475{
1476    IntRect rect = elementRect();
1477    return rect.size();
1478}
1479
1480IntPoint AccessibilityRenderObject::clickPoint() const
1481{
1482    // use the default position unless this is an editable web area, in which case we use the selection bounds.
1483    if (!isWebArea() || isReadOnly())
1484        return AccessibilityObject::clickPoint();
1485
1486    VisibleSelection visSelection = selection();
1487    VisiblePositionRange range = VisiblePositionRange(visSelection.visibleStart(), visSelection.visibleEnd());
1488    IntRect bounds = boundsForVisiblePositionRange(range);
1489#if PLATFORM(MAC)
1490    bounds.setLocation(m_renderer->document()->view()->screenToContents(bounds.location()));
1491#endif
1492    return IntPoint(bounds.x() + (bounds.width() / 2), bounds.y() - (bounds.height() / 2));
1493}
1494
1495AccessibilityObject* AccessibilityRenderObject::internalLinkElement() const
1496{
1497    Element* element = anchorElement();
1498    if (!element)
1499        return 0;
1500
1501    // Right now, we do not support ARIA links as internal link elements
1502    if (!element->hasTagName(aTag))
1503        return 0;
1504    HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(element);
1505
1506    KURL linkURL = anchor->href();
1507    String fragmentIdentifier = linkURL.fragmentIdentifier();
1508    if (fragmentIdentifier.isEmpty())
1509        return 0;
1510
1511    // check if URL is the same as current URL
1512    KURL documentURL = m_renderer->document()->url();
1513    if (!equalIgnoringFragmentIdentifier(documentURL, linkURL))
1514        return 0;
1515
1516    Node* linkedNode = m_renderer->document()->findAnchor(fragmentIdentifier);
1517    if (!linkedNode)
1518        return 0;
1519
1520    // The element we find may not be accessible, so find the first accessible object.
1521    return firstAccessibleObjectFromNode(linkedNode);
1522}
1523
1524ESpeak AccessibilityRenderObject::speakProperty() const
1525{
1526    if (!m_renderer)
1527        return AccessibilityObject::speakProperty();
1528
1529    return m_renderer->style()->speak();
1530}
1531
1532void AccessibilityRenderObject::addRadioButtonGroupMembers(AccessibilityChildrenVector& linkedUIElements) const
1533{
1534    if (!m_renderer || roleValue() != RadioButtonRole)
1535        return;
1536
1537    Node* node = m_renderer->node();
1538    if (!node || !node->hasTagName(inputTag))
1539        return;
1540
1541    HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
1542    // if there's a form, then this is easy
1543    if (input->form()) {
1544        Vector<RefPtr<Node> > formElements;
1545        input->form()->getNamedElements(input->name(), formElements);
1546
1547        unsigned len = formElements.size();
1548        for (unsigned i = 0; i < len; ++i) {
1549            Node* associateElement = formElements[i].get();
1550            if (AccessibilityObject* object = axObjectCache()->getOrCreate(associateElement->renderer()))
1551                linkedUIElements.append(object);
1552        }
1553    } else {
1554        RefPtr<NodeList> list = node->document()->getElementsByTagName("input");
1555        unsigned len = list->length();
1556        for (unsigned i = 0; i < len; ++i) {
1557            if (list->item(i)->hasTagName(inputTag)) {
1558                HTMLInputElement* associateElement = static_cast<HTMLInputElement*>(list->item(i));
1559                if (associateElement->isRadioButton() && associateElement->name() == input->name()) {
1560                    if (AccessibilityObject* object = axObjectCache()->getOrCreate(associateElement->renderer()))
1561                        linkedUIElements.append(object);
1562                }
1563            }
1564        }
1565    }
1566}
1567
1568// linked ui elements could be all the related radio buttons in a group
1569// or an internal anchor connection
1570void AccessibilityRenderObject::linkedUIElements(AccessibilityChildrenVector& linkedUIElements) const
1571{
1572    ariaFlowToElements(linkedUIElements);
1573
1574    if (isAnchor()) {
1575        AccessibilityObject* linkedAXElement = internalLinkElement();
1576        if (linkedAXElement)
1577            linkedUIElements.append(linkedAXElement);
1578    }
1579
1580    if (roleValue() == RadioButtonRole)
1581        addRadioButtonGroupMembers(linkedUIElements);
1582}
1583
1584bool AccessibilityRenderObject::hasTextAlternative() const
1585{
1586    // ARIA: section 2A, bullet #3 says if aria-labeledby or aria-label appears, it should
1587    // override the "label" element association.
1588    if (!ariaLabeledByAttribute().isEmpty() || !getAttribute(aria_labelAttr).isEmpty())
1589        return true;
1590
1591    return false;
1592}
1593
1594bool AccessibilityRenderObject::ariaHasPopup() const
1595{
1596    return elementAttributeValue(aria_haspopupAttr);
1597}
1598
1599bool AccessibilityRenderObject::supportsARIAFlowTo() const
1600{
1601    return !getAttribute(aria_flowtoAttr).isEmpty();
1602}
1603
1604void AccessibilityRenderObject::ariaFlowToElements(AccessibilityChildrenVector& flowTo) const
1605{
1606    Vector<Element*> elements;
1607    elementsFromAttribute(elements, aria_flowtoAttr);
1608
1609    AXObjectCache* cache = axObjectCache();
1610    unsigned count = elements.size();
1611    for (unsigned k = 0; k < count; ++k) {
1612        Element* element = elements[k];
1613        AccessibilityObject* flowToElement = cache->getOrCreate(element->renderer());
1614        if (flowToElement)
1615            flowTo.append(flowToElement);
1616    }
1617
1618}
1619
1620bool AccessibilityRenderObject::supportsARIADropping() const
1621{
1622    const AtomicString& dropEffect = getAttribute(aria_dropeffectAttr);
1623    return !dropEffect.isEmpty();
1624}
1625
1626bool AccessibilityRenderObject::supportsARIADragging() const
1627{
1628    const AtomicString& grabbed = getAttribute(aria_grabbedAttr);
1629    return equalIgnoringCase(grabbed, "true") || equalIgnoringCase(grabbed, "false");
1630}
1631
1632bool AccessibilityRenderObject::isARIAGrabbed()
1633{
1634    return elementAttributeValue(aria_grabbedAttr);
1635}
1636
1637void AccessibilityRenderObject::setARIAGrabbed(bool grabbed)
1638{
1639    setElementAttributeValue(aria_grabbedAttr, grabbed);
1640}
1641
1642void AccessibilityRenderObject::determineARIADropEffects(Vector<String>& effects)
1643{
1644    const AtomicString& dropEffects = getAttribute(aria_dropeffectAttr);
1645    if (dropEffects.isEmpty()) {
1646        effects.clear();
1647        return;
1648    }
1649
1650    String dropEffectsString = dropEffects.string();
1651    dropEffectsString.replace('\n', ' ');
1652    dropEffectsString.split(' ', effects);
1653}
1654
1655bool AccessibilityRenderObject::exposesTitleUIElement() const
1656{
1657    if (!isControl())
1658        return false;
1659
1660    // checkbox or radio buttons don't expose the title ui element unless it has a title already
1661    if (isCheckboxOrRadio() && getAttribute(titleAttr).isEmpty())
1662        return false;
1663
1664    if (hasTextAlternative())
1665        return false;
1666
1667    return true;
1668}
1669
1670AccessibilityObject* AccessibilityRenderObject::titleUIElement() const
1671{
1672    if (!m_renderer)
1673        return 0;
1674
1675    // if isFieldset is true, the renderer is guaranteed to be a RenderFieldset
1676    if (isFieldset())
1677        return axObjectCache()->getOrCreate(toRenderFieldset(m_renderer)->findLegend());
1678
1679    if (!exposesTitleUIElement())
1680        return 0;
1681
1682    Node* element = m_renderer->node();
1683    HTMLLabelElement* label = labelForElement(static_cast<Element*>(element));
1684    if (label && label->renderer())
1685        return axObjectCache()->getOrCreate(label->renderer());
1686
1687    return 0;
1688}
1689
1690bool AccessibilityRenderObject::ariaIsHidden() const
1691{
1692    if (equalIgnoringCase(getAttribute(aria_hiddenAttr), "true"))
1693        return true;
1694
1695    // aria-hidden hides this object and any children
1696    AccessibilityObject* object = parentObject();
1697    while (object) {
1698        if (object->isAccessibilityRenderObject() && equalIgnoringCase(static_cast<AccessibilityRenderObject*>(object)->getAttribute(aria_hiddenAttr), "true"))
1699            return true;
1700        object = object->parentObject();
1701    }
1702
1703    return false;
1704}
1705
1706bool AccessibilityRenderObject::isDescendantOfBarrenParent() const
1707{
1708    for (AccessibilityObject* object = parentObject(); object; object = object->parentObject()) {
1709        if (!object->canHaveChildren())
1710            return true;
1711    }
1712
1713    return false;
1714}
1715
1716bool AccessibilityRenderObject::isAllowedChildOfTree() const
1717{
1718    // Determine if this is in a tree. If so, we apply special behavior to make it work like an AXOutline.
1719    AccessibilityObject* axObj = parentObject();
1720    bool isInTree = false;
1721    while (axObj) {
1722        if (axObj->isTree()) {
1723            isInTree = true;
1724            break;
1725        }
1726        axObj = axObj->parentObject();
1727    }
1728
1729    // If the object is in a tree, only tree items should be exposed (and the children of tree items).
1730    if (isInTree) {
1731        AccessibilityRole role = roleValue();
1732        if (role != TreeItemRole && role != StaticTextRole)
1733            return false;
1734    }
1735    return true;
1736}
1737
1738AccessibilityObjectInclusion AccessibilityRenderObject::accessibilityIsIgnoredBase() const
1739{
1740    // The following cases can apply to any element that's a subclass of AccessibilityRenderObject.
1741
1742    // Ignore invisible elements.
1743    if (!m_renderer || m_renderer->style()->visibility() != VISIBLE)
1744        return IgnoreObject;
1745
1746    // Anything marked as aria-hidden or a child of something aria-hidden must be hidden.
1747    if (ariaIsHidden())
1748        return IgnoreObject;
1749
1750    // Anything that is a presentational role must be hidden.
1751    if (isPresentationalChildOfAriaRole())
1752        return IgnoreObject;
1753
1754    // Allow the platform to make a decision.
1755    AccessibilityObjectInclusion decision = accessibilityPlatformIncludesObject();
1756    if (decision == IncludeObject)
1757        return IncludeObject;
1758    if (decision == IgnoreObject)
1759        return IgnoreObject;
1760
1761    return DefaultBehavior;
1762}
1763
1764bool AccessibilityRenderObject::accessibilityIsIgnored() const
1765{
1766    // Check first if any of the common reasons cause this element to be ignored.
1767    // Then process other use cases that need to be applied to all the various roles
1768    // that AccessibilityRenderObjects take on.
1769    AccessibilityObjectInclusion decision = accessibilityIsIgnoredBase();
1770    if (decision == IncludeObject)
1771        return false;
1772    if (decision == IgnoreObject)
1773        return true;
1774
1775    // If this element is within a parent that cannot have children, it should not be exposed.
1776    if (isDescendantOfBarrenParent())
1777        return true;
1778
1779    if (roleValue() == IgnoredRole)
1780        return true;
1781
1782    if (roleValue() == PresentationalRole || inheritsPresentationalRole())
1783        return true;
1784
1785    // An ARIA tree can only have tree items and static text as children.
1786    if (!isAllowedChildOfTree())
1787        return true;
1788
1789    // Allow the platform to decide if the attachment is ignored or not.
1790    if (isAttachment())
1791        return accessibilityIgnoreAttachment();
1792
1793    // ignore popup menu items because AppKit does
1794    for (RenderObject* parent = m_renderer->parent(); parent; parent = parent->parent()) {
1795        if (parent->isBoxModelObject() && toRenderBoxModelObject(parent)->isMenuList())
1796            return true;
1797    }
1798
1799    // find out if this element is inside of a label element.
1800    // if so, it may be ignored because it's the label for a checkbox or radio button
1801    AccessibilityObject* controlObject = correspondingControlForLabelElement();
1802    if (controlObject && !controlObject->exposesTitleUIElement() && controlObject->isCheckboxOrRadio())
1803        return true;
1804
1805    // NOTE: BRs always have text boxes now, so the text box check here can be removed
1806    if (m_renderer->isText()) {
1807        // static text beneath MenuItems and MenuButtons are just reported along with the menu item, so it's ignored on an individual level
1808        if (parentObjectUnignored()->ariaRoleAttribute() == MenuItemRole
1809            || parentObjectUnignored()->ariaRoleAttribute() == MenuButtonRole)
1810            return true;
1811        RenderText* renderText = toRenderText(m_renderer);
1812        if (m_renderer->isBR() || !renderText->firstTextBox())
1813            return true;
1814
1815        // static text beneath TextControls is reported along with the text control text so it's ignored.
1816        for (AccessibilityObject* parent = parentObject(); parent; parent = parent->parentObject()) {
1817            if (parent->roleValue() == TextFieldRole)
1818                return true;
1819        }
1820
1821        // text elements that are just empty whitespace should not be returned
1822        return renderText->text()->containsOnlyWhitespace();
1823    }
1824
1825    if (isHeading())
1826        return false;
1827
1828    if (isLink())
1829        return false;
1830
1831    // all controls are accessible
1832    if (isControl())
1833        return false;
1834
1835    if (ariaRoleAttribute() != UnknownRole)
1836        return false;
1837
1838    // don't ignore labels, because they serve as TitleUIElements
1839    Node* node = m_renderer->node();
1840    if (node && node->hasTagName(labelTag))
1841        return false;
1842
1843    // Anything that is content editable should not be ignored.
1844    // However, one cannot just call node->rendererIsEditable() since that will ask if its parents
1845    // are also editable. Only the top level content editable region should be exposed.
1846    if (node && node->isElementNode()) {
1847        Element* element = static_cast<Element*>(node);
1848        const AtomicString& contentEditable = element->getAttribute(contenteditableAttr);
1849        if (equalIgnoringCase(contentEditable, "true"))
1850            return false;
1851    }
1852
1853    // List items play an important role in defining the structure of lists. They should not be ignored.
1854    if (roleValue() == ListItemRole)
1855        return false;
1856
1857    // if this element has aria attributes on it, it should not be ignored.
1858    if (supportsARIAAttributes())
1859        return false;
1860
1861    if (m_renderer->isBlockFlow() && m_renderer->childrenInline())
1862        return !toRenderBlock(m_renderer)->firstLineBox() && !mouseButtonListener();
1863
1864    // ignore images seemingly used as spacers
1865    if (isImage()) {
1866        if (node && node->isElementNode()) {
1867            Element* elt = static_cast<Element*>(node);
1868            const AtomicString& alt = elt->getAttribute(altAttr);
1869            // don't ignore an image that has an alt tag
1870            if (!alt.isEmpty())
1871                return false;
1872            // informal standard is to ignore images with zero-length alt strings
1873            if (!alt.isNull())
1874                return true;
1875        }
1876
1877        if (node && node->hasTagName(canvasTag)) {
1878            RenderHTMLCanvas* canvas = toRenderHTMLCanvas(m_renderer);
1879            if (canvas->height() <= 1 || canvas->width() <= 1)
1880                return true;
1881            return false;
1882        }
1883
1884        if (isNativeImage()) {
1885            // check for one-dimensional image
1886            RenderImage* image = toRenderImage(m_renderer);
1887            if (image->height() <= 1 || image->width() <= 1)
1888                return true;
1889
1890            // check whether rendered image was stretched from one-dimensional file image
1891            if (image->cachedImage()) {
1892                IntSize imageSize = image->cachedImage()->imageSize(image->view()->zoomFactor());
1893                return imageSize.height() <= 1 || imageSize.width() <= 1;
1894            }
1895        }
1896        return false;
1897    }
1898
1899    if (isWebArea() || m_renderer->isListMarker())
1900        return false;
1901
1902    // Using the help text to decide an element's visibility is not as definitive
1903    // as previous checks, so this should remain as one of the last.
1904    if (!helpText().isEmpty())
1905        return false;
1906
1907    // By default, objects should be ignored so that the AX hierarchy is not
1908    // filled with unnecessary items.
1909    return true;
1910}
1911
1912bool AccessibilityRenderObject::isLoaded() const
1913{
1914    return !m_renderer->document()->parser();
1915}
1916
1917double AccessibilityRenderObject::estimatedLoadingProgress() const
1918{
1919    if (!m_renderer)
1920        return 0;
1921
1922    if (isLoaded())
1923        return 1.0;
1924
1925    Page* page = m_renderer->document()->page();
1926    if (!page)
1927        return 0;
1928
1929    return page->progress()->estimatedProgress();
1930}
1931
1932int AccessibilityRenderObject::layoutCount() const
1933{
1934    if (!m_renderer->isRenderView())
1935        return 0;
1936    return toRenderView(m_renderer)->frameView()->layoutCount();
1937}
1938
1939String AccessibilityRenderObject::text() const
1940{
1941    // If this is a user defined static text, use the accessible name computation.
1942    if (ariaRoleAttribute() == StaticTextRole)
1943        return ariaAccessibilityDescription();
1944
1945    if (!isTextControl() || isPasswordField())
1946        return String();
1947
1948    if (isNativeTextControl())
1949        return toRenderTextControl(m_renderer)->text();
1950
1951    Node* node = m_renderer->node();
1952    if (!node)
1953        return String();
1954    if (!node->isElementNode())
1955        return String();
1956
1957    return static_cast<Element*>(node)->innerText();
1958}
1959
1960int AccessibilityRenderObject::textLength() const
1961{
1962    ASSERT(isTextControl());
1963
1964    if (isPasswordField())
1965        return -1; // need to return something distinct from 0
1966
1967    return text().length();
1968}
1969
1970PlainTextRange AccessibilityRenderObject::ariaSelectedTextRange() const
1971{
1972    Node* node = m_renderer->node();
1973    if (!node)
1974        return PlainTextRange();
1975
1976    ExceptionCode ec = 0;
1977    VisibleSelection visibleSelection = selection();
1978    RefPtr<Range> currentSelectionRange = visibleSelection.toNormalizedRange();
1979    if (!currentSelectionRange || !currentSelectionRange->intersectsNode(node, ec))
1980        return PlainTextRange();
1981
1982    int start = indexForVisiblePosition(visibleSelection.start());
1983    int end = indexForVisiblePosition(visibleSelection.end());
1984
1985    return PlainTextRange(start, end - start);
1986}
1987
1988String AccessibilityRenderObject::selectedText() const
1989{
1990    ASSERT(isTextControl());
1991
1992    if (isPasswordField())
1993        return String(); // need to return something distinct from empty string
1994
1995    if (isNativeTextControl()) {
1996        RenderTextControl* textControl = toRenderTextControl(m_renderer);
1997        return textControl->text().substring(textControl->selectionStart(), textControl->selectionEnd() - textControl->selectionStart());
1998    }
1999
2000    if (ariaRoleAttribute() == UnknownRole)
2001        return String();
2002
2003    return doAXStringForRange(ariaSelectedTextRange());
2004}
2005
2006const AtomicString& AccessibilityRenderObject::accessKey() const
2007{
2008    Node* node = m_renderer->node();
2009    if (!node)
2010        return nullAtom;
2011    if (!node->isElementNode())
2012        return nullAtom;
2013    return static_cast<Element*>(node)->getAttribute(accesskeyAttr);
2014}
2015
2016VisibleSelection AccessibilityRenderObject::selection() const
2017{
2018    return m_renderer->frame()->selection()->selection();
2019}
2020
2021PlainTextRange AccessibilityRenderObject::selectedTextRange() const
2022{
2023    ASSERT(isTextControl());
2024
2025    if (isPasswordField())
2026        return PlainTextRange();
2027
2028    AccessibilityRole ariaRole = ariaRoleAttribute();
2029    if (isNativeTextControl() && ariaRole == UnknownRole) {
2030        RenderTextControl* textControl = toRenderTextControl(m_renderer);
2031        return PlainTextRange(textControl->selectionStart(), textControl->selectionEnd() - textControl->selectionStart());
2032    }
2033
2034    if (ariaRole == UnknownRole)
2035        return PlainTextRange();
2036
2037    return ariaSelectedTextRange();
2038}
2039
2040void AccessibilityRenderObject::setSelectedTextRange(const PlainTextRange& range)
2041{
2042    if (isNativeTextControl()) {
2043        setSelectionRange(m_renderer->node(), range.start, range.start + range.length);
2044        return;
2045    }
2046
2047    Document* document = m_renderer->document();
2048    if (!document)
2049        return;
2050    Frame* frame = document->frame();
2051    if (!frame)
2052        return;
2053    Node* node = m_renderer->node();
2054    frame->selection()->setSelection(VisibleSelection(Position(node, range.start, Position::PositionIsOffsetInAnchor),
2055        Position(node, range.start + range.length, Position::PositionIsOffsetInAnchor), DOWNSTREAM));
2056}
2057
2058KURL AccessibilityRenderObject::url() const
2059{
2060    if (isAnchor() && m_renderer->node()->hasTagName(aTag)) {
2061        if (HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(anchorElement()))
2062            return anchor->href();
2063    }
2064
2065    if (isWebArea())
2066        return m_renderer->document()->url();
2067
2068    if (isImage() && m_renderer->node() && m_renderer->node()->hasTagName(imgTag))
2069        return static_cast<HTMLImageElement*>(m_renderer->node())->src();
2070
2071    if (isInputImage())
2072        return static_cast<HTMLInputElement*>(m_renderer->node())->src();
2073
2074    return KURL();
2075}
2076
2077bool AccessibilityRenderObject::isVisited() const
2078{
2079    // FIXME: Is it a privacy violation to expose visited information to accessibility APIs?
2080    return m_renderer->style()->isLink() && m_renderer->style()->insideLink() == InsideVisitedLink;
2081}
2082
2083void AccessibilityRenderObject::setElementAttributeValue(const QualifiedName& attributeName, bool value)
2084{
2085    if (!m_renderer)
2086        return;
2087
2088    Node* node = m_renderer->node();
2089    if (!node || !node->isElementNode())
2090        return;
2091
2092    Element* element = static_cast<Element*>(node);
2093    element->setAttribute(attributeName, (value) ? "true" : "false");
2094}
2095
2096bool AccessibilityRenderObject::elementAttributeValue(const QualifiedName& attributeName) const
2097{
2098    if (!m_renderer)
2099        return false;
2100
2101    return equalIgnoringCase(getAttribute(attributeName), "true");
2102}
2103
2104void AccessibilityRenderObject::setIsExpanded(bool isExpanded)
2105{
2106    // Combo boxes, tree items and rows can be expanded (in different ways on different platforms).
2107    // That action translates into setting the aria-expanded attribute to true.
2108    AccessibilityRole role = roleValue();
2109    switch (role) {
2110    case ComboBoxRole:
2111    case TreeItemRole:
2112    case RowRole:
2113        setElementAttributeValue(aria_expandedAttr, isExpanded);
2114        break;
2115    default:
2116        break;
2117    }
2118}
2119
2120bool AccessibilityRenderObject::isRequired() const
2121{
2122    if (equalIgnoringCase(getAttribute(aria_requiredAttr), "true"))
2123        return true;
2124
2125    Node* n = node();
2126    if (n && (n->isElementNode() && static_cast<Element*>(n)->isFormControlElement()))
2127        return static_cast<HTMLFormControlElement*>(n)->required();
2128
2129    return false;
2130}
2131
2132bool AccessibilityRenderObject::isSelected() const
2133{
2134    if (!m_renderer)
2135        return false;
2136
2137    Node* node = m_renderer->node();
2138    if (!node)
2139        return false;
2140
2141    const AtomicString& ariaSelected = getAttribute(aria_selectedAttr);
2142    if (equalIgnoringCase(ariaSelected, "true"))
2143        return true;
2144
2145    if (isTabItem() && isTabItemSelected())
2146        return true;
2147
2148    return false;
2149}
2150
2151bool AccessibilityRenderObject::isTabItemSelected() const
2152{
2153    if (!isTabItem() || !m_renderer)
2154        return false;
2155
2156    Node* node = m_renderer->node();
2157    if (!node || !node->isElementNode())
2158        return false;
2159
2160    // The ARIA spec says a tab item can also be selected if it is aria-labeled by a tabpanel
2161    // that has keyboard focus inside of it, or if a tabpanel in its aria-controls list has KB
2162    // focus inside of it.
2163    AccessibilityObject* focusedElement = focusedUIElement();
2164    if (!focusedElement)
2165        return false;
2166
2167    Vector<Element*> elements;
2168    elementsFromAttribute(elements, aria_controlsAttr);
2169
2170    unsigned count = elements.size();
2171    for (unsigned k = 0; k < count; ++k) {
2172        Element* element = elements[k];
2173        AccessibilityObject* tabPanel = axObjectCache()->getOrCreate(element->renderer());
2174
2175        // A tab item should only control tab panels.
2176        if (!tabPanel || tabPanel->roleValue() != TabPanelRole)
2177            continue;
2178
2179        AccessibilityObject* checkFocusElement = focusedElement;
2180        // Check if the focused element is a descendant of the element controlled by the tab item.
2181        while (checkFocusElement) {
2182            if (tabPanel == checkFocusElement)
2183                return true;
2184            checkFocusElement = checkFocusElement->parentObject();
2185        }
2186    }
2187
2188    return false;
2189}
2190
2191bool AccessibilityRenderObject::isFocused() const
2192{
2193    if (!m_renderer)
2194        return false;
2195
2196    Document* document = m_renderer->document();
2197    if (!document)
2198        return false;
2199
2200    Node* focusedNode = document->focusedNode();
2201    if (!focusedNode)
2202        return false;
2203
2204    // A web area is represented by the Document node in the DOM tree, which isn't focusable.
2205    // Check instead if the frame's selection controller is focused
2206    if (focusedNode == m_renderer->node()
2207        || (roleValue() == WebAreaRole && document->frame()->selection()->isFocusedAndActive()))
2208        return true;
2209
2210    return false;
2211}
2212
2213void AccessibilityRenderObject::setFocused(bool on)
2214{
2215    if (!canSetFocusAttribute())
2216        return;
2217
2218    if (!on)
2219        m_renderer->document()->setFocusedNode(0);
2220    else {
2221        if (m_renderer->node()->isElementNode())
2222            static_cast<Element*>(m_renderer->node())->focus();
2223        else
2224            m_renderer->document()->setFocusedNode(m_renderer->node());
2225    }
2226}
2227
2228void AccessibilityRenderObject::changeValueByPercent(float percentChange)
2229{
2230    float range = maxValueForRange() - minValueForRange();
2231    float value = valueForRange();
2232
2233    value += range * (percentChange / 100);
2234    setValue(String::number(value));
2235
2236    axObjectCache()->postNotification(m_renderer, AXObjectCache::AXValueChanged, true);
2237}
2238
2239void AccessibilityRenderObject::setSelected(bool enabled)
2240{
2241    setElementAttributeValue(aria_selectedAttr, enabled);
2242}
2243
2244void AccessibilityRenderObject::setSelectedRows(AccessibilityChildrenVector& selectedRows)
2245{
2246    // Setting selected only makes sense in trees and tables (and tree-tables).
2247    AccessibilityRole role = roleValue();
2248    if (role != TreeRole && role != TreeGridRole && role != TableRole)
2249        return;
2250
2251    bool isMulti = isMultiSelectable();
2252    unsigned count = selectedRows.size();
2253    if (count > 1 && !isMulti)
2254        count = 1;
2255
2256    for (unsigned k = 0; k < count; ++k)
2257        selectedRows[k]->setSelected(true);
2258}
2259
2260void AccessibilityRenderObject::setValue(const String& string)
2261{
2262    if (!m_renderer || !m_renderer->node() || !m_renderer->node()->isElementNode())
2263        return;
2264    Element* element = static_cast<Element*>(m_renderer->node());
2265
2266    if (roleValue() == SliderRole)
2267        element->setAttribute(aria_valuenowAttr, string);
2268
2269    if (!m_renderer->isBoxModelObject())
2270        return;
2271    RenderBoxModelObject* renderer = toRenderBoxModelObject(m_renderer);
2272
2273    // FIXME: Do we want to do anything here for ARIA textboxes?
2274    if (renderer->isTextField()) {
2275        // FIXME: This is not safe!  Other elements could have a TextField renderer.
2276        static_cast<HTMLInputElement*>(element)->setValue(string);
2277    } else if (renderer->isTextArea()) {
2278        // FIXME: This is not safe!  Other elements could have a TextArea renderer.
2279        static_cast<HTMLTextAreaElement*>(element)->setValue(string);
2280    }
2281}
2282
2283void AccessibilityRenderObject::ariaOwnsElements(AccessibilityChildrenVector& axObjects) const
2284{
2285    Vector<Element*> elements;
2286    elementsFromAttribute(elements, aria_ownsAttr);
2287
2288    unsigned count = elements.size();
2289    for (unsigned k = 0; k < count; ++k) {
2290        RenderObject* render = elements[k]->renderer();
2291        AccessibilityObject* obj = axObjectCache()->getOrCreate(render);
2292        if (obj)
2293            axObjects.append(obj);
2294    }
2295}
2296
2297bool AccessibilityRenderObject::supportsARIAOwns() const
2298{
2299    if (!m_renderer)
2300        return false;
2301    const AtomicString& ariaOwns = getAttribute(aria_ownsAttr);
2302
2303    return !ariaOwns.isEmpty();
2304}
2305
2306bool AccessibilityRenderObject::isEnabled() const
2307{
2308    ASSERT(m_renderer);
2309
2310    if (equalIgnoringCase(getAttribute(aria_disabledAttr), "true"))
2311        return false;
2312
2313    Node* node = m_renderer->node();
2314    if (!node || !node->isElementNode())
2315        return true;
2316
2317    return static_cast<Element*>(node)->isEnabledFormControl();
2318}
2319
2320RenderView* AccessibilityRenderObject::topRenderer() const
2321{
2322    return m_renderer->document()->topDocument()->renderView();
2323}
2324
2325Document* AccessibilityRenderObject::document() const
2326{
2327    if (!m_renderer)
2328        return 0;
2329    return m_renderer->document();
2330}
2331
2332FrameView* AccessibilityRenderObject::topDocumentFrameView() const
2333{
2334    return topRenderer()->view()->frameView();
2335}
2336
2337Widget* AccessibilityRenderObject::widget() const
2338{
2339    if (!m_renderer->isBoxModelObject() || !toRenderBoxModelObject(m_renderer)->isWidget())
2340        return 0;
2341    return toRenderWidget(m_renderer)->widget();
2342}
2343
2344AccessibilityObject* AccessibilityRenderObject::accessibilityParentForImageMap(HTMLMapElement* map) const
2345{
2346    // find an image that is using this map
2347    if (!map)
2348        return 0;
2349
2350    HTMLImageElement* imageElement = map->imageElement();
2351    if (!imageElement)
2352        return 0;
2353
2354    return axObjectCache()->getOrCreate(imageElement->renderer());
2355}
2356
2357void AccessibilityRenderObject::getDocumentLinks(AccessibilityChildrenVector& result)
2358{
2359    Document* document = m_renderer->document();
2360    RefPtr<HTMLCollection> coll = document->links();
2361    Node* curr = coll->firstItem();
2362    while (curr) {
2363        RenderObject* obj = curr->renderer();
2364        if (obj) {
2365            RefPtr<AccessibilityObject> axobj = document->axObjectCache()->getOrCreate(obj);
2366            ASSERT(axobj);
2367            if (!axobj->accessibilityIsIgnored() && axobj->isLink())
2368                result.append(axobj);
2369        } else {
2370            Node* parent = curr->parentNode();
2371            if (parent && curr->hasTagName(areaTag) && parent->hasTagName(mapTag)) {
2372                AccessibilityImageMapLink* areaObject = static_cast<AccessibilityImageMapLink*>(axObjectCache()->getOrCreate(ImageMapLinkRole));
2373                areaObject->setHTMLAreaElement(static_cast<HTMLAreaElement*>(curr));
2374                areaObject->setHTMLMapElement(static_cast<HTMLMapElement*>(parent));
2375                areaObject->setParent(accessibilityParentForImageMap(static_cast<HTMLMapElement*>(parent)));
2376
2377                result.append(areaObject);
2378            }
2379        }
2380        curr = coll->nextItem();
2381    }
2382}
2383
2384FrameView* AccessibilityRenderObject::documentFrameView() const
2385{
2386    if (!m_renderer || !m_renderer->document())
2387        return 0;
2388
2389    // this is the RenderObject's Document's Frame's FrameView
2390    return m_renderer->document()->view();
2391}
2392
2393Widget* AccessibilityRenderObject::widgetForAttachmentView() const
2394{
2395    if (!isAttachment())
2396        return 0;
2397    return toRenderWidget(m_renderer)->widget();
2398}
2399
2400FrameView* AccessibilityRenderObject::frameViewIfRenderView() const
2401{
2402    if (!m_renderer->isRenderView())
2403        return 0;
2404    // this is the RenderObject's Document's renderer's FrameView
2405    return m_renderer->view()->frameView();
2406}
2407
2408// This function is like a cross-platform version of - (WebCoreTextMarkerRange*)textMarkerRange. It returns
2409// a Range that we can convert to a WebCoreTextMarkerRange in the Obj-C file
2410VisiblePositionRange AccessibilityRenderObject::visiblePositionRange() const
2411{
2412    if (!m_renderer)
2413        return VisiblePositionRange();
2414
2415    // construct VisiblePositions for start and end
2416    Node* node = m_renderer->node();
2417    if (!node)
2418        return VisiblePositionRange();
2419
2420    VisiblePosition startPos = firstPositionInOrBeforeNode(node);
2421    VisiblePosition endPos = lastPositionInOrAfterNode(node);
2422
2423    // the VisiblePositions are equal for nodes like buttons, so adjust for that
2424    // FIXME: Really?  [button, 0] and [button, 1] are distinct (before and after the button)
2425    // I expect this code is only hit for things like empty divs?  In which case I don't think
2426    // the behavior is correct here -- eseidel
2427    if (startPos == endPos) {
2428        endPos = endPos.next();
2429        if (endPos.isNull())
2430            endPos = startPos;
2431    }
2432
2433    return VisiblePositionRange(startPos, endPos);
2434}
2435
2436VisiblePositionRange AccessibilityRenderObject::visiblePositionRangeForLine(unsigned lineCount) const
2437{
2438    if (!lineCount || !m_renderer)
2439        return VisiblePositionRange();
2440
2441    // iterate over the lines
2442    // FIXME: this is wrong when lineNumber is lineCount+1,  because nextLinePosition takes you to the
2443    // last offset of the last line
2444    VisiblePosition visiblePos = m_renderer->document()->renderer()->positionForCoordinates(0, 0);
2445    VisiblePosition savedVisiblePos;
2446    while (--lineCount) {
2447        savedVisiblePos = visiblePos;
2448        visiblePos = nextLinePosition(visiblePos, 0);
2449        if (visiblePos.isNull() || visiblePos == savedVisiblePos)
2450            return VisiblePositionRange();
2451    }
2452
2453    // make a caret selection for the marker position, then extend it to the line
2454    // NOTE: ignores results of sel.modify because it returns false when
2455    // starting at an empty line.  The resulting selection in that case
2456    // will be a caret at visiblePos.
2457    SelectionController selection;
2458    selection.setSelection(VisibleSelection(visiblePos));
2459    selection.modify(SelectionController::AlterationExtend, DirectionRight, LineBoundary);
2460
2461    return VisiblePositionRange(selection.selection().visibleStart(), selection.selection().visibleEnd());
2462}
2463
2464VisiblePosition AccessibilityRenderObject::visiblePositionForIndex(int index) const
2465{
2466    if (!m_renderer)
2467        return VisiblePosition();
2468
2469    if (isNativeTextControl())
2470        return toRenderTextControl(m_renderer)->visiblePositionForIndex(index);
2471
2472    if (!allowsTextRanges() && !m_renderer->isText())
2473        return VisiblePosition();
2474
2475    Node* node = m_renderer->node();
2476    if (!node)
2477        return VisiblePosition();
2478
2479    if (index <= 0)
2480        return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM);
2481
2482    ExceptionCode ec = 0;
2483    RefPtr<Range> range = Range::create(m_renderer->document());
2484    range->selectNodeContents(node, ec);
2485    CharacterIterator it(range.get());
2486    it.advance(index - 1);
2487    return VisiblePosition(Position(it.range()->endContainer(ec), it.range()->endOffset(ec), Position::PositionIsOffsetInAnchor), UPSTREAM);
2488}
2489
2490int AccessibilityRenderObject::indexForVisiblePosition(const VisiblePosition& pos) const
2491{
2492    if (isNativeTextControl())
2493        return RenderTextControl::indexForVisiblePosition(toRenderTextControl(m_renderer)->innerTextElement(), pos);
2494
2495    if (!isTextControl())
2496        return 0;
2497
2498    Node* node = m_renderer->node();
2499    if (!node)
2500        return 0;
2501
2502    Position indexPosition = pos.deepEquivalent();
2503    if (!indexPosition.anchorNode() || indexPosition.anchorNode()->rootEditableElement() != node)
2504        return 0;
2505
2506    ExceptionCode ec = 0;
2507    RefPtr<Range> range = Range::create(m_renderer->document());
2508    range->setStart(node, 0, ec);
2509    range->setEnd(indexPosition.anchorNode(), indexPosition.deprecatedEditingOffset(), ec);
2510
2511#if PLATFORM(GTK)
2512    // We need to consider replaced elements for GTK, as they will be
2513    // presented with the 'object replacement character' (0xFFFC).
2514    return TextIterator::rangeLength(range.get(), true);
2515#else
2516    return TextIterator::rangeLength(range.get());
2517#endif
2518}
2519
2520IntRect AccessibilityRenderObject::boundsForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const
2521{
2522    if (visiblePositionRange.isNull())
2523        return IntRect();
2524
2525    // Create a mutable VisiblePositionRange.
2526    VisiblePositionRange range(visiblePositionRange);
2527    IntRect rect1 = range.start.absoluteCaretBounds();
2528    IntRect rect2 = range.end.absoluteCaretBounds();
2529
2530    // readjust for position at the edge of a line.  This is to exclude line rect that doesn't need to be accounted in the range bounds
2531    if (rect2.y() != rect1.y()) {
2532        VisiblePosition endOfFirstLine = endOfLine(range.start);
2533        if (range.start == endOfFirstLine) {
2534            range.start.setAffinity(DOWNSTREAM);
2535            rect1 = range.start.absoluteCaretBounds();
2536        }
2537        if (range.end == endOfFirstLine) {
2538            range.end.setAffinity(UPSTREAM);
2539            rect2 = range.end.absoluteCaretBounds();
2540        }
2541    }
2542
2543    IntRect ourrect = rect1;
2544    ourrect.unite(rect2);
2545
2546    // if the rectangle spans lines and contains multiple text chars, use the range's bounding box intead
2547    if (rect1.maxY() != rect2.maxY()) {
2548        RefPtr<Range> dataRange = makeRange(range.start, range.end);
2549        IntRect boundingBox = dataRange->boundingBox();
2550        String rangeString = plainText(dataRange.get());
2551        if (rangeString.length() > 1 && !boundingBox.isEmpty())
2552            ourrect = boundingBox;
2553    }
2554
2555#if PLATFORM(MAC)
2556    return m_renderer->document()->view()->contentsToScreen(ourrect);
2557#else
2558    return ourrect;
2559#endif
2560}
2561
2562void AccessibilityRenderObject::setSelectedVisiblePositionRange(const VisiblePositionRange& range) const
2563{
2564    if (range.start.isNull() || range.end.isNull())
2565        return;
2566
2567    // make selection and tell the document to use it. if it's zero length, then move to that position
2568    if (range.start == range.end)
2569        m_renderer->frame()->selection()->moveTo(range.start, true);
2570    else {
2571        VisibleSelection newSelection = VisibleSelection(range.start, range.end);
2572        m_renderer->frame()->selection()->setSelection(newSelection);
2573    }
2574}
2575
2576VisiblePosition AccessibilityRenderObject::visiblePositionForPoint(const IntPoint& point) const
2577{
2578    if (!m_renderer)
2579        return VisiblePosition();
2580
2581    // convert absolute point to view coordinates
2582    FrameView* frameView = m_renderer->document()->topDocument()->renderer()->view()->frameView();
2583    RenderView* renderView = topRenderer();
2584    Node* innerNode = 0;
2585
2586    // locate the node containing the point
2587    IntPoint pointResult;
2588    while (1) {
2589        IntPoint ourpoint;
2590#if PLATFORM(MAC)
2591        ourpoint = frameView->screenToContents(point);
2592#else
2593        ourpoint = point;
2594#endif
2595        HitTestRequest request(HitTestRequest::ReadOnly |
2596                               HitTestRequest::Active);
2597        HitTestResult result(ourpoint);
2598        renderView->layer()->hitTest(request, result);
2599        innerNode = result.innerNode();
2600        if (!innerNode)
2601            return VisiblePosition();
2602
2603        RenderObject* renderer = innerNode->renderer();
2604        if (!renderer)
2605            return VisiblePosition();
2606
2607        pointResult = result.localPoint();
2608
2609        // done if hit something other than a widget
2610        if (!renderer->isWidget())
2611            break;
2612
2613        // descend into widget (FRAME, IFRAME, OBJECT...)
2614        Widget* widget = toRenderWidget(renderer)->widget();
2615        if (!widget || !widget->isFrameView())
2616            break;
2617        Frame* frame = static_cast<FrameView*>(widget)->frame();
2618        if (!frame)
2619            break;
2620        renderView = frame->document()->renderView();
2621        frameView = static_cast<FrameView*>(widget);
2622    }
2623
2624    return innerNode->renderer()->positionForPoint(pointResult);
2625}
2626
2627// NOTE: Consider providing this utility method as AX API
2628VisiblePosition AccessibilityRenderObject::visiblePositionForIndex(unsigned indexValue, bool lastIndexOK) const
2629{
2630    if (!isTextControl())
2631        return VisiblePosition();
2632
2633    // lastIndexOK specifies whether the position after the last character is acceptable
2634    if (indexValue >= text().length()) {
2635        if (!lastIndexOK || indexValue > text().length())
2636            return VisiblePosition();
2637    }
2638    VisiblePosition position = visiblePositionForIndex(indexValue);
2639    position.setAffinity(DOWNSTREAM);
2640    return position;
2641}
2642
2643// NOTE: Consider providing this utility method as AX API
2644int AccessibilityRenderObject::index(const VisiblePosition& position) const
2645{
2646    if (!isTextControl())
2647        return -1;
2648
2649    Node* node = position.deepEquivalent().deprecatedNode();
2650    if (!node)
2651        return -1;
2652
2653    for (RenderObject* renderer = node->renderer(); renderer && renderer->node(); renderer = renderer->parent()) {
2654        if (renderer == m_renderer)
2655            return indexForVisiblePosition(position);
2656    }
2657
2658    return -1;
2659}
2660
2661// Given a line number, the range of characters of the text associated with this accessibility
2662// object that contains the line number.
2663PlainTextRange AccessibilityRenderObject::doAXRangeForLine(unsigned lineNumber) const
2664{
2665    if (!isTextControl())
2666        return PlainTextRange();
2667
2668    // iterate to the specified line
2669    VisiblePosition visiblePos = visiblePositionForIndex(0);
2670    VisiblePosition savedVisiblePos;
2671    for (unsigned lineCount = lineNumber; lineCount; lineCount -= 1) {
2672        savedVisiblePos = visiblePos;
2673        visiblePos = nextLinePosition(visiblePos, 0);
2674        if (visiblePos.isNull() || visiblePos == savedVisiblePos)
2675            return PlainTextRange();
2676    }
2677
2678    // Get the end of the line based on the starting position.
2679    VisiblePosition endPosition = endOfLine(visiblePos);
2680
2681    int index1 = indexForVisiblePosition(visiblePos);
2682    int index2 = indexForVisiblePosition(endPosition);
2683
2684    // add one to the end index for a line break not caused by soft line wrap (to match AppKit)
2685    if (endPosition.affinity() == DOWNSTREAM && endPosition.next().isNotNull())
2686        index2 += 1;
2687
2688    // return nil rather than an zero-length range (to match AppKit)
2689    if (index1 == index2)
2690        return PlainTextRange();
2691
2692    return PlainTextRange(index1, index2 - index1);
2693}
2694
2695// The composed character range in the text associated with this accessibility object that
2696// is specified by the given index value. This parameterized attribute returns the complete
2697// range of characters (including surrogate pairs of multi-byte glyphs) at the given index.
2698PlainTextRange AccessibilityRenderObject::doAXRangeForIndex(unsigned index) const
2699{
2700    if (!isTextControl())
2701        return PlainTextRange();
2702
2703    String elementText = text();
2704    if (!elementText.length() || index > elementText.length() - 1)
2705        return PlainTextRange();
2706
2707    return PlainTextRange(index, 1);
2708}
2709
2710// A substring of the text associated with this accessibility object that is
2711// specified by the given character range.
2712String AccessibilityRenderObject::doAXStringForRange(const PlainTextRange& range) const
2713{
2714    if (isPasswordField())
2715        return String();
2716
2717    if (!range.length)
2718        return String();
2719
2720    if (!isTextControl())
2721        return String();
2722
2723    String elementText = text();
2724    if (range.start + range.length > elementText.length())
2725        return String();
2726
2727    return elementText.substring(range.start, range.length);
2728}
2729
2730// The bounding rectangle of the text associated with this accessibility object that is
2731// specified by the given range. This is the bounding rectangle a sighted user would see
2732// on the display screen, in pixels.
2733IntRect AccessibilityRenderObject::doAXBoundsForRange(const PlainTextRange& range) const
2734{
2735    if (allowsTextRanges())
2736        return boundsForVisiblePositionRange(visiblePositionRangeForRange(range));
2737    return IntRect();
2738}
2739
2740AccessibilityObject* AccessibilityRenderObject::accessibilityImageMapHitTest(HTMLAreaElement* area, const IntPoint& point) const
2741{
2742    if (!area)
2743        return 0;
2744
2745    HTMLMapElement* map = static_cast<HTMLMapElement*>(area->parentNode());
2746    AccessibilityObject* parent = accessibilityParentForImageMap(map);
2747    if (!parent)
2748        return 0;
2749
2750    AccessibilityObject::AccessibilityChildrenVector children = parent->children();
2751
2752    unsigned count = children.size();
2753    for (unsigned k = 0; k < count; ++k) {
2754        if (children[k]->elementRect().contains(point))
2755            return children[k].get();
2756    }
2757
2758    return 0;
2759}
2760
2761AccessibilityObject* AccessibilityRenderObject::accessibilityHitTest(const IntPoint& point) const
2762{
2763    if (!m_renderer || !m_renderer->hasLayer())
2764        return 0;
2765
2766    RenderLayer* layer = toRenderBox(m_renderer)->layer();
2767
2768    HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
2769    HitTestResult hitTestResult = HitTestResult(point);
2770    layer->hitTest(request, hitTestResult);
2771    if (!hitTestResult.innerNode())
2772        return 0;
2773    Node* node = hitTestResult.innerNode()->shadowAncestorNode();
2774
2775    if (node->hasTagName(areaTag))
2776        return accessibilityImageMapHitTest(static_cast<HTMLAreaElement*>(node), point);
2777
2778    if (node->hasTagName(optionTag))
2779        node = static_cast<HTMLOptionElement*>(node)->ownerSelectElement();
2780
2781    RenderObject* obj = node->renderer();
2782    if (!obj)
2783        return 0;
2784
2785    AccessibilityObject* result = obj->document()->axObjectCache()->getOrCreate(obj);
2786    result->updateChildrenIfNecessary();
2787
2788    // Allow the element to perform any hit-testing it might need to do to reach non-render children.
2789    result = result->elementAccessibilityHitTest(point);
2790
2791    if (result->accessibilityIsIgnored()) {
2792        // If this element is the label of a control, a hit test should return the control.
2793        AccessibilityObject* controlObject = result->correspondingControlForLabelElement();
2794        if (controlObject && !controlObject->exposesTitleUIElement())
2795            return controlObject;
2796
2797        result = result->parentObjectUnignored();
2798    }
2799
2800    return result;
2801}
2802
2803bool AccessibilityRenderObject::shouldFocusActiveDescendant() const
2804{
2805    switch (ariaRoleAttribute()) {
2806    case GroupRole:
2807    case ComboBoxRole:
2808    case ListBoxRole:
2809    case MenuRole:
2810    case MenuBarRole:
2811    case RadioGroupRole:
2812    case RowRole:
2813    case PopUpButtonRole:
2814    case ProgressIndicatorRole:
2815    case ToolbarRole:
2816    case OutlineRole:
2817    case TreeRole:
2818    case GridRole:
2819    /* FIXME: replace these with actual roles when they are added to AccessibilityRole
2820    composite
2821    alert
2822    alertdialog
2823    status
2824    timer
2825    */
2826        return true;
2827    default:
2828        return false;
2829    }
2830}
2831
2832AccessibilityObject* AccessibilityRenderObject::activeDescendant() const
2833{
2834    if (!m_renderer)
2835        return 0;
2836
2837    if (m_renderer->node() && !m_renderer->node()->isElementNode())
2838        return 0;
2839    Element* element = static_cast<Element*>(m_renderer->node());
2840
2841    const AtomicString& activeDescendantAttrStr = element->getAttribute(aria_activedescendantAttr);
2842    if (activeDescendantAttrStr.isNull() || activeDescendantAttrStr.isEmpty())
2843        return 0;
2844
2845    Element* target = document()->getElementById(activeDescendantAttrStr);
2846    if (!target)
2847        return 0;
2848
2849    AccessibilityObject* obj = axObjectCache()->getOrCreate(target->renderer());
2850    if (obj && obj->isAccessibilityRenderObject())
2851    // an activedescendant is only useful if it has a renderer, because that's what's needed to post the notification
2852        return obj;
2853    return 0;
2854}
2855
2856void AccessibilityRenderObject::handleAriaExpandedChanged()
2857{
2858    // Find if a parent of this object should handle aria-expanded changes.
2859    AccessibilityObject* containerParent = this->parentObject();
2860    while (containerParent) {
2861        bool foundParent = false;
2862
2863        switch (containerParent->roleValue()) {
2864        case TreeRole:
2865        case TreeGridRole:
2866        case GridRole:
2867        case TableRole:
2868        case BrowserRole:
2869            foundParent = true;
2870            break;
2871        default:
2872            break;
2873        }
2874
2875        if (foundParent)
2876            break;
2877
2878        containerParent = containerParent->parentObject();
2879    }
2880
2881    // Post that the row count changed.
2882    if (containerParent)
2883        axObjectCache()->postNotification(containerParent, document(), AXObjectCache::AXRowCountChanged, true);
2884
2885    // Post that the specific row either collapsed or expanded.
2886    if (roleValue() == RowRole || roleValue() == TreeItemRole)
2887        axObjectCache()->postNotification(this, document(), isExpanded() ? AXObjectCache::AXRowExpanded : AXObjectCache::AXRowCollapsed, true);
2888}
2889
2890void AccessibilityRenderObject::handleActiveDescendantChanged()
2891{
2892    Element* element = static_cast<Element*>(renderer()->node());
2893    if (!element)
2894        return;
2895    Document* doc = renderer()->document();
2896    if (!doc->frame()->selection()->isFocusedAndActive() || doc->focusedNode() != element)
2897        return;
2898    AccessibilityRenderObject* activedescendant = static_cast<AccessibilityRenderObject*>(activeDescendant());
2899
2900    if (activedescendant && shouldFocusActiveDescendant())
2901        doc->axObjectCache()->postNotification(m_renderer, AXObjectCache::AXActiveDescendantChanged, true);
2902}
2903
2904AccessibilityObject* AccessibilityRenderObject::correspondingControlForLabelElement() const
2905{
2906    HTMLLabelElement* labelElement = labelElementContainer();
2907    if (!labelElement)
2908        return 0;
2909
2910    HTMLElement* correspondingControl = labelElement->control();
2911    if (!correspondingControl)
2912        return 0;
2913
2914    return axObjectCache()->getOrCreate(correspondingControl->renderer());
2915}
2916
2917AccessibilityObject* AccessibilityRenderObject::correspondingLabelForControlElement() const
2918{
2919    if (!m_renderer)
2920        return 0;
2921
2922    Node* node = m_renderer->node();
2923    if (node && node->isHTMLElement()) {
2924        HTMLLabelElement* label = labelForElement(static_cast<Element*>(node));
2925        if (label)
2926            return axObjectCache()->getOrCreate(label->renderer());
2927    }
2928
2929    return 0;
2930}
2931
2932bool AccessibilityRenderObject::renderObjectIsObservable(RenderObject* renderer) const
2933{
2934    // AX clients will listen for AXValueChange on a text control.
2935    if (renderer->isTextControl())
2936        return true;
2937
2938    // AX clients will listen for AXSelectedChildrenChanged on listboxes.
2939    Node* node = renderer->node();
2940    if (nodeHasRole(node, "listbox") || (renderer->isBoxModelObject() && toRenderBoxModelObject(renderer)->isListBox()))
2941        return true;
2942
2943    // Textboxes should send out notifications.
2944    if (nodeHasRole(node, "textbox"))
2945        return true;
2946
2947    return false;
2948}
2949
2950AccessibilityObject* AccessibilityRenderObject::observableObject() const
2951{
2952    // Find the object going up the parent chain that is used in accessibility to monitor certain notifications.
2953    for (RenderObject* renderer = m_renderer; renderer && renderer->node(); renderer = renderer->parent()) {
2954        if (renderObjectIsObservable(renderer))
2955            return axObjectCache()->getOrCreate(renderer);
2956    }
2957
2958    return 0;
2959}
2960
2961AccessibilityRole AccessibilityRenderObject::determineAriaRoleAttribute() const
2962{
2963    const AtomicString& ariaRole = getAttribute(roleAttr);
2964    if (ariaRole.isNull() || ariaRole.isEmpty())
2965        return UnknownRole;
2966
2967    AccessibilityRole role = ariaRoleToWebCoreRole(ariaRole);
2968
2969    if (role == ButtonRole && ariaHasPopup())
2970        role = PopUpButtonRole;
2971
2972    if (role == TextAreaRole && ariaIsMultiline())
2973        role = TextFieldRole;
2974
2975    if (role)
2976        return role;
2977
2978    AccessibilityObject* parentObject = parentObjectUnignored();
2979    if (!parentObject)
2980        return UnknownRole;
2981
2982    AccessibilityRole parentAriaRole = parentObject->ariaRoleAttribute();
2983
2984    // selects and listboxes both have options as child roles, but they map to different roles within WebCore
2985    if (equalIgnoringCase(ariaRole, "option")) {
2986        if (parentAriaRole == MenuRole)
2987            return MenuItemRole;
2988        if (parentAriaRole == ListBoxRole)
2989            return ListBoxOptionRole;
2990    }
2991    // an aria "menuitem" may map to MenuButton or MenuItem depending on its parent
2992    if (equalIgnoringCase(ariaRole, "menuitem")) {
2993        if (parentAriaRole == GroupRole)
2994            return MenuButtonRole;
2995        if (parentAriaRole == MenuRole || parentAriaRole == MenuBarRole)
2996            return MenuItemRole;
2997    }
2998
2999    return UnknownRole;
3000}
3001
3002AccessibilityRole AccessibilityRenderObject::ariaRoleAttribute() const
3003{
3004    return m_ariaRole;
3005}
3006
3007void AccessibilityRenderObject::updateAccessibilityRole()
3008{
3009    bool ignoredStatus = accessibilityIsIgnored();
3010    m_role = determineAccessibilityRole();
3011
3012    // The AX hierarchy only needs to be updated if the ignored status of an element has changed.
3013    if (ignoredStatus != accessibilityIsIgnored())
3014        childrenChanged();
3015}
3016
3017AccessibilityRole AccessibilityRenderObject::determineAccessibilityRole()
3018{
3019    if (!m_renderer)
3020        return UnknownRole;
3021
3022    m_ariaRole = determineAriaRoleAttribute();
3023
3024    Node* node = m_renderer->node();
3025    AccessibilityRole ariaRole = ariaRoleAttribute();
3026    if (ariaRole != UnknownRole)
3027        return ariaRole;
3028
3029    RenderBoxModelObject* cssBox = renderBoxModelObject();
3030
3031    if (node && node->isLink()) {
3032        if (cssBox && cssBox->isImage())
3033            return ImageMapRole;
3034        return WebCoreLinkRole;
3035    }
3036    if (cssBox && cssBox->isListItem())
3037        return ListItemRole;
3038    if (m_renderer->isListMarker())
3039        return ListMarkerRole;
3040    if (node && node->hasTagName(buttonTag))
3041        return ButtonRole;
3042    if (m_renderer->isText())
3043        return StaticTextRole;
3044    if (cssBox && cssBox->isImage()) {
3045        if (node && node->hasTagName(inputTag))
3046            return ButtonRole;
3047        return ImageRole;
3048    }
3049    if (node && node->hasTagName(canvasTag))
3050        return ImageRole;
3051
3052    if (cssBox && cssBox->isRenderView())
3053        return WebAreaRole;
3054
3055    if (cssBox && cssBox->isTextField())
3056        return TextFieldRole;
3057
3058    if (cssBox && cssBox->isTextArea())
3059        return TextAreaRole;
3060
3061    if (node && node->hasTagName(inputTag)) {
3062        HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
3063        if (input->isCheckbox())
3064            return CheckBoxRole;
3065        if (input->isRadioButton())
3066            return RadioButtonRole;
3067        if (input->isTextButton())
3068            return ButtonRole;
3069    }
3070
3071    if (node && node->hasTagName(buttonTag))
3072        return ButtonRole;
3073
3074    if (isFileUploadButton())
3075        return ButtonRole;
3076
3077    if (cssBox && cssBox->isMenuList())
3078        return PopUpButtonRole;
3079
3080    if (headingLevel())
3081        return HeadingRole;
3082
3083#if ENABLE(MATHML)
3084    if (node && node->hasTagName(MathMLNames::mathTag))
3085        return DocumentMathRole;
3086#endif
3087
3088    if (node && node->hasTagName(ddTag))
3089        return DefinitionListDefinitionRole;
3090
3091    if (node && node->hasTagName(dtTag))
3092        return DefinitionListTermRole;
3093
3094    if (node && (node->hasTagName(rpTag) || node->hasTagName(rtTag)))
3095        return AnnotationRole;
3096
3097#if PLATFORM(GTK)
3098    // Gtk ATs expect all tables, data and layout, to be exposed as tables.
3099    if (node && (node->hasTagName(tdTag) || node->hasTagName(thTag)))
3100        return CellRole;
3101
3102    if (node && node->hasTagName(trTag))
3103        return RowRole;
3104
3105    if (node && node->hasTagName(tableTag))
3106        return TableRole;
3107#endif
3108
3109    // Table sections should be ignored.
3110    if (m_renderer->isTableSection())
3111        return IgnoredRole;
3112
3113#if PLATFORM(GTK)
3114    if (m_renderer->isHR())
3115        return SplitterRole;
3116
3117    if (node && node->hasTagName(pTag))
3118        return ParagraphRole;
3119
3120    if (node && node->hasTagName(labelTag))
3121        return LabelRole;
3122
3123    if (node && node->hasTagName(divTag))
3124        return DivRole;
3125
3126    if (node && node->hasTagName(formTag))
3127        return FormRole;
3128#else
3129    if (node && node->hasTagName(labelTag))
3130        return GroupRole;
3131#endif
3132
3133    if (m_renderer->isBlockFlow())
3134        return GroupRole;
3135
3136    // If the element does not have role, but it has ARIA attributes, accessibility should fallback to exposing it as a group.
3137    if (supportsARIAAttributes())
3138        return GroupRole;
3139
3140    return UnknownRole;
3141}
3142
3143AccessibilityOrientation AccessibilityRenderObject::orientation() const
3144{
3145    const AtomicString& ariaOrientation = getAttribute(aria_orientationAttr);
3146    if (equalIgnoringCase(ariaOrientation, "horizontal"))
3147        return AccessibilityOrientationHorizontal;
3148    if (equalIgnoringCase(ariaOrientation, "vertical"))
3149        return AccessibilityOrientationVertical;
3150
3151    return AccessibilityObject::orientation();
3152}
3153
3154bool AccessibilityRenderObject::inheritsPresentationalRole() const
3155{
3156    // ARIA spec says that when a parent object is presentational, and it has required child elements,
3157    // those child elements are also presentational. For example, <li> becomes presentational from <ul>.
3158    // http://www.w3.org/WAI/PF/aria/complete#presentation
3159    DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, listItemParents, ());
3160
3161    HashSet<QualifiedName>* possibleParentTagNames = 0;
3162    switch (roleValue()) {
3163    case ListItemRole:
3164    case ListMarkerRole:
3165        if (listItemParents.isEmpty()) {
3166            listItemParents.add(ulTag);
3167            listItemParents.add(olTag);
3168            listItemParents.add(dlTag);
3169        }
3170        possibleParentTagNames = &listItemParents;
3171        break;
3172    default:
3173        break;
3174    }
3175
3176    // Not all elements need to check for this, only ones that are required children.
3177    if (!possibleParentTagNames)
3178        return false;
3179
3180    for (AccessibilityObject* parent = parentObject(); parent; parent = parent->parentObject()) {
3181        if (!parent->isAccessibilityRenderObject())
3182            continue;
3183
3184        Node* elementNode = static_cast<AccessibilityRenderObject*>(parent)->node();
3185        if (!elementNode || !elementNode->isElementNode())
3186            continue;
3187
3188        // If native tag of the parent element matches an acceptable name, then return
3189        // based on its presentational status.
3190        if (possibleParentTagNames->contains(static_cast<Element*>(elementNode)->tagQName()))
3191            return parent->roleValue() == PresentationalRole;
3192    }
3193
3194    return false;
3195}
3196
3197bool AccessibilityRenderObject::isPresentationalChildOfAriaRole() const
3198{
3199    // Walk the parent chain looking for a parent that has presentational children
3200    AccessibilityObject* parent;
3201    for (parent = parentObject(); parent && !parent->ariaRoleHasPresentationalChildren(); parent = parent->parentObject())
3202    { }
3203
3204    return parent;
3205}
3206
3207bool AccessibilityRenderObject::ariaRoleHasPresentationalChildren() const
3208{
3209    switch (m_ariaRole) {
3210    case ButtonRole:
3211    case SliderRole:
3212    case ImageRole:
3213    case ProgressIndicatorRole:
3214    // case SeparatorRole:
3215        return true;
3216    default:
3217        return false;
3218    }
3219}
3220
3221bool AccessibilityRenderObject::canSetFocusAttribute() const
3222{
3223    ASSERT(m_renderer);
3224    Node* node = m_renderer->node();
3225
3226    // NOTE: It would be more accurate to ask the document whether setFocusedNode() would
3227    // do anything.  For example, setFocusedNode() will do nothing if the current focused
3228    // node will not relinquish the focus.
3229    if (!node || !node->isElementNode())
3230        return false;
3231
3232    if (!static_cast<Element*>(node)->isEnabledFormControl())
3233        return false;
3234
3235    switch (roleValue()) {
3236    case WebCoreLinkRole:
3237    case ImageMapLinkRole:
3238    case TextFieldRole:
3239    case TextAreaRole:
3240    case ButtonRole:
3241    case PopUpButtonRole:
3242    case CheckBoxRole:
3243    case RadioButtonRole:
3244    case SliderRole:
3245        return true;
3246    default:
3247        return node->supportsFocus();
3248    }
3249}
3250
3251bool AccessibilityRenderObject::canSetExpandedAttribute() const
3252{
3253    // An object can be expanded if it aria-expanded is true or false.
3254    const AtomicString& ariaExpanded = getAttribute(aria_expandedAttr);
3255    return equalIgnoringCase(ariaExpanded, "true") || equalIgnoringCase(ariaExpanded, "false");
3256}
3257
3258bool AccessibilityRenderObject::canSetValueAttribute() const
3259{
3260    if (equalIgnoringCase(getAttribute(aria_readonlyAttr), "true"))
3261        return false;
3262
3263    // Any node could be contenteditable, so isReadOnly should be relied upon
3264    // for this information for all elements.
3265    return isProgressIndicator() || isSlider() || !isReadOnly();
3266}
3267
3268bool AccessibilityRenderObject::canSetTextRangeAttributes() const
3269{
3270    return isTextControl();
3271}
3272
3273void AccessibilityRenderObject::contentChanged()
3274{
3275    // If this element supports ARIA live regions, then notify the AT of changes.
3276    AXObjectCache* cache = axObjectCache();
3277    for (RenderObject* renderParent = m_renderer; renderParent; renderParent = renderParent->parent()) {
3278        AccessibilityObject* parent = cache->get(renderParent);
3279        if (!parent)
3280            continue;
3281
3282        // If we find a parent that has ARIA live region on, send the notification and stop processing.
3283        // The spec does not talk about nested live regions.
3284        if (parent->supportsARIALiveRegion()) {
3285            axObjectCache()->postNotification(renderParent, AXObjectCache::AXLiveRegionChanged, true);
3286            break;
3287        }
3288    }
3289}
3290
3291void AccessibilityRenderObject::childrenChanged()
3292{
3293    // This method is meant as a quick way of marking a portion of the accessibility tree dirty.
3294    if (!m_renderer)
3295        return;
3296
3297    bool sentChildrenChanged = false;
3298
3299    // Go up the accessibility parent chain, but only if the element already exists. This method is
3300    // called during render layouts, minimal work should be done.
3301    // If AX elements are created now, they could interrogate the render tree while it's in a funky state.
3302    // At the same time, process ARIA live region changes.
3303    for (AccessibilityObject* parent = this; parent; parent = parent->parentObjectIfExists()) {
3304        if (!parent->isAccessibilityRenderObject())
3305            continue;
3306
3307        AccessibilityRenderObject* axParent = static_cast<AccessibilityRenderObject*>(parent);
3308
3309        // Send the children changed notification on the first accessibility render object ancestor.
3310        if (!sentChildrenChanged) {
3311            axObjectCache()->postNotification(axParent->renderer(), AXObjectCache::AXChildrenChanged, true);
3312            sentChildrenChanged = true;
3313        }
3314
3315        // Only do work if the children haven't been marked dirty. This has the effect of blocking
3316        // future live region change notifications until the AX tree has been accessed again. This
3317        // is a good performance win for all parties.
3318        if (!axParent->needsToUpdateChildren()) {
3319            axParent->setNeedsToUpdateChildren();
3320
3321            // If this element supports ARIA live regions, then notify the AT of changes.
3322            if (axParent->supportsARIALiveRegion())
3323                axObjectCache()->postNotification(axParent->renderer(), AXObjectCache::AXLiveRegionChanged, true);
3324        }
3325    }
3326}
3327
3328bool AccessibilityRenderObject::canHaveChildren() const
3329{
3330    if (!m_renderer)
3331        return false;
3332
3333    // Elements that should not have children
3334    switch (roleValue()) {
3335    case ImageRole:
3336    case ButtonRole:
3337    case PopUpButtonRole:
3338    case CheckBoxRole:
3339    case RadioButtonRole:
3340    case TabRole:
3341    case StaticTextRole:
3342    case ListBoxOptionRole:
3343    case ScrollBarRole:
3344        return false;
3345    default:
3346        return true;
3347    }
3348}
3349
3350void AccessibilityRenderObject::clearChildren()
3351{
3352    AccessibilityObject::clearChildren();
3353    m_childrenDirty = false;
3354}
3355
3356void AccessibilityRenderObject::updateChildrenIfNecessary()
3357{
3358    if (needsToUpdateChildren())
3359        clearChildren();
3360
3361    AccessibilityObject::updateChildrenIfNecessary();
3362}
3363
3364const AccessibilityObject::AccessibilityChildrenVector& AccessibilityRenderObject::children()
3365{
3366    updateChildrenIfNecessary();
3367
3368    return m_children;
3369}
3370
3371void AccessibilityRenderObject::addChildren()
3372{
3373    // If the need to add more children in addition to existing children arises,
3374    // childrenChanged should have been called, leaving the object with no children.
3375    ASSERT(!m_haveChildren);
3376
3377    // nothing to add if there is no RenderObject
3378    if (!m_renderer)
3379        return;
3380
3381    m_haveChildren = true;
3382
3383    if (!canHaveChildren())
3384        return;
3385
3386    // add all unignored acc children
3387    for (RefPtr<AccessibilityObject> obj = firstChild(); obj; obj = obj->nextSibling()) {
3388        if (obj->accessibilityIsIgnored()) {
3389            obj->updateChildrenIfNecessary();
3390            AccessibilityChildrenVector children = obj->children();
3391            unsigned length = children.size();
3392            for (unsigned i = 0; i < length; ++i)
3393                m_children.append(children[i]);
3394        } else {
3395            ASSERT(obj->parentObject() == this);
3396            m_children.append(obj);
3397        }
3398    }
3399
3400    // FrameView's need to be inserted into the AX hierarchy when encountered.
3401    if (isAttachment()) {
3402        Widget* widget = widgetForAttachmentView();
3403        if (widget && widget->isFrameView())
3404            m_children.append(axObjectCache()->getOrCreate(widget));
3405    }
3406
3407    // for a RenderImage, add the <area> elements as individual accessibility objects
3408    RenderBoxModelObject* cssBox = renderBoxModelObject();
3409    if (cssBox && cssBox->isRenderImage()) {
3410        HTMLMapElement* map = toRenderImage(cssBox)->imageMap();
3411        if (map) {
3412            for (Node* current = map->firstChild(); current; current = current->traverseNextNode(map)) {
3413
3414                // add an <area> element for this child if it has a link
3415                if (current->hasTagName(areaTag) && current->isLink()) {
3416                    AccessibilityImageMapLink* areaObject = static_cast<AccessibilityImageMapLink*>(axObjectCache()->getOrCreate(ImageMapLinkRole));
3417                    areaObject->setHTMLAreaElement(static_cast<HTMLAreaElement*>(current));
3418                    areaObject->setHTMLMapElement(map);
3419                    areaObject->setParent(this);
3420
3421                    m_children.append(areaObject);
3422                }
3423            }
3424        }
3425    }
3426}
3427
3428const AtomicString& AccessibilityRenderObject::ariaLiveRegionStatus() const
3429{
3430    DEFINE_STATIC_LOCAL(const AtomicString, liveRegionStatusAssertive, ("assertive"));
3431    DEFINE_STATIC_LOCAL(const AtomicString, liveRegionStatusPolite, ("polite"));
3432    DEFINE_STATIC_LOCAL(const AtomicString, liveRegionStatusOff, ("off"));
3433
3434    const AtomicString& liveRegionStatus = getAttribute(aria_liveAttr);
3435    // These roles have implicit live region status.
3436    if (liveRegionStatus.isEmpty()) {
3437        switch (roleValue()) {
3438        case ApplicationAlertDialogRole:
3439        case ApplicationAlertRole:
3440            return liveRegionStatusAssertive;
3441        case ApplicationLogRole:
3442        case ApplicationStatusRole:
3443            return liveRegionStatusPolite;
3444        case ApplicationTimerRole:
3445        case ApplicationMarqueeRole:
3446            return liveRegionStatusOff;
3447        default:
3448            break;
3449        }
3450    }
3451
3452    return liveRegionStatus;
3453}
3454
3455const AtomicString& AccessibilityRenderObject::ariaLiveRegionRelevant() const
3456{
3457    DEFINE_STATIC_LOCAL(const AtomicString, defaultLiveRegionRelevant, ("additions text"));
3458    const AtomicString& relevant = getAttribute(aria_relevantAttr);
3459
3460    // Default aria-relevant = "additions text".
3461    if (relevant.isEmpty())
3462        return defaultLiveRegionRelevant;
3463
3464    return relevant;
3465}
3466
3467bool AccessibilityRenderObject::ariaLiveRegionAtomic() const
3468{
3469    return elementAttributeValue(aria_atomicAttr);
3470}
3471
3472bool AccessibilityRenderObject::ariaLiveRegionBusy() const
3473{
3474    return elementAttributeValue(aria_busyAttr);
3475}
3476
3477void AccessibilityRenderObject::ariaSelectedRows(AccessibilityChildrenVector& result)
3478{
3479    // Get all the rows.
3480    AccessibilityChildrenVector allRows;
3481    ariaTreeRows(allRows);
3482
3483    // Determine which rows are selected.
3484    bool isMulti = isMultiSelectable();
3485
3486    // Prefer active descendant over aria-selected.
3487    AccessibilityObject* activeDesc = activeDescendant();
3488    if (activeDesc && (activeDesc->isTreeItem() || activeDesc->isTableRow())) {
3489        result.append(activeDesc);
3490        if (!isMulti)
3491            return;
3492    }
3493
3494    unsigned count = allRows.size();
3495    for (unsigned k = 0; k < count; ++k) {
3496        if (allRows[k]->isSelected()) {
3497            result.append(allRows[k]);
3498            if (!isMulti)
3499                break;
3500        }
3501    }
3502}
3503
3504void AccessibilityRenderObject::ariaListboxSelectedChildren(AccessibilityChildrenVector& result)
3505{
3506    bool isMulti = isMultiSelectable();
3507
3508    AccessibilityChildrenVector childObjects = children();
3509    unsigned childrenSize = childObjects.size();
3510    for (unsigned k = 0; k < childrenSize; ++k) {
3511        // Every child should have aria-role option, and if so, check for selected attribute/state.
3512        AccessibilityObject* child = childObjects[k].get();
3513        if (child->isSelected() && child->ariaRoleAttribute() == ListBoxOptionRole) {
3514            result.append(child);
3515            if (!isMulti)
3516                return;
3517        }
3518    }
3519}
3520
3521void AccessibilityRenderObject::selectedChildren(AccessibilityChildrenVector& result)
3522{
3523    ASSERT(result.isEmpty());
3524
3525    // only listboxes should be asked for their selected children.
3526    AccessibilityRole role = roleValue();
3527    if (role == ListBoxRole) // native list boxes would be AccessibilityListBoxes, so only check for aria list boxes
3528        ariaListboxSelectedChildren(result);
3529    else if (role == TreeRole || role == TreeGridRole || role == TableRole)
3530        ariaSelectedRows(result);
3531}
3532
3533void AccessibilityRenderObject::ariaListboxVisibleChildren(AccessibilityChildrenVector& result)
3534{
3535    if (!hasChildren())
3536        addChildren();
3537
3538    unsigned length = m_children.size();
3539    for (unsigned i = 0; i < length; i++) {
3540        if (!m_children[i]->isOffScreen())
3541            result.append(m_children[i]);
3542    }
3543}
3544
3545void AccessibilityRenderObject::visibleChildren(AccessibilityChildrenVector& result)
3546{
3547    ASSERT(result.isEmpty());
3548
3549    // only listboxes are asked for their visible children.
3550    if (ariaRoleAttribute() != ListBoxRole) { // native list boxes would be AccessibilityListBoxes, so only check for aria list boxes
3551        ASSERT_NOT_REACHED();
3552        return;
3553    }
3554    return ariaListboxVisibleChildren(result);
3555}
3556
3557void AccessibilityRenderObject::tabChildren(AccessibilityChildrenVector& result)
3558{
3559    ASSERT(roleValue() == TabListRole);
3560
3561    unsigned length = m_children.size();
3562    for (unsigned i = 0; i < length; ++i) {
3563        if (m_children[i]->isTabItem())
3564            result.append(m_children[i]);
3565    }
3566}
3567
3568const String& AccessibilityRenderObject::actionVerb() const
3569{
3570    // FIXME: Need to add verbs for select elements.
3571    DEFINE_STATIC_LOCAL(const String, buttonAction, (AXButtonActionVerb()));
3572    DEFINE_STATIC_LOCAL(const String, textFieldAction, (AXTextFieldActionVerb()));
3573    DEFINE_STATIC_LOCAL(const String, radioButtonAction, (AXRadioButtonActionVerb()));
3574    DEFINE_STATIC_LOCAL(const String, checkedCheckBoxAction, (AXCheckedCheckBoxActionVerb()));
3575    DEFINE_STATIC_LOCAL(const String, uncheckedCheckBoxAction, (AXUncheckedCheckBoxActionVerb()));
3576    DEFINE_STATIC_LOCAL(const String, linkAction, (AXLinkActionVerb()));
3577    DEFINE_STATIC_LOCAL(const String, noAction, ());
3578
3579    switch (roleValue()) {
3580    case ButtonRole:
3581        return buttonAction;
3582    case TextFieldRole:
3583    case TextAreaRole:
3584        return textFieldAction;
3585    case RadioButtonRole:
3586        return radioButtonAction;
3587    case CheckBoxRole:
3588        return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction;
3589    case LinkRole:
3590    case WebCoreLinkRole:
3591        return linkAction;
3592    default:
3593        return noAction;
3594    }
3595}
3596
3597void AccessibilityRenderObject::setAccessibleName(String& name)
3598{
3599    // Setting the accessible name can store the value in the DOM
3600    if (!m_renderer)
3601        return;
3602
3603    Node* domNode = 0;
3604    // For web areas, set the aria-label on the HTML element.
3605    if (isWebArea())
3606        domNode = m_renderer->document()->documentElement();
3607    else
3608        domNode = m_renderer->node();
3609
3610    if (domNode && domNode->isElementNode())
3611        static_cast<Element*>(domNode)->setAttribute(aria_labelAttr, name);
3612}
3613
3614void AccessibilityRenderObject::updateBackingStore()
3615{
3616    if (!m_renderer)
3617        return;
3618
3619    // Updating layout may delete m_renderer and this object.
3620    m_renderer->document()->updateLayoutIgnorePendingStylesheets();
3621}
3622
3623static bool isLinkable(const AccessibilityRenderObject& object)
3624{
3625    if (!object.renderer())
3626        return false;
3627
3628    // See https://wiki.mozilla.org/Accessibility/AT-Windows-API for the elements
3629    // Mozilla considers linkable.
3630    return object.isLink() || object.isImage() || object.renderer()->isText();
3631}
3632
3633String AccessibilityRenderObject::stringValueForMSAA() const
3634{
3635    if (isLinkable(*this)) {
3636        Element* anchor = anchorElement();
3637        if (anchor && anchor->hasTagName(aTag))
3638            return static_cast<HTMLAnchorElement*>(anchor)->href();
3639    }
3640
3641    return stringValue();
3642}
3643
3644bool AccessibilityRenderObject::isLinked() const
3645{
3646    if (!isLinkable(*this))
3647        return false;
3648
3649    Element* anchor = anchorElement();
3650    if (!anchor || !anchor->hasTagName(aTag))
3651        return false;
3652
3653    return !static_cast<HTMLAnchorElement*>(anchor)->href().isEmpty();
3654}
3655
3656String AccessibilityRenderObject::nameForMSAA() const
3657{
3658    if (m_renderer && m_renderer->isText())
3659        return textUnderElement();
3660
3661    return title();
3662}
3663
3664static bool shouldReturnTagNameAsRoleForMSAA(const Element& element)
3665{
3666    // See "document structure",
3667    // https://wiki.mozilla.org/Accessibility/AT-Windows-API
3668    // FIXME: Add the other tag names that should be returned as the role.
3669    return element.hasTagName(h1Tag) || element.hasTagName(h2Tag)
3670        || element.hasTagName(h3Tag) || element.hasTagName(h4Tag)
3671        || element.hasTagName(h5Tag) || element.hasTagName(h6Tag);
3672}
3673
3674String AccessibilityRenderObject::stringRoleForMSAA() const
3675{
3676    if (!m_renderer)
3677        return String();
3678
3679    Node* node = m_renderer->node();
3680    if (!node || !node->isElementNode())
3681        return String();
3682
3683    Element* element = static_cast<Element*>(node);
3684    if (!shouldReturnTagNameAsRoleForMSAA(*element))
3685        return String();
3686
3687    return element->tagName();
3688}
3689
3690String AccessibilityRenderObject::positionalDescriptionForMSAA() const
3691{
3692    // See "positional descriptions",
3693    // https://wiki.mozilla.org/Accessibility/AT-Windows-API
3694    if (isHeading())
3695        return "L" + String::number(headingLevel());
3696
3697    // FIXME: Add positional descriptions for other elements.
3698    return String();
3699}
3700
3701String AccessibilityRenderObject::descriptionForMSAA() const
3702{
3703    String description = positionalDescriptionForMSAA();
3704    if (!description.isEmpty())
3705        return description;
3706
3707    description = accessibilityDescription();
3708    if (!description.isEmpty()) {
3709        // From the Mozilla MSAA implementation:
3710        // "Signal to screen readers that this description is speakable and is not
3711        // a formatted positional information description. Don't localize the
3712        // 'Description: ' part of this string, it will be parsed out by assistive
3713        // technologies."
3714        return "Description: " + description;
3715    }
3716
3717    return String();
3718}
3719
3720static AccessibilityRole msaaRoleForRenderer(const RenderObject* renderer)
3721{
3722    if (!renderer)
3723        return UnknownRole;
3724
3725    if (renderer->isText())
3726        return EditableTextRole;
3727
3728    if (renderer->isBoxModelObject() && toRenderBoxModelObject(renderer)->isListItem())
3729        return ListItemRole;
3730
3731    return UnknownRole;
3732}
3733
3734AccessibilityRole AccessibilityRenderObject::roleValueForMSAA() const
3735{
3736    if (m_roleForMSAA != UnknownRole)
3737        return m_roleForMSAA;
3738
3739    m_roleForMSAA = msaaRoleForRenderer(m_renderer);
3740
3741    if (m_roleForMSAA == UnknownRole)
3742        m_roleForMSAA = roleValue();
3743
3744    return m_roleForMSAA;
3745}
3746
3747} // namespace WebCore
3748