WebCore:
[WebKit-https.git] / WebCore / page / AccessibilityRenderObject.cpp
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 "AccessibilityListBox.h"
34 #include "CharacterNames.h"
35 #include "EventNames.h"
36 #include "FloatRect.h"
37 #include "FocusController.h"
38 #include "Frame.h"
39 #include "FrameLoader.h"
40 #include "HTMLAreaElement.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 "NotImplemented.h"
56 #include "Page.h"
57 #include "RenderFileUploadControl.h"
58 #include "RenderImage.h"
59 #include "RenderListBox.h"
60 #include "RenderListMarker.h"
61 #include "RenderMenuList.h"
62 #include "RenderTextControl.h"
63 #include "RenderTheme.h"
64 #include "RenderView.h"
65 #include "RenderWidget.h"
66 #include "SelectionController.h"
67 #include "Text.h"
68 #include "TextIterator.h"
69 #include "htmlediting.h"
70 #include "visible_units.h"
71
72 using namespace std;
73
74 namespace WebCore {
75
76 using namespace EventNames;
77 using namespace HTMLNames;
78
79 AccessibilityRenderObject::AccessibilityRenderObject(RenderObject* renderer)
80     : m_renderer(renderer)
81     , m_ariaRole(UnknownRole)
82 {
83     setAriaRole();
84 #ifndef NDEBUG
85     m_renderer->setHasAXObject(true);
86 #endif
87 }
88
89 AccessibilityRenderObject::~AccessibilityRenderObject()
90 {
91     ASSERT(isDetached());
92 }
93
94 PassRefPtr<AccessibilityRenderObject> AccessibilityRenderObject::create(RenderObject* renderer)
95 {
96     return adoptRef(new AccessibilityRenderObject(renderer));
97 }
98
99 void AccessibilityRenderObject::detach()
100 {
101     clearChildren();
102     AccessibilityObject::detach();
103     
104 #ifndef NDEBUG
105     if (m_renderer)
106         m_renderer->setHasAXObject(false);
107 #endif
108     m_renderer = 0;    
109 }
110
111 AccessibilityObject* AccessibilityRenderObject::firstChild() const
112 {
113     if (!m_renderer)
114         return 0;
115     
116     RenderObject* firstChild = m_renderer->firstChild();
117     if (!firstChild)
118         return 0;
119     
120     return m_renderer->document()->axObjectCache()->get(firstChild);
121 }
122
123 AccessibilityObject* AccessibilityRenderObject::lastChild() const
124 {
125     if (!m_renderer)
126         return 0;
127     
128     RenderObject* lastChild = m_renderer->lastChild();
129     if (!lastChild)
130         return 0;
131     
132     return m_renderer->document()->axObjectCache()->get(lastChild);
133 }
134
135 AccessibilityObject* AccessibilityRenderObject::previousSibling() const
136 {
137     if (!m_renderer)
138         return 0;
139     
140     RenderObject* previousSibling = m_renderer->previousSibling();
141     if (!previousSibling)
142         return 0;
143     
144     return m_renderer->document()->axObjectCache()->get(previousSibling);
145 }
146
147 AccessibilityObject* AccessibilityRenderObject::nextSibling() const
148 {
149     if (!m_renderer)
150         return 0;
151     
152     RenderObject* nextSibling = m_renderer->nextSibling();
153     if (!nextSibling)
154         return 0;
155     
156     return m_renderer->document()->axObjectCache()->get(nextSibling);
157 }
158
159 AccessibilityObject* AccessibilityRenderObject::parentObject() const
160 {
161     if (!m_renderer)
162         return 0;
163     
164     if (m_areaElement)
165         return m_renderer->document()->axObjectCache()->get(m_renderer);
166     
167     RenderObject *parent = m_renderer->parent();
168     if (!parent)
169         return 0;
170     
171     if (ariaRoleAttribute() == MenuBarRole)
172         return m_renderer->document()->axObjectCache()->get(parent);
173
174     // menuButton and its corresponding menu are DOM siblings, but Accessibility needs them to be parent/child
175     if (ariaRoleAttribute() == MenuRole) {
176         AccessibilityObject* parent = menuButtonForMenu();
177         if (parent)
178             return parent;
179     }
180     
181     return m_renderer->document()->axObjectCache()->get(parent);
182 }
183
184 bool AccessibilityRenderObject::isWebArea() const
185 {
186     return roleValue() == WebAreaRole;
187 }
188
189 bool AccessibilityRenderObject::isImageButton() const
190 {
191     return isNativeImage() && roleValue() == ButtonRole;
192 }
193
194 bool AccessibilityRenderObject::isAnchor() const
195 {
196     return m_areaElement || (!isNativeImage() && isLink());
197 }
198
199 bool AccessibilityRenderObject::isNativeTextControl() const
200 {
201     return m_renderer->isTextField() || m_renderer->isTextArea();
202 }
203     
204 bool AccessibilityRenderObject::isTextControl() const
205 {
206     AccessibilityRole role = roleValue();
207     return role == TextAreaRole || role == TextFieldRole;
208 }
209
210 bool AccessibilityRenderObject::isNativeImage() const
211 {
212     return m_renderer->isImage();
213 }    
214     
215 bool AccessibilityRenderObject::isImage() const
216 {
217     return roleValue() == ImageRole;
218 }
219
220 bool AccessibilityRenderObject::isAttachment() const
221 {
222     // Widgets are the replaced elements that we represent to AX as attachments
223     bool isWidget = m_renderer && m_renderer->isWidget();
224     ASSERT(!isWidget || (m_renderer->isReplaced() && !isImage()));
225     return isWidget && ariaRoleAttribute() == UnknownRole;
226 }
227
228 bool AccessibilityRenderObject::isPasswordField() const
229 {
230     ASSERT(m_renderer);
231     if (!m_renderer->element() || !m_renderer->element()->isHTMLElement())
232         return false;
233     return static_cast<HTMLElement*>(m_renderer->element())->isPasswordField() && ariaRoleAttribute() == UnknownRole;
234 }
235
236 bool AccessibilityRenderObject::isCheckboxOrRadio() const
237 {
238     AccessibilityRole role = roleValue();
239     return role == RadioButtonRole || role == CheckBoxRole;
240 }    
241     
242 bool AccessibilityRenderObject::isFileUploadButton() const
243 {
244     if (m_renderer && m_renderer->element() && m_renderer->element()->hasTagName(inputTag)) {
245         HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element());
246         return input->inputType() == HTMLInputElement::FILE;
247     }
248     
249     return false;
250 }
251
252 bool AccessibilityRenderObject::isProgressIndicator() const
253 {
254     return roleValue() == ProgressIndicatorRole;
255 }
256
257 bool AccessibilityRenderObject::isSlider() const
258 {
259     return roleValue() == SliderRole;
260 }
261     
262 bool AccessibilityRenderObject::isMenuRelated() const
263 {
264     AccessibilityRole role = roleValue();
265     return  role == MenuRole ||
266             role == MenuBarRole ||
267             role == MenuButtonRole ||
268             role == MenuItemRole;
269 }    
270
271 bool AccessibilityRenderObject::isMenu() const
272 {
273     return roleValue() == MenuRole;
274 }
275
276 bool AccessibilityRenderObject::isMenuBar() const
277 {
278     return roleValue() == MenuBarRole;
279 }
280
281 bool AccessibilityRenderObject::isMenuButton() const
282 {
283     return roleValue() == MenuButtonRole;
284 }
285
286 bool AccessibilityRenderObject::isMenuItem() const
287 {
288     return roleValue() == MenuItemRole;
289 }
290      
291 bool AccessibilityRenderObject::isPressed() const
292 {
293     ASSERT(m_renderer);
294     if (roleValue() != ButtonRole)
295         return false;
296
297     Node* node = m_renderer->node();
298     if (!node)
299         return false;
300
301     // If this is an ARIA button, check the aria-pressed attribute rather than node()->active()
302     if (ariaRoleAttribute() == ButtonRole) {
303         if (equalIgnoringCase(getAttribute(aria_pressedAttr).string(), "true"))
304             return true;
305         return false;
306     }
307
308     return node->active();
309 }
310
311 bool AccessibilityRenderObject::isIndeterminate() const
312 {
313     ASSERT(m_renderer);
314     return m_renderer->node() && m_renderer->node()->isIndeterminate();
315 }
316
317 bool AccessibilityRenderObject::isChecked() const
318 {
319     ASSERT(m_renderer);
320     return m_renderer->node() && m_renderer->node()->isChecked();
321 }
322
323 bool AccessibilityRenderObject::isHovered() const
324 {
325     ASSERT(m_renderer);
326     return m_renderer->node() && m_renderer->node()->hovered();
327 }
328
329 bool AccessibilityRenderObject::isMultiSelect() const
330 {
331     ASSERT(m_renderer);
332     if (!m_renderer->isListBox())
333         return false;
334     return m_renderer->element() && static_cast<HTMLSelectElement*>(m_renderer->element())->multiple();
335 }
336     
337 bool AccessibilityRenderObject::isReadOnly() const
338 {
339     ASSERT(m_renderer);
340     
341     if (isWebArea()) {
342         Document* document = m_renderer->document();
343         if (!document)
344             return true;
345         
346         Frame* frame = document->frame();
347         if (!frame)
348             return true;
349         
350         return !frame->isContentEditable();
351     }
352
353     return !m_renderer->node() || !m_renderer->node()->isContentEditable();
354 }
355
356 bool AccessibilityRenderObject::isOffScreen() const
357 {
358     ASSERT(m_renderer);
359     IntRect contentRect = m_renderer->absoluteClippedOverflowRect();
360     FrameView* view = m_renderer->document()->frame()->view();
361     FloatRect viewRect = view->visibleContentRect();
362     viewRect.intersect(contentRect);
363     return viewRect.isEmpty();
364 }
365
366 int AccessibilityRenderObject::headingLevel(Node* node)
367 {
368     // headings can be in block flow and non-block flow
369     if (!node)
370         return 0;
371
372     if (RenderObject* renderer = node->renderer()) {
373         AccessibilityObject* axObjectForNode = node->document()->axObjectCache()->get(renderer);
374         if (axObjectForNode->ariaRoleAttribute() == HeadingRole) {
375             if (!node->isElementNode())
376                 return 0;
377             Element* element = static_cast<Element*>(node);
378             return element->getAttribute(aria_levelAttr).toInt();
379         }
380     }
381             
382     
383     if (node->hasTagName(h1Tag))
384         return 1;
385     
386     if (node->hasTagName(h2Tag))
387         return 2;
388     
389     if (node->hasTagName(h3Tag))
390         return 3;
391     
392     if (node->hasTagName(h4Tag))
393         return 4;
394     
395     if (node->hasTagName(h5Tag))
396         return 5;
397     
398     if (node->hasTagName(h6Tag))
399         return 6;
400     
401     return 0;
402 }
403
404 bool AccessibilityRenderObject::isHeading() const
405 {
406     return roleValue() == HeadingRole;
407 }
408     
409 bool AccessibilityRenderObject::isLink() const
410 {
411     return roleValue() == WebCoreLinkRole;
412 }    
413     
414 bool AccessibilityRenderObject::isControl() const
415 {
416     if (!m_renderer)
417         return false;
418     
419     Node* node = m_renderer->element();
420     return node && (node->isControl() || AccessibilityObject::isARIAControl(ariaRoleAttribute()));
421 }
422
423 const AtomicString& AccessibilityRenderObject::getAttribute(const QualifiedName& attribute) const
424 {
425     Node* node = m_renderer->element();
426     if (!node)
427         return nullAtom;
428
429     if (!node->isElementNode())
430         return nullAtom;
431
432     Element* element = static_cast<Element*>(node);
433     return element->getAttribute(attribute);
434 }
435
436 HTMLAnchorElement* AccessibilityRenderObject::anchorElement() const
437 {
438     // FIXME: In XHTML 2.0, any HTML element can have an href attribute. We will need to implement this to fully
439     // support ARIA links.
440     if (m_areaElement)
441         return m_areaElement.get();
442     
443     // Search up the render tree for a RenderObject with a DOM node.  Defer to an earlier continuation, though.
444     RenderObject* currRenderer;
445     for (currRenderer = m_renderer; currRenderer && !currRenderer->element(); currRenderer = currRenderer->parent()) {
446         if (currRenderer->continuation())
447             return currRenderer->document()->axObjectCache()->get(currRenderer->continuation())->anchorElement();
448     }
449     
450     // bail if none found
451     if (!currRenderer)
452         return 0;
453     
454     // search up the DOM tree for an anchor element
455     // NOTE: this assumes that any non-image with an anchor is an HTMLAnchorElement
456     Node* node = currRenderer->node();
457     for ( ; node; node = node->parentNode()) {
458         if (node->hasTagName(aTag))
459             return static_cast<HTMLAnchorElement*>(node);
460     }
461     
462     return 0;
463 }
464
465 Element* AccessibilityRenderObject::actionElement() const
466 {
467     if (m_renderer->element() && m_renderer->element()->hasTagName(inputTag)) {
468         HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element());
469         if (!input->disabled() && (isCheckboxOrRadio() || input->isTextButton()))
470             return input;
471     }
472             
473     if (isFileUploadButton())
474         return static_cast<Element*>(m_renderer->element());
475             
476     if (AccessibilityObject::isARIAInput(ariaRoleAttribute()))
477         return static_cast<Element*>(m_renderer->element());
478
479     if (isImageButton())
480         return static_cast<Element*>(m_renderer->element());
481     
482     if (m_renderer->isMenuList())
483         return static_cast<RenderMenuList*>(m_renderer)->selectElement();
484     
485     Element* elt = anchorElement();
486     if (!elt)
487         elt = mouseButtonListener();
488     return elt;
489 }
490
491 Element* AccessibilityRenderObject::mouseButtonListener() const
492 {
493     Node* node = m_renderer->element();
494     if (!node)
495         return 0;
496     if (!node->isEventTargetNode())
497         return 0;
498     
499     // FIXME: Do the continuation search like anchorElement does
500     for (EventTargetNode* elt = static_cast<EventTargetNode*>(node); elt; elt = static_cast<EventTargetNode*>(elt->parentNode())) {
501         if (elt->getHTMLEventListener(clickEvent) || elt->getHTMLEventListener(mousedownEvent) || elt->getHTMLEventListener(mouseupEvent))
502             return static_cast<Element*>(elt);
503     }
504     
505     return 0;
506 }
507
508 static Element* siblingWithAriaRole(String role, Node* node)
509 {
510     Node* sibling = node->parent()->firstChild();
511     while (sibling) {
512         if (sibling->isElementNode()) {
513             String siblingAriaRole = static_cast<Element*>(sibling)->getAttribute(roleAttr).string();
514             if (equalIgnoringCase(siblingAriaRole, role))
515                 return static_cast<Element*>(sibling);
516         }
517         sibling = sibling->nextSibling();
518     }
519     
520     return 0;
521 }
522
523 Element* AccessibilityRenderObject::menuElementForMenuButton() const
524 {
525     if (ariaRoleAttribute() != MenuButtonRole)
526         return 0;
527
528     return siblingWithAriaRole("menu", renderer()->node());
529 }
530
531 AccessibilityObject* AccessibilityRenderObject::menuForMenuButton() const
532 {
533     Element* menu = menuElementForMenuButton();
534     if (menu && menu->renderer())
535         return m_renderer->document()->axObjectCache()->get(menu->renderer());
536     return 0;
537 }
538
539 Element* AccessibilityRenderObject::menuItemElementForMenu() const
540 {
541     if (ariaRoleAttribute() != MenuRole)
542         return 0;
543     
544     return siblingWithAriaRole("menuitem", renderer()->node());    
545 }
546
547 AccessibilityObject* AccessibilityRenderObject::menuButtonForMenu() const
548 {
549     Element* menuItem = menuItemElementForMenu();
550
551     if (menuItem && menuItem->renderer()) {
552         // ARIA just has generic menu items.  AppKit needs to know if this is a top level items like MenuBarButton or MenuBarItem
553         AccessibilityObject* menuItemAX = m_renderer->document()->axObjectCache()->get(menuItem->renderer());
554         if (menuItemAX->isMenuButton())
555             return menuItemAX;
556     }
557     return 0;
558 }
559
560 String AccessibilityRenderObject::helpText() const
561 {
562     if (!m_renderer)
563         return String();
564     
565     if (m_areaElement) {
566         const AtomicString& summary = m_areaElement->getAttribute(summaryAttr);
567         if (!summary.isEmpty())
568             return summary;
569         const AtomicString& title = m_areaElement->getAttribute(titleAttr);
570         if (!title.isEmpty())
571             return title;
572     }
573     
574     for (RenderObject* curr = m_renderer; curr; curr = curr->parent()) {
575         if (curr->element() && curr->element()->isHTMLElement()) {
576             const AtomicString& summary = static_cast<Element*>(curr->element())->getAttribute(summaryAttr);
577             if (!summary.isEmpty())
578                 return summary;
579             const AtomicString& title = static_cast<Element*>(curr->element())->getAttribute(titleAttr);
580             if (!title.isEmpty())
581                 return title;
582         }
583     }
584     
585     return String();
586 }
587
588 String AccessibilityRenderObject::textUnderElement() const
589 {
590     if (!m_renderer)
591         return String();
592     
593     if (isFileUploadButton()) {
594         RenderFileUploadControl* uploadControl = static_cast<RenderFileUploadControl*>(m_renderer);
595         return uploadControl->buttonValue();
596     }
597     
598     Node* node = m_renderer->element();
599     if (node) {
600         if (Frame* frame = node->document()->frame()) {
601             // catch stale WebCoreAXObject (see <rdar://problem/3960196>)
602             if (frame->document() != node->document())
603                 return String();
604             return plainText(rangeOfContents(node).get());
605         }
606     }
607     
608     // return the null string for anonymous text because it is non-trivial to get
609     // the actual text and, so far, that is not needed
610     return String();
611 }
612
613 bool AccessibilityRenderObject::hasIntValue() const
614 {
615     if (isHeading())
616         return true;
617     
618     if (m_renderer->element() && isCheckboxOrRadio())
619         return true;
620     
621     return false;
622 }
623
624 int AccessibilityRenderObject::intValue() const
625 {
626     if (!m_renderer || m_areaElement || isPasswordField())
627         return 0;
628     
629     if (isHeading())
630         return headingLevel(m_renderer->element());
631     
632     Node* node = m_renderer->element();
633     if (!node || !isCheckboxOrRadio())
634         return 0;
635
636     // If this is an ARIA checkbox or radio, check the aria-checked attribute rather than node()->checked()
637     AccessibilityRole ariaRole = ariaRoleAttribute();
638     if (ariaRole == RadioButtonRole || ariaRole == CheckBoxRole) {
639         if (equalIgnoringCase(getAttribute(aria_checkedAttr).string(), "true"))
640             return true;
641         return false;
642     }
643     
644     return static_cast<HTMLInputElement*>(node)->checked();
645 }
646
647 float AccessibilityRenderObject::valueForRange() const
648 {
649     if (!isProgressIndicator() && !isSlider())
650         return 0.0f;
651
652     return getAttribute(aria_valuenowAttr).toFloat();
653 }
654
655 float AccessibilityRenderObject::maxValueForRange() const
656 {
657     if (!isProgressIndicator() && !isSlider())
658         return 0.0f;
659
660     return getAttribute(aria_valuemaxAttr).toFloat();
661 }
662
663 float AccessibilityRenderObject::minValueForRange() const
664 {
665     if (!isProgressIndicator() && !isSlider())
666         return 0.0f;
667
668     return getAttribute(aria_valueminAttr).toFloat();
669 }
670
671 String AccessibilityRenderObject::stringValue() const
672 {
673     if (!m_renderer || m_areaElement || isPasswordField())
674         return String();
675     
676     if (m_renderer->isText())
677         return textUnderElement();
678     
679     if (m_renderer->isMenuList())
680         return static_cast<RenderMenuList*>(m_renderer)->text();
681     
682     if (m_renderer->isListMarker())
683         return static_cast<RenderListMarker*>(m_renderer)->text();
684     
685     if (isWebArea()) {
686         if (m_renderer->document()->frame())
687             return String();
688         
689         // FIXME: should use startOfDocument and endOfDocument (or rangeForDocument?) here
690         VisiblePosition startVisiblePosition = m_renderer->positionForCoordinates(0, 0);
691         VisiblePosition endVisiblePosition = m_renderer->positionForCoordinates(INT_MAX, INT_MAX);
692         if (startVisiblePosition.isNull() || endVisiblePosition.isNull())
693             return String();
694         
695         return plainText(makeRange(startVisiblePosition, endVisiblePosition).get());
696     }
697     
698     if (isTextControl())
699         return text();
700     
701     if (isFileUploadButton()) {
702         RenderFileUploadControl* uploadControl = static_cast<RenderFileUploadControl*>(m_renderer);
703         return uploadControl->fileTextValue();
704     }
705     
706     // FIXME: We might need to implement a value here for more types
707     // FIXME: It would be better not to advertise a value at all for the types for which we don't implement one;
708     // this would require subclassing or making accessibilityAttributeNames do something other than return a
709     // single static array.
710     return String();
711 }
712
713 // This function implements the ARIA accessible name as described by the Mozilla
714 // ARIA Implementer's Guide.
715 static String accessibleNameForNode(Node* node)
716 {
717     if (node->isTextNode())
718         return static_cast<Text*>(node)->data();
719
720     if (node->hasTagName(inputTag))
721         return static_cast<HTMLInputElement*>(node)->value();
722
723     if (node->isHTMLElement()) {
724         const AtomicString& alt = static_cast<HTMLElement*>(node)->getAttribute(altAttr);
725         if (!alt.isEmpty())
726             return alt;
727     }
728
729     return String();
730 }
731
732 String AccessibilityRenderObject::ariaAccessiblityName(const String& s) const
733 {
734     Document* document = m_renderer->document();
735     if (!document)
736         return String();
737
738     String idList = s;
739     idList.replace('\n', ' ');
740     Vector<String> idVector;
741     idList.split(' ', idVector);
742
743     Vector<UChar> ariaLabel;
744     unsigned size = idVector.size();
745     for (unsigned i = 0; i < size; ++i) {
746         String idName = idVector[i];
747         Element* idElement = document->getElementById(idName);
748         if (idElement) {
749             String nameFragment = accessibleNameForNode(idElement);
750             ariaLabel.append(nameFragment.characters(), nameFragment.length());
751             for (Node* n = idElement->firstChild(); n; n = n->traverseNextNode(idElement->nextSibling())) {
752                 nameFragment = accessibleNameForNode(n);
753                 ariaLabel.append(nameFragment.characters(), nameFragment.length());
754             }
755             ariaLabel.append(' ');
756         }
757     }
758     return String::adopt(ariaLabel);
759 }
760
761 String AccessibilityRenderObject::ariaLabeledByAttribute() const
762 {
763     Node* node = m_renderer->node();
764     if (!node)
765         return String();
766
767     if (!node->isElementNode())
768         return String();
769
770     // The ARIA spec uses the British spelling: "labelled." It seems prudent to support the American
771     // spelling ("labeled") as well.
772     String idList = getAttribute(aria_labeledbyAttr).string();
773     if (idList.isEmpty()) {
774         idList = getAttribute(aria_labelledbyAttr).string();
775         if (idList.isEmpty())
776             return String();
777     }
778
779     return ariaAccessiblityName(idList);
780 }
781
782 static HTMLLabelElement* labelForElement(Element* element)
783 {
784     RefPtr<NodeList> list = element->document()->getElementsByTagName("label");
785     unsigned len = list->length();
786     for (unsigned i = 0; i < len; i++) {
787         if (list->item(i)->hasTagName(labelTag)) {
788             HTMLLabelElement* label = static_cast<HTMLLabelElement*>(list->item(i));
789             if (label->correspondingControl() == element)
790                 return label;
791         }
792     }
793     
794     return 0;
795 }
796     
797 HTMLLabelElement* AccessibilityRenderObject::labelElementContainer() const
798 {
799     if (!m_renderer)
800         return false;
801
802     // the control element should not be considered part of the label
803     if (isControl())
804         return false;
805     
806     // find if this has a parent that is a label
807     for (Node* parentNode = m_renderer->element(); parentNode; parentNode = parentNode->parentNode()) {
808         if (parentNode->hasTagName(labelTag))
809             return static_cast<HTMLLabelElement*>(parentNode);
810     }
811     
812     return 0;
813 }
814
815 String AccessibilityRenderObject::title() const
816 {
817     AccessibilityRole ariaRole = ariaRoleAttribute();
818     
819     if (!m_renderer || m_areaElement)
820         return String();
821
822     Node* node = m_renderer->element();
823     if (!node)
824         return String();
825     
826     String ariaLabel = ariaLabeledByAttribute();
827     if (!ariaLabel.isEmpty())
828         return ariaLabel;
829     
830     const AtomicString& title = getAttribute(titleAttr);
831     if (!title.isEmpty())
832         return title;
833     
834     bool isInputTag = node->hasTagName(inputTag);
835     if (isInputTag) {
836         HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
837         if (input->isTextButton())
838             return input->value();
839     }
840     
841     if (isInputTag || AccessibilityObject::isARIAInput(ariaRole) || isControl()) {
842         HTMLLabelElement* label = labelForElement(static_cast<Element*>(node));
843         if (label)
844             return label->innerText();
845     }
846     
847     if (roleValue() == ButtonRole
848         || ariaRole == ListBoxOptionRole
849         || ariaRole == MenuItemRole
850         || ariaRole == MenuButtonRole
851         || isHeading())
852         return textUnderElement();
853     
854     if (isLink())
855         return textUnderElement();
856     
857     return String();
858 }
859
860 String AccessibilityRenderObject::ariaDescribedByAttribute() const
861 {
862     String idList = getAttribute(aria_describedbyAttr).string();
863     if (idList.isEmpty())
864         return String();
865     
866     return ariaAccessiblityName(idList);
867 }
868
869 String AccessibilityRenderObject::accessibilityDescription() const
870 {
871     if (!m_renderer || m_areaElement)
872         return String();
873
874     String ariaDescription = ariaDescribedByAttribute();
875     if (!ariaDescription.isEmpty())
876         return ariaDescription;
877     
878     if (isImage()) {
879         if (m_renderer->element() && m_renderer->element()->isHTMLElement()) {
880             const AtomicString& alt = static_cast<HTMLElement*>(m_renderer->element())->getAttribute(altAttr);
881             if (alt.isEmpty())
882                 return String();
883             return alt;
884         }
885     }
886     
887     if (isWebArea()) {
888         Document *document = m_renderer->document();
889         Node* owner = document->ownerElement();
890         if (owner) {
891             if (owner->hasTagName(frameTag) || owner->hasTagName(iframeTag))
892                 return static_cast<HTMLFrameElementBase*>(owner)->name();
893             if (owner->isHTMLElement())
894                 return static_cast<HTMLElement*>(owner)->getAttribute(nameAttr);
895         }
896         owner = document->body();
897         if (owner && owner->isHTMLElement())
898             return static_cast<HTMLElement*>(owner)->getAttribute(nameAttr);
899     }
900     
901     return String();
902 }
903
904 IntRect AccessibilityRenderObject::boundingBoxRect() const
905 {
906     IntRect rect;
907     RenderObject* obj = m_renderer;
908     
909     if (!obj)
910         return IntRect();
911     
912     if (obj->isInlineContinuation())
913         obj = obj->element()->renderer();
914     
915     // FIXME: This doesn't work correctly with transforms.
916     Vector<IntRect> rects;
917     int x, y;
918     obj->absolutePosition(x, y);
919     obj->absoluteRects(rects, x, y);
920     const size_t n = rects.size();
921     for (size_t i = 0; i < n; ++i) {
922         IntRect r = rects[i];
923         if (!r.isEmpty()) {
924             if (obj->style()->hasAppearance())
925                 theme()->adjustRepaintRect(obj, r);
926             rect.unite(r);
927         }
928     }
929     return rect;
930 }
931     
932 IntRect AccessibilityRenderObject::checkboxOrRadioRect() const
933 {
934     if (!m_renderer)
935         return IntRect();
936     
937     HTMLLabelElement* label = labelForElement(static_cast<Element*>(m_renderer->element()));
938     if (!label || !label->renderer())
939         return boundingBoxRect();
940     
941     IntRect labelRect = axObjectCache()->get(label->renderer())->elementRect();
942     labelRect.unite(boundingBoxRect());
943     return labelRect;
944 }
945
946 IntRect AccessibilityRenderObject::elementRect() const
947 {
948     if (m_areaElement)
949         return m_areaElement->getRect(m_renderer);
950     
951     // a checkbox or radio button should encompass its label
952     if (isCheckboxOrRadio())
953         return checkboxOrRadioRect();
954     
955     return boundingBoxRect();
956 }
957
958 IntSize AccessibilityRenderObject::size() const
959 {
960     IntRect rect = elementRect();
961     return rect.size();
962 }
963
964 AccessibilityObject* AccessibilityRenderObject::internalLinkElement() const
965 {
966     HTMLAnchorElement* anchor = anchorElement();
967     if (!anchor)
968         return 0;
969     
970     KURL linkURL = anchor->href();
971     String ref = linkURL.ref();
972     if (ref.isEmpty())
973         return 0;
974     
975     // check if URL is the same as current URL
976     linkURL.setRef("");
977     if (m_renderer->document()->url() != linkURL)
978         return 0;
979     
980     Node* linkedNode = m_renderer->document()->getElementById(ref);
981     if (!linkedNode) {
982         linkedNode = m_renderer->document()->anchors()->namedItem(ref, !m_renderer->document()->inCompatMode());
983         if (!linkedNode)
984             return 0;
985     }
986     
987     // the element we find may not be accessible, keep searching until we find a good one
988     AccessibilityObject* linkedAXElement = m_renderer->document()->axObjectCache()->get(linkedNode->renderer());
989     while (linkedAXElement && linkedAXElement->accessibilityIsIgnored()) {
990         linkedNode = linkedNode->traverseNextNode();
991         if (!linkedNode)
992             return 0;
993         linkedAXElement = m_renderer->document()->axObjectCache()->get(linkedNode->renderer());
994     }
995     
996     return linkedAXElement;
997 }
998     
999 void AccessibilityRenderObject::addRadioButtonGroupMembers(AccessibilityChildrenVector& linkedUIElements) const
1000 {
1001     if (!m_renderer || roleValue() != RadioButtonRole)
1002         return;
1003     
1004     Node* node = m_renderer->node();
1005     if (!node || !node->hasTagName(inputTag))
1006         return;
1007     
1008     HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
1009     // if there's a form, then this is easy
1010     if (input->form()) {
1011         Vector<RefPtr<Node> > formElements;
1012         input->form()->getNamedElements(input->name(), formElements);
1013         
1014         unsigned len = formElements.size();
1015         for (unsigned i = 0; i < len; ++i) {
1016             Node* associateElement = formElements[i].get();
1017             if (AccessibilityObject* object = m_renderer->document()->axObjectCache()->get(associateElement->renderer()))
1018                 linkedUIElements.append(object);        
1019         } 
1020     } else {
1021         RefPtr<NodeList> list = node->document()->getElementsByTagName("input");
1022         unsigned len = list->length();
1023         for (unsigned i = 0; i < len; ++i) {
1024             if (list->item(i)->hasTagName(inputTag)) {
1025                 HTMLInputElement* associateElement = static_cast<HTMLInputElement*>(list->item(i));
1026                 if (associateElement->isRadioButton() && associateElement->name() == input->name()) {
1027                     if (AccessibilityObject* object = m_renderer->document()->axObjectCache()->get(associateElement->renderer()))
1028                         linkedUIElements.append(object);
1029                 }
1030             }
1031         }
1032     }
1033 }
1034     
1035 // linked ui elements could be all the related radio buttons in a group
1036 // or an internal anchor connection
1037 void AccessibilityRenderObject::linkedUIElements(AccessibilityChildrenVector& linkedUIElements) const
1038 {
1039     if (isAnchor()) {
1040         AccessibilityObject* linkedAXElement = internalLinkElement();
1041         if (linkedAXElement)
1042             linkedUIElements.append(linkedAXElement);
1043     }
1044
1045     if (roleValue() == RadioButtonRole)
1046         addRadioButtonGroupMembers(linkedUIElements);
1047 }
1048
1049 AccessibilityObject* AccessibilityRenderObject::titleUIElement() const
1050 {
1051     if (!m_renderer)
1052         return 0;
1053     
1054     // checkbox and radio hide their labels. Only controls get titleUIElements for now
1055     if (isCheckboxOrRadio() || !isControl())
1056         return 0;
1057     
1058     Node* element = m_renderer->element();
1059     HTMLLabelElement* label = labelForElement(static_cast<Element*>(element));
1060     if (label && label->renderer())
1061         return axObjectCache()->get(label->renderer());
1062
1063     return 0;   
1064 }
1065     
1066 bool AccessibilityRenderObject::accessibilityIsIgnored() const
1067 {
1068     // ignore invisible element
1069     if (!m_renderer || m_renderer->style()->visibility() != VISIBLE)
1070         return true;
1071
1072     if (isPresentationalChildOfAriaRole())
1073         return true;
1074         
1075     // ignore popup menu items because AppKit does
1076     for (RenderObject* parent = m_renderer->parent(); parent; parent = parent->parent()) {
1077         if (parent->isMenuList())
1078             return true;
1079     }
1080     
1081     // find out if this element is inside of a label element.
1082     // if so, it may be ignored because it's the label for a checkbox or radio button
1083     HTMLLabelElement* labelElement = labelElementContainer();
1084     if (labelElement) {
1085         HTMLElement* correspondingControl = labelElement->correspondingControl();
1086         if (correspondingControl && correspondingControl->renderer()) {
1087             AccessibilityObject* controlObject = axObjectCache()->get(correspondingControl->renderer());
1088             if (controlObject->isCheckboxOrRadio())
1089                 return true;
1090         }
1091     }
1092         
1093     AccessibilityRole ariaRole = ariaRoleAttribute();
1094     if (ariaRole == TextAreaRole || ariaRole == StaticTextRole) {
1095         String ariaText = text();
1096         return ariaText.isNull() || ariaText.isEmpty();
1097     }    
1098     
1099     // NOTE: BRs always have text boxes now, so the text box check here can be removed
1100     if (m_renderer->isText()) {
1101         // static text beneath MenuItems and MenuButtons are just reported along with the menu item, so it's ignored on an individual level
1102         if (parentObjectUnignored()->ariaRoleAttribute() == MenuItemRole ||
1103             parentObjectUnignored()->ariaRoleAttribute() == MenuButtonRole)
1104             return true;
1105          return m_renderer->isBR() || !static_cast<RenderText*>(m_renderer)->firstTextBox();
1106     }
1107     
1108     if (isHeading())
1109         return false;
1110     
1111     if (m_areaElement || isLink())
1112         return false;
1113     
1114     // all controls are accessible
1115     if (isControl())
1116         return false;
1117     
1118     // don't ignore labels, because they serve as TitleUIElements
1119     Node* node = m_renderer->element();
1120     if (node && node->hasTagName(labelTag))
1121         return false;
1122     
1123     if (m_renderer->isBlockFlow() && m_renderer->childrenInline())
1124         return !static_cast<RenderBlock*>(m_renderer)->firstLineBox() && !mouseButtonListener();
1125     
1126     // ignore images seemingly used as spacers
1127     if (isImage()) {
1128         if (node && node->isElementNode()) {
1129             Element* elt = static_cast<Element*>(node);
1130             const AtomicString& alt = elt->getAttribute(altAttr);
1131             // don't ignore an image that has an alt tag
1132             if (!alt.isEmpty())
1133                 return false;
1134             // informal standard is to ignore images with zero-length alt strings
1135             if (!alt.isNull())
1136                 return true;
1137         }
1138         
1139         // check for one-dimensional image
1140         if (m_renderer->height() <= 1 || m_renderer->width() <= 1)
1141             return true;
1142         
1143         // check whether rendered image was stretched from one-dimensional file image
1144         if (isNativeImage()) {
1145             RenderImage* image = static_cast<RenderImage*>(m_renderer);
1146             if (image->cachedImage()) {
1147                 IntSize imageSize = image->cachedImage()->imageSize(image->view()->zoomFactor());
1148                 return imageSize.height() <= 1 || imageSize.width() <= 1;
1149             }
1150         }
1151         return false;
1152     }
1153     
1154     if (ariaRole != UnknownRole)
1155         return false;
1156     
1157     if (isAttachment())
1158         return false;
1159     
1160     return !m_renderer->isListMarker() && !isWebArea();
1161 }
1162
1163 bool AccessibilityRenderObject::isLoaded() const
1164 {
1165     return !m_renderer->document()->tokenizer();
1166 }
1167
1168 int AccessibilityRenderObject::layoutCount() const
1169 {
1170     if (!m_renderer->isRenderView())
1171         return 0;
1172     return static_cast<RenderView*>(m_renderer)->frameView()->layoutCount();
1173 }
1174
1175 String AccessibilityRenderObject::text() const
1176 {
1177     if (!isTextControl() || isPasswordField())
1178         return String();
1179     
1180     if (isNativeTextControl())
1181         return static_cast<RenderTextControl*>(m_renderer)->text();
1182     
1183     Node* node = m_renderer->element();
1184     if (!node)
1185         return String();
1186     if (!node->isElementNode())
1187         return String();
1188     
1189     return static_cast<Element*>(node)->innerText();
1190 }
1191     
1192 int AccessibilityRenderObject::textLength() const
1193 {
1194     ASSERT(isTextControl());
1195     
1196     if (isPasswordField())
1197         return -1; // need to return something distinct from 0
1198     
1199     return text().length();
1200 }
1201
1202 PassRefPtr<Range> AccessibilityRenderObject::ariaSelectedTextDOMRange() const
1203 {
1204     Node* node = m_renderer->element();
1205     if (!node)
1206         return 0;
1207     
1208     RefPtr<Range> currentSelectionRange = selection().toRange();
1209     if (!currentSelectionRange)
1210         return 0;
1211     
1212     ExceptionCode ec = 0;
1213     if (!currentSelectionRange->intersectsNode(node, ec))
1214         return Range::create(currentSelectionRange->ownerDocument());
1215     
1216     RefPtr<Range> ariaRange = rangeOfContents(node);
1217     Position startPosition, endPosition;
1218     
1219     // Find intersection of currentSelectionRange and ariaRange
1220     if (ariaRange->startOffset() > currentSelectionRange->startOffset())
1221         startPosition = ariaRange->startPosition();
1222     else
1223         startPosition = currentSelectionRange->startPosition();
1224     
1225     if (ariaRange->endOffset() < currentSelectionRange->endOffset())
1226         endPosition = ariaRange->endPosition();
1227     else
1228         endPosition = currentSelectionRange->endPosition();
1229     
1230     return Range::create(ariaRange->ownerDocument(), startPosition, endPosition);
1231 }
1232
1233 String AccessibilityRenderObject::selectedText() const
1234 {
1235     ASSERT(isTextControl());
1236     
1237     if (isPasswordField())
1238         return String(); // need to return something distinct from empty string
1239     
1240     if (isNativeTextControl()) {
1241         RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
1242         return textControl->text().substring(textControl->selectionStart(), textControl->selectionEnd() - textControl->selectionStart());
1243     }
1244     
1245     if (ariaRoleAttribute() == UnknownRole)
1246         return String();
1247     
1248     RefPtr<Range> ariaRange = ariaSelectedTextDOMRange();
1249     if (!ariaRange)
1250         return String();
1251     return ariaRange->text();
1252 }
1253
1254 const AtomicString& AccessibilityRenderObject::accessKey() const
1255 {
1256     Node* node = m_renderer->element();
1257     if (!node)
1258         return nullAtom;
1259     if (!node->isElementNode())
1260         return nullAtom;
1261     return static_cast<Element*>(node)->getAttribute(accesskeyAttr);
1262 }
1263
1264 Selection AccessibilityRenderObject::selection() const
1265 {
1266     return m_renderer->document()->frame()->selection()->selection();
1267 }
1268
1269 PlainTextRange AccessibilityRenderObject::selectedTextRange() const
1270 {
1271     ASSERT(isTextControl());
1272     
1273     if (isPasswordField())
1274         return PlainTextRange();
1275     
1276     AccessibilityRole ariaRole = ariaRoleAttribute();
1277     if (isNativeTextControl() && ariaRole == UnknownRole) {
1278         RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
1279         return PlainTextRange(textControl->selectionStart(), textControl->selectionEnd() - textControl->selectionStart());
1280     }
1281     
1282     if (ariaRole == UnknownRole)
1283         return PlainTextRange();
1284     
1285     RefPtr<Range> ariaRange = ariaSelectedTextDOMRange();
1286     if (!ariaRange)
1287         return PlainTextRange();
1288     return PlainTextRange(ariaRange->startOffset(), ariaRange->endOffset());
1289 }
1290
1291 void AccessibilityRenderObject::setSelectedTextRange(const PlainTextRange& range)
1292 {
1293     if (isNativeTextControl()) {
1294         RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
1295         textControl->setSelectionRange(range.start, range.start + range.length);
1296     }
1297     
1298     Document* document = m_renderer->document();
1299     if (!document)
1300         return;
1301     Frame* frame = document->frame();
1302     if (!frame)
1303         return;
1304     Node* node = m_renderer->element();
1305     frame->selection()->setSelection(Selection(Position(node, range.start),
1306         Position(node, range.start + range.length), DOWNSTREAM));
1307 }
1308
1309 KURL AccessibilityRenderObject::url() const
1310 {
1311     if (isAnchor()) {
1312         if (HTMLAnchorElement* anchor = anchorElement())
1313             return anchor->href();
1314     }
1315     
1316     if (isWebArea())
1317         return m_renderer->document()->url();
1318     
1319     if (isImage() && m_renderer->element() && m_renderer->element()->hasTagName(imgTag))
1320         return static_cast<HTMLImageElement*>(m_renderer->element())->src();
1321     
1322     return KURL();
1323 }
1324
1325 bool AccessibilityRenderObject::isVisited() const
1326 {
1327     return m_renderer->style()->pseudoState() == PseudoVisited;
1328 }
1329
1330 bool AccessibilityRenderObject::isSelected() const
1331 {
1332     if (!m_renderer)
1333         return false;
1334     
1335     Node* node = m_renderer->node();
1336     if (!node)
1337         return false;
1338     
1339     return false;
1340 }
1341
1342 bool AccessibilityRenderObject::isFocused() const
1343 {
1344     if (!m_renderer)
1345         return false;
1346     
1347     Document* document = m_renderer->document();
1348     if (!document)
1349         return false;
1350     
1351     Node* focusedNode = document->focusedNode();
1352     if (!focusedNode)
1353         return false;
1354     
1355     // A web area is represented by the Document node in the DOM tree, which isn't focusable.
1356     // Check instead if the frame's selection controller is focused
1357     if (focusedNode == m_renderer->element() || 
1358         (roleValue() == WebAreaRole && document->frame()->selection()->isFocusedAndActive()))
1359         return true;
1360     
1361     return false;
1362 }
1363
1364 void AccessibilityRenderObject::setFocused(bool on)
1365 {
1366     if (!canSetFocusAttribute())
1367         return;
1368     
1369     if (!on)
1370         m_renderer->document()->setFocusedNode(0);
1371     else {
1372         if (m_renderer->element()->isElementNode())
1373             static_cast<Element*>(m_renderer->element())->focus();
1374         else
1375             m_renderer->document()->setFocusedNode(m_renderer->element());
1376     }
1377 }
1378
1379 void AccessibilityRenderObject::setValue(const String& string)
1380 {
1381     // FIXME: Do we want to do anything here for ARIA textboxes?
1382     if (m_renderer->isTextField()) {
1383         HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element());
1384         input->setValue(string);
1385     } else if (m_renderer->isTextArea()) {
1386         HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(m_renderer->element());
1387         textArea->setValue(string);
1388     }
1389 }
1390
1391 bool AccessibilityRenderObject::isEnabled() const
1392 {
1393     return m_renderer->element() ? m_renderer->element()->isEnabled() : true;
1394 }
1395
1396 RenderObject* AccessibilityRenderObject::topRenderer() const
1397 {
1398     return m_renderer->document()->topDocument()->renderer();
1399 }
1400
1401 Document* AccessibilityRenderObject::document() const
1402 {
1403     return m_renderer->document();
1404 }
1405
1406 FrameView* AccessibilityRenderObject::topDocumentFrameView() const
1407 {
1408     return topRenderer()->view()->frameView();
1409 }
1410
1411 Widget* AccessibilityRenderObject::widget() const
1412 {
1413     if (!m_renderer->isWidget())
1414         return 0;
1415     
1416     return static_cast<RenderWidget*>(m_renderer)->widget();
1417 }
1418
1419 AXObjectCache* AccessibilityRenderObject::axObjectCache() const
1420 {
1421     return m_renderer->document()->axObjectCache();
1422 }
1423
1424 void AccessibilityRenderObject::getDocumentLinks(AccessibilityChildrenVector& result) const
1425 {
1426     Document* document = m_renderer->document();
1427     RefPtr<HTMLCollection> coll = document->links();
1428     Node* curr = coll->firstItem();
1429     while (curr) {
1430         RenderObject* obj = curr->renderer();
1431         if (obj) {
1432             RefPtr<AccessibilityObject> axobj = document->axObjectCache()->get(obj);
1433             ASSERT(axobj);
1434             ASSERT(axobj->roleValue() == WebCoreLinkRole);
1435             if (!axobj->accessibilityIsIgnored())
1436                 result.append(axobj);
1437         }
1438         curr = coll->nextItem();
1439     }
1440 }
1441
1442 FrameView* AccessibilityRenderObject::documentFrameView() const 
1443
1444     if (!m_renderer || !m_renderer->document()) 
1445         return 0; 
1446
1447     // this is the RenderObject's Document's Frame's FrameView 
1448     return m_renderer->document()->view();
1449 }
1450
1451 Widget* AccessibilityRenderObject::widgetForAttachmentView() const
1452 {
1453     if (!isAttachment())
1454         return 0;
1455     return static_cast<RenderWidget*>(m_renderer)->widget();
1456 }
1457
1458 FrameView* AccessibilityRenderObject::frameViewIfRenderView() const
1459 {
1460     if (!m_renderer->isRenderView())
1461         return 0;
1462     // this is the RenderObject's Document's renderer's FrameView
1463     return m_renderer->view()->frameView();
1464 }
1465
1466 // This function is like a cross-platform version of - (WebCoreTextMarkerRange*)textMarkerRange. It returns
1467 // a Range that we can convert to a WebCoreTextMarkerRange in the Obj-C file
1468 VisiblePositionRange AccessibilityRenderObject::visiblePositionRange() const
1469 {
1470     if (!m_renderer)
1471         return VisiblePositionRange();
1472     
1473     // construct VisiblePositions for start and end
1474     Node* node = m_renderer->element();
1475     if (!node)
1476         return VisiblePositionRange();
1477     
1478     VisiblePosition startPos = VisiblePosition(node, 0, VP_DEFAULT_AFFINITY);
1479     VisiblePosition endPos = VisiblePosition(node, maxDeepOffset(node), VP_DEFAULT_AFFINITY);
1480     
1481     // the VisiblePositions are equal for nodes like buttons, so adjust for that
1482     if (startPos == endPos) {
1483         endPos = endPos.next();
1484         if (endPos.isNull())
1485             endPos = startPos;
1486     }
1487     
1488     return VisiblePositionRange(startPos, endPos);
1489 }
1490
1491 VisiblePositionRange AccessibilityRenderObject::visiblePositionRangeForLine(unsigned lineCount) const
1492 {
1493     if (lineCount == 0 || !m_renderer)
1494         return VisiblePositionRange();
1495     
1496     // iterate over the lines
1497     // FIXME: this is wrong when lineNumber is lineCount+1,  because nextLinePosition takes you to the
1498     // last offset of the last line
1499     VisiblePosition visiblePos = m_renderer->document()->renderer()->positionForCoordinates(0, 0);
1500     VisiblePosition savedVisiblePos;
1501     while (--lineCount != 0) {
1502         savedVisiblePos = visiblePos;
1503         visiblePos = nextLinePosition(visiblePos, 0);
1504         if (visiblePos.isNull() || visiblePos == savedVisiblePos)
1505             return VisiblePositionRange();
1506     }
1507     
1508     // make a caret selection for the marker position, then extend it to the line
1509     // NOTE: ignores results of sel.modify because it returns false when
1510     // starting at an empty line.  The resulting selection in that case
1511     // will be a caret at visiblePos.
1512     SelectionController selection;
1513     selection.setSelection(Selection(visiblePos));
1514     selection.modify(SelectionController::EXTEND, SelectionController::RIGHT, LineBoundary);
1515     
1516     return VisiblePositionRange(selection.selection().visibleStart(), selection.selection().visibleEnd());
1517 }
1518     
1519 VisiblePosition AccessibilityRenderObject::visiblePositionForIndex(int index) const
1520 {
1521     if (isNativeTextControl())
1522         return static_cast<RenderTextControl*>(m_renderer)->visiblePositionForIndex(index);
1523     
1524     if (!isTextControl())
1525         return VisiblePosition();
1526     
1527     Node* node = m_renderer->node();
1528     if (!node)
1529         return VisiblePosition();
1530     
1531     if (index <= 0)
1532         return VisiblePosition(node, 0, DOWNSTREAM);
1533     
1534     ExceptionCode ec = 0;
1535     RefPtr<Range> range = Range::create(m_renderer->document());
1536     range->selectNodeContents(node, ec);
1537     CharacterIterator it(range.get());
1538     it.advance(index - 1);
1539     return VisiblePosition(it.range()->endContainer(ec), it.range()->endOffset(ec), UPSTREAM);
1540 }
1541     
1542 int AccessibilityRenderObject::indexForVisiblePosition(const VisiblePosition& pos) const
1543 {
1544     if (isNativeTextControl())
1545         return static_cast<RenderTextControl*>(m_renderer)->indexForVisiblePosition(pos);
1546     
1547     if (!isTextControl())
1548         return 0;
1549     
1550     Node* node = m_renderer->node();
1551     if (!node)
1552         return 0;
1553     
1554     Position indexPosition = pos.deepEquivalent();
1555     if (!indexPosition.node() || indexPosition.node()->rootEditableElement() != node)
1556         return 0;
1557     
1558     ExceptionCode ec = 0;
1559     RefPtr<Range> range = Range::create(m_renderer->document());
1560     range->setStart(node, 0, ec);
1561     range->setEnd(indexPosition.node(), indexPosition.offset(), ec);
1562     return TextIterator::rangeLength(range.get());
1563 }
1564
1565 IntRect AccessibilityRenderObject::boundsForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const
1566 {
1567     if (visiblePositionRange.isNull())
1568         return IntRect();
1569     
1570     // Create a mutable VisiblePositionRange.
1571     VisiblePositionRange range(visiblePositionRange);
1572     IntRect rect1 = range.start.caretRect();
1573     IntRect rect2 = range.end.caretRect();
1574     
1575     // 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
1576     if (rect2.y() != rect1.y()) {
1577         VisiblePosition endOfFirstLine = endOfLine(range.start);
1578         if (range.start == endOfFirstLine) {
1579             range.start.setAffinity(DOWNSTREAM);
1580             rect1 = range.start.caretRect();
1581         }
1582         if (range.end == endOfFirstLine) {
1583             range.end.setAffinity(UPSTREAM);
1584             rect2 = range.end.caretRect();
1585         }
1586     }
1587     
1588     IntRect ourrect = rect1;
1589     ourrect.unite(rect2);
1590     
1591     // if the rectangle spans lines and contains multiple text chars, use the range's bounding box intead
1592     if (rect1.bottom() != rect2.bottom()) {
1593         RefPtr<Range> dataRange = makeRange(range.start, range.end);
1594         IntRect boundingBox = dataRange->boundingBox();
1595         String rangeString = plainText(dataRange.get());
1596         if (rangeString.length() > 1 && !boundingBox.isEmpty())
1597             ourrect = boundingBox;
1598     }
1599     
1600 #if PLATFORM(MAC)
1601     return m_renderer->document()->view()->contentsToScreen(ourrect);
1602 #else
1603     return ourrect;
1604 #endif
1605 }
1606     
1607 void AccessibilityRenderObject::setSelectedVisiblePositionRange(const VisiblePositionRange& range) const
1608 {
1609     if (range.start.isNull() || range.end.isNull())
1610         return;
1611     
1612     // make selection and tell the document to use it. if it's zero length, then move to that position
1613     if (range.start == range.end) {
1614         m_renderer->document()->frame()->selection()->moveTo(range.start, true);
1615     }
1616     else {
1617         Selection newSelection = Selection(range.start, range.end);
1618         m_renderer->document()->frame()->selection()->setSelection(newSelection);
1619     }    
1620 }
1621
1622 VisiblePosition AccessibilityRenderObject::visiblePositionForPoint(const IntPoint& point) const
1623 {
1624     // convert absolute point to view coordinates
1625     FrameView* frameView = m_renderer->document()->topDocument()->renderer()->view()->frameView();
1626     RenderObject* renderer = topRenderer();
1627     Node* innerNode = 0;
1628     
1629     // locate the node containing the point
1630     IntPoint pointResult;
1631     while (1) {
1632         IntPoint ourpoint;
1633 #if PLATFORM(MAC)
1634         ourpoint = frameView->screenToContents(point);
1635 #else
1636         ourpoint = point;
1637 #endif
1638         HitTestRequest request(true, true);
1639         HitTestResult result(ourpoint);
1640         renderer->layer()->hitTest(request, result);
1641         innerNode = result.innerNode();
1642         if (!innerNode || !innerNode->renderer())
1643             return VisiblePosition();
1644         
1645         pointResult = result.localPoint();
1646         
1647         // done if hit something other than a widget
1648         renderer = innerNode->renderer();
1649         if (!renderer->isWidget())
1650             break;
1651         
1652         // descend into widget (FRAME, IFRAME, OBJECT...)
1653         Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
1654         if (!widget || !widget->isFrameView())
1655             break;
1656         Frame* frame = static_cast<FrameView*>(widget)->frame();
1657         if (!frame)
1658             break;
1659         Document* document = frame->document();
1660         if (!document)
1661             break;
1662         renderer = document->renderer();
1663         frameView = static_cast<FrameView*>(widget);
1664     }
1665     
1666     return innerNode->renderer()->positionForPoint(pointResult);
1667 }
1668
1669 // NOTE: Consider providing this utility method as AX API
1670 VisiblePosition AccessibilityRenderObject::visiblePositionForIndex(unsigned indexValue, bool lastIndexOK) const
1671 {
1672     if (!isTextControl())
1673         return VisiblePosition();
1674     
1675     // lastIndexOK specifies whether the position after the last character is acceptable
1676     if (indexValue >= text().length()) {
1677         if (!lastIndexOK || indexValue > text().length())
1678             return VisiblePosition();
1679     }
1680     VisiblePosition position = visiblePositionForIndex(indexValue);
1681     position.setAffinity(DOWNSTREAM);
1682     return position;
1683 }
1684
1685 // NOTE: Consider providing this utility method as AX API
1686 int AccessibilityRenderObject::index(const VisiblePosition& position) const
1687 {
1688     if (!isTextControl())
1689         return -1;
1690     
1691     Node* node = position.deepEquivalent().node();
1692     if (!node)
1693         return -1;
1694     
1695     for (RenderObject* renderer = node->renderer(); renderer && renderer->element(); renderer = renderer->parent()) {
1696         if (renderer == m_renderer)
1697             return indexForVisiblePosition(position);
1698     }
1699     
1700     return -1;
1701 }
1702
1703 // Given a line number, the range of characters of the text associated with this accessibility
1704 // object that contains the line number.
1705 PlainTextRange AccessibilityRenderObject::doAXRangeForLine(unsigned lineNumber) const
1706 {
1707     if (!isTextControl())
1708         return PlainTextRange();
1709     
1710     // iterate to the specified line
1711     VisiblePosition visiblePos = visiblePositionForIndex(0);
1712     VisiblePosition savedVisiblePos;
1713     for (unsigned lineCount = lineNumber; lineCount != 0; lineCount -= 1) {
1714         savedVisiblePos = visiblePos;
1715         visiblePos = nextLinePosition(visiblePos, 0);
1716         if (visiblePos.isNull() || visiblePos == savedVisiblePos)
1717             return PlainTextRange();
1718     }
1719     
1720     // make a caret selection for the marker position, then extend it to the line
1721     // NOTE: ignores results of selection.modify because it returns false when
1722     // starting at an empty line.  The resulting selection in that case
1723     // will be a caret at visiblePos.
1724     SelectionController selection;
1725     selection.setSelection(Selection(visiblePos));
1726     selection.modify(SelectionController::EXTEND, SelectionController::LEFT, LineBoundary);
1727     selection.modify(SelectionController::EXTEND, SelectionController::RIGHT, LineBoundary);
1728     
1729     // calculate the indices for the selection start and end
1730     VisiblePosition startPosition = selection.selection().visibleStart();
1731     VisiblePosition endPosition = selection.selection().visibleEnd();
1732     int index1 = indexForVisiblePosition(startPosition);
1733     int index2 = indexForVisiblePosition(endPosition);
1734     
1735     // add one to the end index for a line break not caused by soft line wrap (to match AppKit)
1736     if (endPosition.affinity() == DOWNSTREAM && endPosition.next().isNotNull())
1737         index2 += 1;
1738     
1739     // return nil rather than an zero-length range (to match AppKit)
1740     if (index1 == index2)
1741         return PlainTextRange();
1742     
1743     return PlainTextRange(index1, index2 - index1);
1744 }
1745
1746 // The composed character range in the text associated with this accessibility object that
1747 // is specified by the given index value. This parameterized attribute returns the complete
1748 // range of characters (including surrogate pairs of multi-byte glyphs) at the given index.
1749 PlainTextRange AccessibilityRenderObject::doAXRangeForIndex(unsigned index) const
1750 {
1751     if (!isTextControl())
1752         return PlainTextRange();
1753     
1754     String elementText = text();
1755     if (!elementText.length() || index > elementText.length() - 1)
1756         return PlainTextRange();
1757     
1758     return PlainTextRange(index, 1);
1759 }
1760
1761 // A substring of the text associated with this accessibility object that is
1762 // specified by the given character range.
1763 String AccessibilityRenderObject::doAXStringForRange(const PlainTextRange& range) const
1764 {
1765     if (isPasswordField())
1766         return String();
1767     
1768     if (range.length == 0)
1769         return "";
1770     
1771     if (!isTextControl())
1772         return String();
1773     
1774     String elementText = text();
1775     if (range.start + range.length > elementText.length())
1776         return String();
1777     
1778     return elementText.substring(range.start, range.length);
1779 }
1780
1781 // The bounding rectangle of the text associated with this accessibility object that is
1782 // specified by the given range. This is the bounding rectangle a sighted user would see
1783 // on the display screen, in pixels.
1784 IntRect AccessibilityRenderObject::doAXBoundsForRange(const PlainTextRange& range) const
1785 {
1786     if (isTextControl())
1787         return boundsForVisiblePositionRange(visiblePositionRangeForRange(range));
1788     return IntRect();
1789 }
1790
1791 AccessibilityObject* AccessibilityRenderObject::doAccessibilityHitTest(const IntPoint& point) const
1792 {
1793     if (!m_renderer)
1794         return 0;
1795     
1796     RenderLayer* layer = m_renderer->layer();
1797     if (!layer)
1798         return 0;
1799     
1800     HitTestRequest request(true, true);
1801     HitTestResult hitTestResult = HitTestResult(point);
1802     layer->hitTest(request, hitTestResult);
1803     if (!hitTestResult.innerNode())
1804         return 0;
1805     Node* node = hitTestResult.innerNode()->shadowAncestorNode();
1806     RenderObject* obj = node->renderer();
1807     if (!obj)
1808         return 0;
1809     
1810     AccessibilityObject *result = obj->document()->axObjectCache()->get(obj);
1811
1812     if (obj->isListBox())
1813         return static_cast<AccessibilityListBox*>(result)->doAccessibilityHitTest(point);
1814         
1815     if (result->accessibilityIsIgnored())
1816         result = result->parentObjectUnignored();
1817
1818     return result;
1819 }
1820
1821 AccessibilityObject* AccessibilityRenderObject::focusedUIElement() const
1822 {
1823     // get the focused node in the page
1824     Page* page = m_renderer->document()->page();
1825     if (!page)
1826         return 0;
1827     
1828     Document* focusedDocument = page->focusController()->focusedOrMainFrame()->document();
1829     Node* focusedNode = focusedDocument->focusedNode();
1830     if (!focusedNode)
1831         focusedNode = focusedDocument;
1832     
1833     RenderObject* focusedNodeRenderer = focusedNode->renderer();
1834     if (!focusedNodeRenderer)
1835         return 0;
1836     
1837     AccessibilityObject* obj = focusedNodeRenderer->document()->axObjectCache()->get(focusedNodeRenderer);
1838     
1839     if (obj->shouldFocusActiveDescendant()) {
1840         if (AccessibilityObject* descendant = obj->activeDescendant())
1841             obj = descendant;
1842     }
1843     
1844     // the HTML element, for example, is focusable but has an AX object that is ignored
1845     if (obj->accessibilityIsIgnored())
1846         obj = obj->parentObjectUnignored();
1847     
1848     return obj;
1849 }
1850
1851 bool AccessibilityRenderObject::shouldFocusActiveDescendant() const
1852 {
1853     switch (ariaRoleAttribute()) {
1854     case GroupRole:
1855     case ComboBoxRole:
1856     case ListBoxRole:
1857     case MenuRole:
1858     case MenuBarRole:
1859     case RadioGroupRole:
1860     case RowRole:
1861     case PopUpButtonRole:
1862     case ProgressIndicatorRole:
1863     case ToolbarRole:
1864     case OutlineRole:
1865     /* FIXME: replace these with actual roles when they are added to AccessibilityRole
1866     composite
1867     alert
1868     alertdialog
1869     grid
1870     status
1871     timer
1872     tree
1873     */
1874         return true;
1875     default:
1876         return false;
1877     }
1878 }
1879
1880 AccessibilityObject* AccessibilityRenderObject::activeDescendant() const
1881 {
1882     if (renderer()->element() && !renderer()->element()->isElementNode())
1883         return 0;
1884     Element* element = static_cast<Element*>(renderer()->element());
1885         
1886     String activeDescendantAttrStr = element->getAttribute(aria_activedescendantAttr).string();
1887     if (activeDescendantAttrStr.isNull() || activeDescendantAttrStr.isEmpty())
1888         return 0;
1889     
1890     Element* target = renderer()->document()->getElementById(activeDescendantAttrStr);
1891     AccessibilityObject* obj = renderer()->document()->axObjectCache()->get(target->renderer());
1892     if (obj->isAccessibilityRenderObject())
1893     // an activedescendant is only useful if it has a renderer, because that's what's needed to post the notification
1894         return obj;
1895     return 0;
1896 }
1897
1898
1899 void AccessibilityRenderObject::handleActiveDescendantChanged()
1900 {
1901     Element* element = static_cast<Element*>(renderer()->element());
1902     if (!element)
1903         return;
1904     Document* doc = renderer()->document();
1905     if (!doc->frame()->selection()->isFocusedAndActive() || doc->focusedNode() != element)
1906         return; 
1907     AccessibilityRenderObject* activedescendant = static_cast<AccessibilityRenderObject*>(activeDescendant());
1908     
1909     if (activedescendant && shouldFocusActiveDescendant())
1910         doc->axObjectCache()->postNotificationToElement(activedescendant->renderer(), "AXFocusedUIElementChanged");
1911 }
1912
1913
1914 AccessibilityObject* AccessibilityRenderObject::observableObject() const
1915 {
1916     for (RenderObject* renderer = m_renderer; renderer && renderer->element(); renderer = renderer->parent()) {
1917         if (renderer->isTextField() || renderer->isTextArea())
1918             return renderer->document()->axObjectCache()->get(renderer);
1919     }
1920     
1921     return 0;
1922 }
1923     
1924 typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap;
1925
1926 static const ARIARoleMap& createARIARoleMap()
1927 {
1928     struct RoleEntry {
1929         String ariaRole;
1930         AccessibilityRole webcoreRole;
1931     };
1932
1933     static const RoleEntry roles[] = {
1934         { "button", ButtonRole },
1935         { "checkbox", CheckBoxRole },
1936         { "group", GroupRole },
1937         { "heading", HeadingRole },
1938         { "img", ImageRole },
1939         { "link", WebCoreLinkRole },
1940         { "listbox", ListBoxRole },
1941         // "option" isn't here because it may map to different roles depending on the parent element's role
1942         { "menu", MenuRole },
1943         { "menubar", GroupRole },
1944         // "menuitem" isn't here because it may map to different roles depending on the parent element's role
1945         { "menuitemcheckbox", MenuItemRole },
1946         { "menuitemradio", MenuItemRole },
1947         { "progressbar", ProgressIndicatorRole },
1948         { "radio", RadioButtonRole },
1949         { "range", SliderRole },
1950         { "slider", SliderRole },
1951         { "spinbutton", ProgressIndicatorRole },
1952         { "textbox", TextAreaRole }
1953     };
1954     ARIARoleMap& roleMap = *new ARIARoleMap;
1955         
1956     const unsigned numRoles = sizeof(roles) / sizeof(roles[0]);
1957     for (unsigned i = 0; i < numRoles; ++i)
1958         roleMap.set(roles[i].ariaRole, roles[i].webcoreRole);
1959     return roleMap;
1960 }
1961
1962 static AccessibilityRole ariaRoleToWebCoreRole(String value)
1963 {
1964     ASSERT(!value.isEmpty() && !value.isNull());
1965     static const ARIARoleMap& roleMap = createARIARoleMap();
1966     return roleMap.get(value);
1967 }
1968
1969 AccessibilityRole AccessibilityRenderObject::determineAriaRoleAttribute() const
1970 {
1971     String ariaRole = getAttribute(roleAttr).string();
1972     if (ariaRole.isNull() || ariaRole.isEmpty())
1973         return UnknownRole;
1974     
1975     AccessibilityRole role = ariaRoleToWebCoreRole(ariaRole);
1976     if (role)
1977         return role;
1978     // selects and listboxes both have options as child roles, but they map to different roles within WebCore
1979     if (equalIgnoringCase(ariaRole,"option")) {
1980         if (parentObjectUnignored()->ariaRoleAttribute() == MenuRole)
1981             return MenuItemRole;
1982         if (parentObjectUnignored()->ariaRoleAttribute() == ListBoxRole)
1983             return ListBoxOptionRole;
1984     }
1985     // an aria "menuitem" may map to MenuButton or MenuItem depending on its parent
1986     if (equalIgnoringCase(ariaRole,"menuitem")) {
1987         if (parentObjectUnignored()->ariaRoleAttribute() == GroupRole)
1988             return MenuButtonRole;
1989         if (parentObjectUnignored()->ariaRoleAttribute() == MenuRole)
1990             return MenuItemRole;
1991     }
1992     
1993     return UnknownRole;
1994 }
1995
1996 void AccessibilityRenderObject::setAriaRole()
1997 {
1998     m_ariaRole = determineAriaRoleAttribute();
1999 }
2000
2001 AccessibilityRole AccessibilityRenderObject::ariaRoleAttribute() const
2002 {
2003     return m_ariaRole;
2004 }
2005
2006 AccessibilityRole AccessibilityRenderObject::roleValue() const
2007 {
2008     if (!m_renderer)
2009         return UnknownRole;
2010     
2011     Node* node = m_renderer->element();
2012     AccessibilityRole ariaRole = ariaRoleAttribute();
2013     if (ariaRole != UnknownRole)
2014         return ariaRole;
2015     
2016     if (m_areaElement)
2017         return WebCoreLinkRole;
2018     if (node && node->isLink()) {
2019         if (m_renderer->isImage())
2020             return ImageMapRole;
2021         return WebCoreLinkRole;
2022     }
2023     if (m_renderer->isListMarker())
2024         return ListMarkerRole;
2025     if (node && node->hasTagName(buttonTag))
2026         return ButtonRole;
2027     if (m_renderer->isText())
2028         return StaticTextRole;
2029     if (m_renderer->isImage()) {
2030         if (node && node->hasTagName(inputTag))
2031             return ButtonRole;
2032         return ImageRole;
2033     }
2034     if (m_renderer->isRenderView())
2035         return WebAreaRole;
2036     
2037     if (m_renderer->isTextField())
2038         return TextFieldRole;
2039     
2040     if (m_renderer->isTextArea())
2041         return TextAreaRole;
2042     
2043     if (node && node->hasTagName(inputTag)) {
2044         HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
2045         if (input->inputType() == HTMLInputElement::CHECKBOX)
2046             return CheckBoxRole;
2047         if (input->inputType() == HTMLInputElement::RADIO)
2048             return RadioButtonRole;
2049         if (input->isTextButton())
2050             return ButtonRole;
2051     }
2052
2053     if (node && node->hasTagName(buttonTag))
2054         return ButtonRole;
2055
2056     if (isFileUploadButton())
2057         return ButtonRole;
2058     
2059     if (m_renderer->isMenuList())
2060         return PopUpButtonRole;
2061     
2062     if (headingLevel(m_renderer->element()) != 0)
2063         return HeadingRole;
2064     
2065     if (m_renderer->isBlockFlow() || (node && node->hasTagName(labelTag)))
2066         return GroupRole;
2067     
2068     return UnknownRole;
2069 }
2070
2071 bool AccessibilityRenderObject::isPresentationalChildOfAriaRole() const
2072 {
2073     // Walk the parent chain looking for a parent that has presentational children
2074     AccessibilityObject* parent;
2075     for (parent = parentObject(); parent && !parent->ariaRoleHasPresentationalChildren(); parent = parent->parentObject())
2076         ;
2077     return parent;
2078 }
2079     
2080 bool AccessibilityRenderObject::ariaRoleHasPresentationalChildren() const
2081 {
2082     switch (m_ariaRole) {
2083     case ButtonRole:
2084     case SliderRole:
2085     case ImageRole:
2086     case ProgressIndicatorRole:
2087     //case SeparatorRole:
2088         return true;
2089     default:
2090         return false;
2091     }
2092 }
2093
2094 bool AccessibilityRenderObject::canSetFocusAttribute() const
2095 {
2096     // NOTE: It would be more accurate to ask the document whether setFocusedNode() would
2097     // do anything.  For example, it setFocusedNode() will do nothing if the current focused
2098     // node will not relinquish the focus.
2099     if (!m_renderer->element() || !m_renderer->element()->isEnabled())
2100         return false;
2101     
2102     switch (roleValue()) {
2103         case WebCoreLinkRole:
2104         case TextFieldRole:
2105         case TextAreaRole:
2106         case ButtonRole:
2107         case PopUpButtonRole:
2108         case CheckBoxRole:
2109         case RadioButtonRole:
2110             return true;
2111         case UnknownRole:
2112         case SliderRole:
2113         case TabGroupRole:
2114         case StaticTextRole:
2115         case ScrollAreaRole:
2116         case MenuButtonRole:
2117         case TableRole:
2118         case ApplicationRole:
2119         case GroupRole:
2120         case RadioGroupRole:
2121         case ListRole:
2122         case ScrollBarRole:
2123         case ValueIndicatorRole:
2124         case ImageRole:
2125         case MenuBarRole:
2126         case MenuRole:
2127         case MenuItemRole:
2128         case ColumnRole:
2129         case RowRole:
2130         case ToolbarRole:
2131         case BusyIndicatorRole:
2132         case ProgressIndicatorRole:
2133         case WindowRole:
2134         case DrawerRole:
2135         case SystemWideRole:
2136         case OutlineRole:
2137         case IncrementorRole:
2138         case BrowserRole:
2139         case ComboBoxRole:
2140         case SplitGroupRole:
2141         case SplitterRole:
2142         case ColorWellRole:
2143         case GrowAreaRole:
2144         case SheetRole:
2145         case HelpTagRole:
2146         case MatteRole:
2147         case RulerRole:
2148         case RulerMarkerRole:
2149         case LinkRole:
2150         case DisclosureTriangleRole:
2151         case GridRole:
2152         case ImageMapRole:
2153         case ListMarkerRole:
2154         case WebAreaRole:
2155         case HeadingRole:
2156         case ListBoxRole:
2157         case ListBoxOptionRole:
2158             return false;
2159     }
2160     ASSERT_NOT_REACHED();
2161     return false;
2162 }
2163
2164 bool AccessibilityRenderObject::canSetValueAttribute() const
2165 {
2166     if (isWebArea()) 
2167         return !isReadOnly();
2168
2169     return isTextControl() || isProgressIndicator() || isSlider();
2170 }
2171
2172 bool AccessibilityRenderObject::canSetTextRangeAttributes() const
2173 {
2174     return isTextControl();
2175 }
2176
2177 void AccessibilityRenderObject::childrenChanged()
2178 {
2179     clearChildren();
2180     
2181     if (accessibilityIsIgnored()) {
2182         AccessibilityObject* parent = parentObject();
2183         if (parent)
2184             parent->childrenChanged();
2185     }
2186 }
2187
2188 const AccessibilityObject::AccessibilityChildrenVector& AccessibilityRenderObject::children()
2189 {
2190     if (!m_haveChildren)
2191         addChildren();
2192     return m_children;
2193 }
2194
2195 void AccessibilityRenderObject::addChildren()
2196 {
2197     // If the need to add more children in addition to existing children arises, 
2198     // childrenChanged should have been called, leaving the object with no children.
2199     ASSERT(!m_haveChildren); 
2200     
2201     // nothing to add if there is no RenderObject
2202     if (!m_renderer)
2203         return;
2204     
2205     m_haveChildren = true;
2206     
2207     // add all unignored acc children
2208     for (RefPtr<AccessibilityObject> obj = firstChild(); obj; obj = obj->nextSibling()) {
2209         if (obj->accessibilityIsIgnored()) {
2210             if (!obj->hasChildren())
2211                 obj->addChildren();
2212             AccessibilityChildrenVector children = obj->children();
2213             unsigned length = children.size();
2214             for (unsigned i = 0; i < length; ++i)
2215                 m_children.append(children[i]);
2216         } else
2217             m_children.append(obj);
2218     }
2219     
2220     // for a RenderImage, add the <area> elements as individual accessibility objects
2221     if (m_renderer->isRenderImage() && !m_areaElement) {
2222         HTMLMapElement* map = static_cast<RenderImage*>(m_renderer)->imageMap();
2223         if (map) {
2224             for (Node* current = map->firstChild(); current; current = current->traverseNextNode(map)) {
2225                 // add an <area> element for this child if it has a link
2226                 // NOTE: can't cache these because they all have the same renderer, which is the cache key, right?
2227                 // plus there may be little reason to since they are being added to the handy array
2228                 if (current->isLink()) {
2229                     RefPtr<AccessibilityRenderObject> obj = new AccessibilityRenderObject(m_renderer);
2230                     obj->m_areaElement = static_cast<HTMLAreaElement*>(current);
2231                     m_children.append(obj);
2232                 }
2233             }
2234         }
2235     }
2236 }
2237
2238 void AccessibilityRenderObject::ariaListboxSelectedChildren(AccessibilityChildrenVector& result)
2239 {
2240     AccessibilityObject* child = firstChild();
2241     bool isMultiselectable = false;
2242     
2243     Element* element = static_cast<Element*>(renderer()->element());        
2244     if (!element || !element->isElementNode()) // do this check to ensure safety of static_cast above
2245         return;
2246
2247     String multiselectablePropertyStr = element->getAttribute("aria-multiselectable").string();
2248     isMultiselectable = equalIgnoringCase(multiselectablePropertyStr, "true");
2249     
2250     while (child) {
2251         // every child should have aria-role option, and if so, check for selected attribute/state
2252         AccessibilityRole ariaRole = child->ariaRoleAttribute();
2253         RenderObject* childRenderer = 0;
2254         if (child->isAccessibilityRenderObject())
2255             childRenderer = static_cast<AccessibilityRenderObject*>(child)->renderer();
2256         if (childRenderer && ariaRole == ListBoxOptionRole) {
2257             Element* childElement = static_cast<Element*>(childRenderer->element());
2258             if (childElement && childElement->isElementNode()) { // do this check to ensure safety of static_cast above
2259                 String selectedAttrString = childElement->getAttribute("aria-selected").string();
2260                 if (equalIgnoringCase(selectedAttrString, "true")) {
2261                     result.append(child);
2262                     if (isMultiselectable)
2263                         return;
2264                 }
2265             }
2266         }
2267         child = child->nextSibling(); 
2268     }
2269 }
2270
2271 void AccessibilityRenderObject::selectedChildren(AccessibilityChildrenVector& result)
2272 {
2273     ASSERT(result.isEmpty());
2274
2275     // only listboxes should be asked for their selected children. 
2276     if (ariaRoleAttribute() != ListBoxRole) { // native list boxes would be AccessibilityListBoxes, so only check for aria list boxes
2277         ASSERT_NOT_REACHED(); 
2278         return;
2279     }
2280     return ariaListboxSelectedChildren(result);
2281 }
2282
2283 void AccessibilityRenderObject::ariaListboxVisibleChildren(AccessibilityChildrenVector& result)      
2284 {
2285     if (!hasChildren())
2286         addChildren();
2287     
2288     unsigned length = m_children.size();
2289     for (unsigned i = 0; i < length; i++) {
2290         if (!m_children[i]->isOffScreen())
2291             result.append(m_children[i]);
2292     }
2293 }
2294
2295 void AccessibilityRenderObject::visibleChildren(AccessibilityChildrenVector& result)
2296 {
2297     ASSERT(result.isEmpty());
2298         
2299     // only listboxes are asked for their visible children. 
2300     if (ariaRoleAttribute() != ListBoxRole) { // native list boxes would be AccessibilityListBoxes, so only check for aria list boxes
2301         ASSERT_NOT_REACHED();
2302         return;
2303     }
2304     return ariaListboxVisibleChildren(result);
2305 }
2306  
2307 void AccessibilityRenderObject::removeAXObjectID()
2308 {
2309     if (!m_id)
2310         return;
2311 #if PLATFORM(MAC)
2312     m_renderer->document()->axObjectCache()->removeAXID(this);
2313 #endif
2314 }   
2315     
2316 const String& AccessibilityRenderObject::actionVerb() const
2317 {
2318     // FIXME: Need to add verbs for select elements.
2319     static const String buttonAction = AXButtonActionVerb();
2320     static const String textFieldAction = AXTextFieldActionVerb();
2321     static const String radioButtonAction = AXRadioButtonActionVerb();
2322     static const String checkedCheckBoxAction = AXCheckedCheckBoxActionVerb();
2323     static const String uncheckedCheckBoxAction = AXUncheckedCheckBoxActionVerb();
2324     static const String linkAction = AXLinkActionVerb();
2325     static const String noAction;
2326     
2327     switch (roleValue()) {
2328         case ButtonRole:
2329             return buttonAction;
2330         case TextFieldRole:
2331         case TextAreaRole:
2332             return textFieldAction;
2333         case RadioButtonRole:
2334             return radioButtonAction;
2335         case CheckBoxRole:
2336             return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction;
2337         case LinkRole:
2338         case WebCoreLinkRole:
2339             return linkAction;
2340         default:
2341             return noAction;
2342     }
2343 }
2344      
2345     
2346 } // namespace WebCore