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