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