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