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