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