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