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