WebCore:
[WebKit-https.git] / WebCore / page / AccessibilityRenderObject.cpp
1 /*
2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 *     its contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "config.h"
30 #include "AccessibilityRenderObject.h"
31
32 #include "AXObjectCache.h"
33 #include "AccessibilityListBox.h"
34 #include "CharacterNames.h"
35 #include "EventNames.h"
36 #include "FloatRect.h"
37 #include "FocusController.h"
38 #include "Frame.h"
39 #include "FrameLoader.h"
40 #include "HTMLAreaElement.h"
41 #include "HTMLFrameElementBase.h"
42 #include "HTMLImageElement.h"
43 #include "HTMLInputElement.h"
44 #include "HTMLLabelElement.h"
45 #include "HTMLMapElement.h"
46 #include "HTMLOptGroupElement.h"
47 #include "HTMLOptionElement.h"
48 #include "HTMLOptionsCollection.h"
49 #include "HTMLSelectElement.h"
50 #include "HTMLTextAreaElement.h"
51 #include "HitTestRequest.h"
52 #include "HitTestResult.h"
53 #include "LocalizedStrings.h"
54 #include "NodeList.h"
55 #include "NotImplemented.h"
56 #include "Page.h"
57 #include "RenderImage.h"
58 #include "RenderListBox.h"
59 #include "RenderListMarker.h"
60 #include "RenderMenuList.h"
61 #include "RenderTextControl.h"
62 #include "RenderTheme.h"
63 #include "RenderView.h"
64 #include "RenderWidget.h"
65 #include "SelectionController.h"
66 #include "Text.h"
67 #include "TextIterator.h"
68 #include "htmlediting.h"
69 #include "visible_units.h"
70
71 using namespace std;
72
73 namespace WebCore {
74
75 using namespace EventNames;
76 using namespace HTMLNames;
77
78 AccessibilityRenderObject::AccessibilityRenderObject(RenderObject* renderer)
79     : m_renderer(renderer)
80 {
81 #ifndef NDEBUG
82     m_renderer->setHasAXObject(true);
83 #endif
84 }
85
86 AccessibilityRenderObject::~AccessibilityRenderObject()
87 {
88     ASSERT(isDetached());
89 }
90
91 PassRefPtr<AccessibilityRenderObject> AccessibilityRenderObject::create(RenderObject* renderer)
92 {
93     return adoptRef(new AccessibilityRenderObject(renderer));
94 }
95
96 void AccessibilityRenderObject::detach()
97 {
98     clearChildren();
99     AccessibilityObject::detach();
100     
101 #ifndef NDEBUG
102     if (m_renderer)
103         m_renderer->setHasAXObject(false);
104 #endif
105     m_renderer = 0;    
106 }
107
108 AccessibilityObject* AccessibilityRenderObject::firstChild() const
109 {
110     if (!m_renderer)
111         return 0;
112     
113     RenderObject* firstChild = m_renderer->firstChild();
114     if (!firstChild)
115         return 0;
116     
117     return m_renderer->document()->axObjectCache()->get(firstChild);
118 }
119
120 AccessibilityObject* AccessibilityRenderObject::lastChild() const
121 {
122     if (!m_renderer)
123         return 0;
124     
125     RenderObject* lastChild = m_renderer->lastChild();
126     if (!lastChild)
127         return 0;
128     
129     return m_renderer->document()->axObjectCache()->get(lastChild);
130 }
131
132 AccessibilityObject* AccessibilityRenderObject::previousSibling() const
133 {
134     if (!m_renderer)
135         return 0;
136     
137     RenderObject* previousSibling = m_renderer->previousSibling();
138     if (!previousSibling)
139         return 0;
140     
141     return m_renderer->document()->axObjectCache()->get(previousSibling);
142 }
143
144 AccessibilityObject* AccessibilityRenderObject::nextSibling() const
145 {
146     if (!m_renderer)
147         return 0;
148     
149     RenderObject* nextSibling = m_renderer->nextSibling();
150     if (!nextSibling)
151         return 0;
152     
153     return m_renderer->document()->axObjectCache()->get(nextSibling);
154 }
155
156 AccessibilityObject* AccessibilityRenderObject::parentObject() const
157 {
158     if (m_areaElement)
159         return m_renderer->document()->axObjectCache()->get(m_renderer);
160     
161     if (!m_renderer)
162         return 0;
163     
164     RenderObject *parent = m_renderer->parent();
165     if (!parent)
166         return 0;
167     
168     return m_renderer->document()->axObjectCache()->get(parent);
169 }
170
171 bool AccessibilityRenderObject::isWebArea() const
172 {
173     return roleValue() == WebAreaRole;
174 }
175
176 bool AccessibilityRenderObject::isImageButton() const
177 {
178     return isNativeImage() && roleValue() == ButtonRole;
179 }
180
181 bool AccessibilityRenderObject::isAnchor() const
182 {
183     return m_areaElement || (!isNativeImage() && isLink());
184 }
185
186 bool AccessibilityRenderObject::isNativeTextControl() const
187 {
188     return m_renderer->isTextField() || m_renderer->isTextArea();
189 }
190     
191 bool AccessibilityRenderObject::isTextControl() const
192 {
193     AccessibilityRole role = roleValue();
194     return role == TextAreaRole || role == TextFieldRole;
195 }
196
197 bool AccessibilityRenderObject::isNativeImage() const
198 {
199     return m_renderer->isImage();
200 }    
201     
202 bool AccessibilityRenderObject::isImage() const
203 {
204     return roleValue() == ImageRole;
205 }
206
207 bool AccessibilityRenderObject::isAttachment() const
208 {
209     // Widgets are the replaced elements that we represent to AX as attachments
210     bool isWidget = m_renderer && m_renderer->isWidget();
211     ASSERT(!isWidget || (m_renderer->isReplaced() && !isImage()));
212     return isWidget && ariaRoleAttribute() == UnknownRole;
213 }
214
215 bool AccessibilityRenderObject::isPasswordField() const
216 {
217     ASSERT(m_renderer);
218     if (!m_renderer->element() || !m_renderer->element()->isHTMLElement())
219         return false;
220     return static_cast<HTMLElement*>(m_renderer->element())->isPasswordField() && ariaRoleAttribute() == UnknownRole;
221 }
222
223 bool AccessibilityRenderObject::isCheckboxOrRadio() const
224 {
225     AccessibilityRole role = roleValue();
226     return role == RadioButtonRole || role == CheckBoxRole;
227 }    
228     
229 bool AccessibilityRenderObject::isPressed() const
230 {
231     ASSERT(m_renderer);
232     if (roleValue() != ButtonRole)
233         return false;
234     return m_renderer->node() && m_renderer->node()->active();
235 }
236
237 bool AccessibilityRenderObject::isIndeterminate() const
238 {
239     ASSERT(m_renderer);
240     return m_renderer->node() && m_renderer->node()->isIndeterminate();
241 }
242
243 bool AccessibilityRenderObject::isChecked() const
244 {
245     ASSERT(m_renderer);
246     return m_renderer->node() && m_renderer->node()->isChecked();
247 }
248
249 bool AccessibilityRenderObject::isHovered() const
250 {
251     ASSERT(m_renderer);
252     return m_renderer->node() && m_renderer->node()->hovered();
253 }
254
255 bool AccessibilityRenderObject::isMultiSelect() const
256 {
257     ASSERT(m_renderer);
258     if (!m_renderer->isListBox())
259         return false;
260     return m_renderer->element() && static_cast<HTMLSelectElement*>(m_renderer->element())->multiple();
261 }
262     
263 bool AccessibilityRenderObject::isReadOnly() const
264 {
265     ASSERT(m_renderer);
266     return !m_renderer->node() || !m_renderer->node()->isContentEditable();
267 }
268
269 bool AccessibilityRenderObject::isOffScreen() const
270 {
271     ASSERT(m_renderer);
272     IntRect contentRect = m_renderer->absoluteClippedOverflowRect();
273     FrameView* view = m_renderer->document()->frame()->view();
274     FloatRect viewRect = view->visibleContentRect();
275     viewRect.intersect(contentRect);
276     return viewRect.isEmpty();
277 }
278
279 int AccessibilityRenderObject::headingLevel(Node* node)
280 {
281     // headings can be in block flow and non-block flow
282     
283     if (!node)
284         return 0;
285     
286     if (node->hasTagName(h1Tag))
287         return 1;
288     
289     if (node->hasTagName(h2Tag))
290         return 2;
291     
292     if (node->hasTagName(h3Tag))
293         return 3;
294     
295     if (node->hasTagName(h4Tag))
296         return 4;
297     
298     if (node->hasTagName(h5Tag))
299         return 5;
300     
301     if (node->hasTagName(h6Tag))
302         return 6;
303     
304     // FIXME: When we implement ARIA's level property, this needs to return that instead of 1.
305     RenderObject* renderer = node->renderer();
306     if (!renderer)
307         return 0;
308     
309     AccessibilityObject* axObjectForNode = node->document()->axObjectCache()->get(renderer);
310     if (axObjectForNode->ariaRoleAttribute() == HeadingRole)
311         return 1;    
312     
313     return 0;
314 }
315
316 bool AccessibilityRenderObject::isHeading() const
317 {
318     return roleValue() == HeadingRole;
319 }
320     
321 bool AccessibilityRenderObject::isLink() const
322 {
323     return roleValue() == WebCoreLinkRole;
324 }    
325
326 HTMLAnchorElement* AccessibilityRenderObject::anchorElement() const
327 {
328     // FIXME: In XHTML 2.0, any HTML element can have an href attribute. We will need to implement this to fully
329     // support ARIA links.
330     if (m_areaElement)
331         return m_areaElement.get();
332     
333     // Search up the render tree for a RenderObject with a DOM node.  Defer to an earlier continuation, though.
334     RenderObject* currRenderer;
335     for (currRenderer = m_renderer; currRenderer && !currRenderer->element(); currRenderer = currRenderer->parent()) {
336         if (currRenderer->continuation())
337             return currRenderer->document()->axObjectCache()->get(currRenderer->continuation())->anchorElement();
338     }
339     
340     // bail if none found
341     if (!currRenderer)
342         return 0;
343     
344     // search up the DOM tree for an anchor element
345     // NOTE: this assumes that any non-image with an anchor is an HTMLAnchorElement
346     Node* node = currRenderer->node();
347     for ( ; node; node = node->parentNode()) {
348         if (node->hasTagName(aTag))
349             return static_cast<HTMLAnchorElement*>(node);
350     }
351     
352     return 0;
353 }
354
355 Element* AccessibilityRenderObject::actionElement() const
356 {
357     if (m_renderer->element() && m_renderer->element()->hasTagName(inputTag)) {
358         HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element());
359         if (!input->disabled() && (isCheckboxOrRadio() || input->isTextButton()))
360             return input;
361     }
362     
363     if (AccessibilityObject::isARIAInput(ariaRoleAttribute()))
364         return static_cast<Element*>(m_renderer->element());
365
366     if (isImageButton())
367         return static_cast<Element*>(m_renderer->element());
368     
369     if (m_renderer->isMenuList())
370         return static_cast<RenderMenuList*>(m_renderer)->selectElement();
371     
372     Element* elt = anchorElement();
373     if (!elt)
374         elt = mouseButtonListener();
375     return elt;
376 }
377
378 Element* AccessibilityRenderObject::mouseButtonListener() const
379 {
380     Node* node = m_renderer->element();
381     if (!node)
382         return 0;
383     if (!node->isEventTargetNode())
384         return 0;
385     
386     // FIXME: Do the continuation search like anchorElement does
387     for (EventTargetNode* elt = static_cast<EventTargetNode*>(node); elt; elt = static_cast<EventTargetNode*>(elt->parentNode())) {
388         if (elt->getHTMLEventListener(clickEvent) || elt->getHTMLEventListener(mousedownEvent) || elt->getHTMLEventListener(mouseupEvent))
389             return static_cast<Element*>(elt);
390     }
391     
392     return 0;
393 }
394
395 String AccessibilityRenderObject::helpText() const
396 {
397     if (!m_renderer)
398         return String();
399     
400     if (m_areaElement) {
401         const AtomicString& summary = m_areaElement->getAttribute(summaryAttr);
402         if (!summary.isEmpty())
403             return summary;
404         const AtomicString& title = m_areaElement->getAttribute(titleAttr);
405         if (!title.isEmpty())
406             return title;
407     }
408     
409     for (RenderObject* curr = m_renderer; curr; curr = curr->parent()) {
410         if (curr->element() && curr->element()->isHTMLElement()) {
411             const AtomicString& summary = static_cast<Element*>(curr->element())->getAttribute(summaryAttr);
412             if (!summary.isEmpty())
413                 return summary;
414             const AtomicString& title = static_cast<Element*>(curr->element())->getAttribute(titleAttr);
415             if (!title.isEmpty())
416                 return title;
417         }
418     }
419     
420     return String();
421 }
422
423 String AccessibilityRenderObject::textUnderElement() const
424 {
425     if (!m_renderer)
426         return String();
427     
428     Node* node = m_renderer->element();
429     if (node) {
430         if (Frame* frame = node->document()->frame()) {
431             // catch stale WebCoreAXObject (see <rdar://problem/3960196>)
432             if (frame->document() != node->document())
433                 return String();
434             return plainText(rangeOfContents(node).get());
435         }
436     }
437     
438     // return the null string for anonymous text because it is non-trivial to get
439     // the actual text and, so far, that is not needed
440     return String();
441 }
442
443 bool AccessibilityRenderObject::hasIntValue() const
444 {
445     if (isHeading())
446         return true;
447     
448     if (m_renderer->element() && isCheckboxOrRadio())
449         return true;
450     
451     return false;
452 }
453
454 int AccessibilityRenderObject::intValue() const
455 {
456     if (!m_renderer || m_areaElement || isPasswordField())
457         return 0;
458     
459     if (isHeading())
460         return headingLevel(m_renderer->element());
461     
462     Node* node = m_renderer->element();
463     if (node && isCheckboxOrRadio() && ariaRoleAttribute() == UnknownRole)
464         return static_cast<HTMLInputElement*>(node)->checked();
465     
466     return 0;
467 }
468
469 String AccessibilityRenderObject::stringValue() const
470 {
471     if (!m_renderer || m_areaElement || isPasswordField())
472         return String();
473     
474     if (m_renderer->isText())
475         return textUnderElement();
476     
477     if (m_renderer->isMenuList())
478         return static_cast<RenderMenuList*>(m_renderer)->text();
479     
480     if (m_renderer->isListMarker())
481         return static_cast<RenderListMarker*>(m_renderer)->text();
482     
483     if (isWebArea()) {
484         if (m_renderer->document()->frame())
485             return String();
486         
487         // FIXME: should use startOfDocument and endOfDocument (or rangeForDocument?) here
488         VisiblePosition startVisiblePosition = m_renderer->positionForCoordinates(0, 0);
489         VisiblePosition endVisiblePosition = m_renderer->positionForCoordinates(INT_MAX, INT_MAX);
490         if (startVisiblePosition.isNull() || endVisiblePosition.isNull())
491             return String();
492         
493         return plainText(makeRange(startVisiblePosition, endVisiblePosition).get());
494     }
495     
496     if (isTextControl())
497         return text();
498     
499     // FIXME: We might need to implement a value here for more types
500     // FIXME: It would be better not to advertise a value at all for the types for which we don't implement one;
501     // this would require subclassing or making accessibilityAttributeNames do something other than return a
502     // single static array.
503     return String();
504 }
505
506 // This function implements the ARIA accessible name as described by the Mozilla
507 // ARIA Implementer's Guide.
508 static String accessibleNameForNode(Node* node)
509 {
510     if (node->isTextNode())
511         return static_cast<Text*>(node)->data();
512
513     if (node->hasTagName(inputTag))
514         return static_cast<HTMLInputElement*>(node)->value();
515
516     if (node->isHTMLElement()) {
517         const AtomicString& alt = static_cast<HTMLElement*>(node)->getAttribute(altAttr);
518         if (!alt.isEmpty())
519             return alt;
520     }
521
522     return String();
523 }
524
525 String AccessibilityRenderObject::ariaAccessiblityName(const String& s) const
526 {
527     Document* document = m_renderer->document();
528     if (!document)
529         return String();
530
531     String idList = s;
532     idList.replace('\n', ' ');
533     Vector<String> idVector;
534     idList.split(' ', idVector);
535
536     Vector<UChar> ariaLabel;
537     unsigned size = idVector.size();
538     for (unsigned i = 0; i < size; ++i) {
539         String idName = idVector[i];
540         Element* idElement = document->getElementById(idName);
541         if (idElement) {
542             String nameFragment = accessibleNameForNode(idElement);
543             ariaLabel.append(nameFragment.characters(), nameFragment.length());
544             for (Node* n = idElement->firstChild(); n; n = n->traverseNextNode(idElement->nextSibling())) {
545                 nameFragment = accessibleNameForNode(n);
546                 ariaLabel.append(nameFragment.characters(), nameFragment.length());
547             }
548             ariaLabel.append(' ');
549         }
550     }
551     return String::adopt(ariaLabel);
552 }
553
554 String AccessibilityRenderObject::ariaLabeledByAttribute() const
555 {
556     Node* node = m_renderer->node();
557     if (!node || !node->isElementNode())
558         return String();
559
560     // The ARIA spec uses the British spelling: "labelled." It seems prudent to support the American
561     // spelling ("labeled") as well.
562     Element* element = static_cast<Element*>(node);
563     String idList = element->getAttribute(aria_labeledbyAttr).string();
564     if (idList.isEmpty()) {
565         idList = element->getAttribute(aria_labelledbyAttr).string();
566         if (idList.isEmpty())
567             return String();
568     }
569
570     return ariaAccessiblityName(idList);
571 }
572
573 static HTMLLabelElement* labelForElement(Element* element)
574 {
575     RefPtr<NodeList> list = element->document()->getElementsByTagName("label");
576     unsigned len = list->length();
577     for (unsigned i = 0; i < len; i++) {
578         if (list->item(i)->hasTagName(labelTag)) {
579             HTMLLabelElement* label = static_cast<HTMLLabelElement*>(list->item(i));
580             if (label->correspondingControl() == element)
581                 return label;
582         }
583     }
584     
585     return 0;
586 }
587
588 String AccessibilityRenderObject::title() const
589 {
590     if (!m_renderer || m_areaElement || !m_renderer->element())
591         return String();
592
593     String ariaLabel = ariaLabeledByAttribute();
594     if (!ariaLabel.isEmpty())
595         return ariaLabel;
596     
597     if (roleValue() == ButtonRole)
598         return textUnderElement();
599     
600     bool isInputTag = m_renderer->element()->hasTagName(inputTag);
601     if (isInputTag) {
602         HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element());
603         if (input->isTextButton())
604             return input->value();
605     }
606     
607     if (isInputTag || AccessibilityObject::isARIAInput(ariaRoleAttribute())) {
608         HTMLLabelElement* label = labelForElement(static_cast<Element*>(m_renderer->element()));
609         if (label)
610             return label->innerText();
611     }
612     
613     if (isLink() || isHeading())
614         return textUnderElement();
615     
616     return String();
617 }
618
619 String AccessibilityRenderObject::ariaDescribedByAttribute() const
620 {
621     Node* node = m_renderer->node();
622     if (!node || !node->isElementNode())
623         return String();
624
625     Element* element = static_cast<Element*>(node);
626     String idList = element->getAttribute(aria_describedbyAttr).string();
627     if (idList.isEmpty())
628         return String();
629     
630     return ariaAccessiblityName(idList);
631 }
632
633 String AccessibilityRenderObject::accessibilityDescription() const
634 {
635     if (!m_renderer || m_areaElement)
636         return String();
637
638     String ariaDescription = ariaDescribedByAttribute();
639     if (!ariaDescription.isEmpty())
640         return ariaDescription;
641     
642     if (isImage()) {
643         if (m_renderer->element() && m_renderer->element()->isHTMLElement()) {
644             const AtomicString& alt = static_cast<HTMLElement*>(m_renderer->element())->getAttribute(altAttr);
645             if (alt.isEmpty())
646                 return String();
647             return alt;
648         }
649     }
650     
651     if (isWebArea()) {
652         Document *document = m_renderer->document();
653         Node* owner = document->ownerElement();
654         if (owner) {
655             if (owner->hasTagName(frameTag) || owner->hasTagName(iframeTag))
656                 return static_cast<HTMLFrameElementBase*>(owner)->name();
657             if (owner->isHTMLElement())
658                 return static_cast<HTMLElement*>(owner)->getAttribute(nameAttr);
659         }
660         owner = document->body();
661         if (owner && owner->isHTMLElement())
662             return static_cast<HTMLElement*>(owner)->getAttribute(nameAttr);
663     }
664     
665     return String();
666 }
667
668 IntRect AccessibilityRenderObject::boundingBoxRect() const
669 {
670     IntRect rect;
671     RenderObject* obj = m_renderer;
672     
673     if (!obj)
674         return IntRect();
675     
676     if (obj->isInlineContinuation())
677         obj = obj->element()->renderer();
678     
679     // FIXME: This doesn't work correctly with transforms.
680     Vector<IntRect> rects;
681     int x, y;
682     obj->absolutePosition(x, y);
683     obj->absoluteRects(rects, x, y);
684     const size_t n = rects.size();
685     for (size_t i = 0; i < n; ++i) {
686         IntRect r = rects[i];
687         if (!r.isEmpty()) {
688             if (obj->style()->hasAppearance())
689                 theme()->adjustRepaintRect(obj, r);
690             rect.unite(r);
691         }
692     }
693     return rect;
694 }
695
696 IntRect AccessibilityRenderObject::elementRect() const
697 {
698     if (m_areaElement)
699         return m_areaElement->getRect(m_renderer);
700     
701     return boundingBoxRect();
702 }
703
704 IntSize AccessibilityRenderObject::size() const
705 {
706     IntRect rect = elementRect();
707     return rect.size();
708 }
709
710 // the closest object for an internal anchor
711 AccessibilityObject* AccessibilityRenderObject::linkedUIElement() const
712 {
713     if (!isAnchor())
714         return 0;
715     
716     HTMLAnchorElement* anchor = anchorElement();
717     if (!anchor)
718         return 0;
719     
720     KURL linkURL = anchor->href();
721     String ref = linkURL.ref();
722     if (ref.isEmpty())
723         return 0;
724     
725     // check if URL is the same as current URL
726     linkURL.setRef("");
727     if (m_renderer->document()->url() != linkURL)
728         return 0;
729     
730     Node* linkedNode = m_renderer->document()->getElementById(ref);
731     if (!linkedNode) {
732         linkedNode = m_renderer->document()->anchors()->namedItem(ref, !m_renderer->document()->inCompatMode());
733         if (!linkedNode)
734             return 0;
735     }
736     
737     // the element we find may not be accessible, keep searching until we find a good one
738     AccessibilityObject* linkedAXElement = m_renderer->document()->axObjectCache()->get(linkedNode->renderer());
739     while (linkedAXElement && linkedAXElement->accessibilityIsIgnored()) {
740         linkedNode = linkedNode->traverseNextNode();
741         if (!linkedNode)
742             return 0;
743         linkedAXElement = m_renderer->document()->axObjectCache()->get(linkedNode->renderer());
744     }
745     
746     return linkedAXElement;
747 }
748
749 bool AccessibilityRenderObject::accessibilityShouldUseUniqueId() const
750 {
751     return isWebArea() || isTextControl();
752 }
753
754 bool AccessibilityRenderObject::accessibilityIsIgnored() const
755 {
756     // ignore invisible element
757     if (!m_renderer || m_renderer->style()->visibility() != VISIBLE)
758         return true;
759
760     if (ariaRoleAttribute() != UnknownRole)
761         return false;
762     
763     // ignore popup menu items because AppKit does
764     for (RenderObject* parent = m_renderer->parent(); parent; parent = parent->parent()) {
765         if (parent->isMenuList())
766             return true;
767     }
768     
769     AccessibilityRole ariaRole = ariaRoleAttribute();
770     if (ariaRole == TextAreaRole || ariaRole == StaticTextRole) {
771         String ariaText = text();
772         return ariaText.isNull() || ariaText.isEmpty();
773     }    
774     
775     // NOTE: BRs always have text boxes now, so the text box check here can be removed
776     if (m_renderer->isText())
777         return m_renderer->isBR() || !static_cast<RenderText*>(m_renderer)->firstTextBox();
778     
779     if (isHeading())
780         return false;
781     
782     if (m_areaElement || isLink())
783         return false;
784     
785     // all controls are accessible
786     if (m_renderer->element() && (m_renderer->element()->isControl() || AccessibilityObject::isARIAControl(ariaRoleAttribute())))
787         return false;
788     
789     if (m_renderer->isBlockFlow() && m_renderer->childrenInline())
790         return !static_cast<RenderBlock*>(m_renderer)->firstLineBox() && !mouseButtonListener();
791     
792     // ignore images seemingly used as spacers
793     if (isImage()) {
794         // informal standard is to ignore images with zero-length alt strings
795         Node* node = m_renderer->element();
796         if (node && node->isElementNode()) {
797             Element* elt = static_cast<Element*>(node);
798             const AtomicString& alt = elt->getAttribute(altAttr);
799             if (alt.isEmpty() && !alt.isNull())
800                 return true;
801         }
802         
803         // check for one-dimensional image
804         if (m_renderer->height() <= 1 || m_renderer->width() <= 1)
805             return true;
806         
807         // check whether rendered image was stretched from one-dimensional file image
808         if (isNativeImage()) {
809             RenderImage* image = static_cast<RenderImage*>(m_renderer);
810             if (image->cachedImage()) {
811                 IntSize imageSize = image->cachedImage()->imageSize(image->view()->zoomFactor());
812                 return imageSize.height() <= 1 || imageSize.width() <= 1;
813             }
814         }
815         return false;
816     }
817     
818     return !m_renderer->isListMarker() && !isWebArea();
819 }
820
821 bool AccessibilityRenderObject::isLoaded() const
822 {
823     return !m_renderer->document()->tokenizer();
824 }
825
826 int AccessibilityRenderObject::layoutCount() const
827 {
828     if (!m_renderer->isRenderView())
829         return 0;
830     return static_cast<RenderView*>(m_renderer)->frameView()->layoutCount();
831 }
832
833 String AccessibilityRenderObject::text() const
834 {
835     if (!isTextControl() || isPasswordField())
836         return String();
837     
838     if (isNativeTextControl())
839         return static_cast<RenderTextControl*>(m_renderer)->text();
840     
841     Node* node = m_renderer->element();
842     if (!node)
843         return String();
844     if (!node->isElementNode())
845         return String();
846     
847     return static_cast<Element*>(node)->innerText();
848 }
849     
850 int AccessibilityRenderObject::textLength() const
851 {
852     ASSERT(isTextControl());
853     
854     if (isPasswordField())
855         return -1; // need to return something distinct from 0
856     
857     return text().length();
858 }
859
860 PassRefPtr<Range> AccessibilityRenderObject::ariaSelectedTextDOMRange() const
861 {
862     Node* node = m_renderer->element();
863     if (!node)
864         return 0;
865     
866     RefPtr<Range> currentSelectionRange = selection().toRange();
867     if (!currentSelectionRange)
868         return 0;
869     
870     ExceptionCode ec = 0;
871     if (!currentSelectionRange->intersectsNode(node, ec))
872         return Range::create(currentSelectionRange->ownerDocument());
873     
874     RefPtr<Range> ariaRange = rangeOfContents(node);
875     Position startPosition, endPosition;
876     
877     // Find intersection of currentSelectionRange and ariaRange
878     if (ariaRange->startOffset() > currentSelectionRange->startOffset())
879         startPosition = ariaRange->startPosition();
880     else
881         startPosition = currentSelectionRange->startPosition();
882     
883     if (ariaRange->endOffset() < currentSelectionRange->endOffset())
884         endPosition = ariaRange->endPosition();
885     else
886         endPosition = currentSelectionRange->endPosition();
887     
888     return Range::create(ariaRange->ownerDocument(), startPosition, endPosition);
889 }
890
891 String AccessibilityRenderObject::selectedText() const
892 {
893     ASSERT(isTextControl());
894     
895     if (isPasswordField())
896         return String(); // need to return something distinct from empty string
897     
898     if (isNativeTextControl()) {
899         RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
900         return textControl->text().substring(textControl->selectionStart(), textControl->selectionEnd() - textControl->selectionStart());
901     }
902     
903     if (ariaRoleAttribute() == UnknownRole)
904         return String();
905     
906     RefPtr<Range> ariaRange = ariaSelectedTextDOMRange();
907     if (!ariaRange)
908         return String();
909     return ariaRange->text();
910 }
911
912 const AtomicString& AccessibilityRenderObject::accessKey() const
913 {
914     Node* node = m_renderer->element();
915     if (!node || !node->isElementNode())
916         return nullAtom;
917     return static_cast<Element*>(node)->getAttribute(accesskeyAttr);
918 }
919
920 Selection AccessibilityRenderObject::selection() const
921 {
922     return m_renderer->document()->frame()->selectionController()->selection();
923 }
924
925 PlainTextRange AccessibilityRenderObject::selectedTextRange() const
926 {
927     ASSERT(isTextControl());
928     
929     if (isPasswordField())
930         return PlainTextRange();
931     
932     AccessibilityRole ariaRole = ariaRoleAttribute();
933     if (isNativeTextControl() && ariaRole == UnknownRole) {
934         RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
935         return PlainTextRange(textControl->selectionStart(), textControl->selectionEnd() - textControl->selectionStart());
936     }
937     
938     if (ariaRole == UnknownRole)
939         return PlainTextRange();
940     
941     RefPtr<Range> ariaRange = ariaSelectedTextDOMRange();
942     if (!ariaRange)
943         return PlainTextRange();
944     return PlainTextRange(ariaRange->startOffset(), ariaRange->endOffset());
945 }
946
947 void AccessibilityRenderObject::setSelectedTextRange(const PlainTextRange& range)
948 {
949     if (isNativeTextControl()) {
950         RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
951         textControl->setSelectionRange(range.start, range.start + range.length);
952     }
953     
954     Document* document = m_renderer->document();
955     if (!document)
956         return;
957     Frame* frame = document->frame();
958     if (!frame)
959         return;
960     Node* node = m_renderer->element();
961     frame->selectionController()->setSelection(Selection(Position(node, range.start),
962         Position(node, range.start + range.length), DOWNSTREAM));
963 }
964
965 KURL AccessibilityRenderObject::url() const
966 {
967     if (isAnchor()) {
968         if (HTMLAnchorElement* anchor = anchorElement())
969             return anchor->href();
970     }
971     
972     if (isWebArea())
973         return m_renderer->document()->documentURI();
974     
975     if (isImage() && m_renderer->element() && m_renderer->element()->hasTagName(imgTag))
976         return static_cast<HTMLImageElement*>(m_renderer->element())->src();
977     
978     return KURL();
979 }
980
981 bool AccessibilityRenderObject::isVisited() const
982 {
983     return m_renderer->style()->pseudoState() == PseudoVisited;
984 }
985
986 bool AccessibilityRenderObject::isSelected() const
987 {
988     if (!m_renderer)
989         return false;
990     
991     Node* node = m_renderer->node();
992     if (!node)
993         return false;
994     
995     return false;
996 }
997
998 bool AccessibilityRenderObject::isFocused() const
999 {
1000     return (m_renderer->element() && m_renderer->document()->focusedNode() == m_renderer->element());
1001 }
1002
1003 void AccessibilityRenderObject::setFocused(bool on)
1004 {
1005     if (!canSetFocusAttribute())
1006         return;
1007     
1008     if (!on)
1009         m_renderer->document()->setFocusedNode(0);
1010     else {
1011         if (m_renderer->element()->isElementNode())
1012             static_cast<Element*>(m_renderer->element())->focus();
1013         else
1014             m_renderer->document()->setFocusedNode(m_renderer->element());
1015     }
1016 }
1017
1018 void AccessibilityRenderObject::setValue(const String& string)
1019 {
1020     // FIXME: Do we want to do anything here for ARIA textboxes?
1021     if (m_renderer->isTextField()) {
1022         HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element());
1023         input->setValue(string);
1024     } else if (m_renderer->isTextArea()) {
1025         HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(m_renderer->element());
1026         textArea->setValue(string);
1027     }
1028 }
1029
1030 bool AccessibilityRenderObject::isEnabled() const
1031 {
1032     return m_renderer->element() ? m_renderer->element()->isEnabled() : true;
1033 }
1034
1035 RenderObject* AccessibilityRenderObject::topRenderer() const
1036 {
1037     return m_renderer->document()->topDocument()->renderer();
1038 }
1039
1040 Document* AccessibilityRenderObject::document() const
1041 {
1042     return m_renderer->document();
1043 }
1044
1045 FrameView* AccessibilityRenderObject::topDocumentFrameView() const
1046 {
1047     return topRenderer()->view()->frameView();
1048 }
1049
1050 Widget* AccessibilityRenderObject::widget() const
1051 {
1052     if (!m_renderer->isWidget())
1053         return 0;
1054     
1055     return static_cast<RenderWidget*>(m_renderer)->widget();
1056 }
1057
1058 AXObjectCache* AccessibilityRenderObject::axObjectCache() const
1059 {
1060     return m_renderer->document()->axObjectCache();
1061 }
1062
1063 void AccessibilityRenderObject::getDocumentLinks(Vector<RefPtr<AccessibilityObject> >& result) const
1064 {
1065     Document* document = m_renderer->document();
1066     RefPtr<HTMLCollection> coll = document->links();
1067     Node* curr = coll->firstItem();
1068     while (curr) {
1069         RenderObject* obj = curr->renderer();
1070         if (obj) {
1071             RefPtr<AccessibilityObject> axobj = document->axObjectCache()->get(obj);
1072             ASSERT(axobj);
1073             ASSERT(axobj->roleValue() == WebCoreLinkRole);
1074             if (!axobj->accessibilityIsIgnored())
1075                 result.append(axobj);
1076         }
1077         curr = coll->nextItem();
1078     }
1079 }
1080
1081 FrameView* AccessibilityRenderObject::documentFrameView() const 
1082
1083     if (!m_renderer || !m_renderer->document()) 
1084         return 0; 
1085
1086     // this is the RenderObject's Document's Frame's FrameView 
1087     return m_renderer->document()->view();
1088 }
1089
1090 Widget* AccessibilityRenderObject::widgetForAttachmentView() const
1091 {
1092     if (!isAttachment())
1093         return 0;
1094     return static_cast<RenderWidget*>(m_renderer)->widget();
1095 }
1096
1097 FrameView* AccessibilityRenderObject::frameViewIfRenderView() const
1098 {
1099     if (!m_renderer->isRenderView())
1100         return 0;
1101     // this is the RenderObject's Document's renderer's FrameView
1102     return m_renderer->view()->frameView();
1103 }
1104
1105 // This function is like a cross-platform version of - (WebCoreTextMarkerRange*)textMarkerRange. It returns
1106 // a Range that we can convert to a WebCoreTextMarkerRange in the Obj-C file
1107 VisiblePositionRange AccessibilityRenderObject::visiblePositionRange() const
1108 {
1109     if (!m_renderer)
1110         return VisiblePositionRange();
1111     
1112     // construct VisiblePositions for start and end
1113     Node* node = m_renderer->element();
1114     VisiblePosition startPos = VisiblePosition(node, 0, VP_DEFAULT_AFFINITY);
1115     VisiblePosition endPos = VisiblePosition(node, maxDeepOffset(node), VP_DEFAULT_AFFINITY);
1116     
1117     // the VisiblePositions are equal for nodes like buttons, so adjust for that
1118     if (startPos == endPos) {
1119         endPos = endPos.next();
1120         if (endPos.isNull())
1121             endPos = startPos;
1122     }
1123     
1124     return VisiblePositionRange(startPos, endPos);
1125 }
1126
1127 VisiblePositionRange AccessibilityRenderObject::doAXTextMarkerRangeForLine(unsigned lineCount) const
1128 {
1129     if (lineCount == 0 || !m_renderer)
1130         return VisiblePositionRange();
1131     
1132     // iterate over the lines
1133     // FIXME: this is wrong when lineNumber is lineCount+1,  because nextLinePosition takes you to the
1134     // last offset of the last line
1135     VisiblePosition visiblePos = m_renderer->document()->renderer()->positionForCoordinates(0, 0);
1136     VisiblePosition savedVisiblePos;
1137     while (--lineCount != 0) {
1138         savedVisiblePos = visiblePos;
1139         visiblePos = nextLinePosition(visiblePos, 0);
1140         if (visiblePos.isNull() || visiblePos == savedVisiblePos)
1141             return VisiblePositionRange();
1142     }
1143     
1144     // make a caret selection for the marker position, then extend it to the line
1145     // NOTE: ignores results of sel.modify because it returns false when
1146     // starting at an empty line.  The resulting selection in that case
1147     // will be a caret at visiblePos.
1148     SelectionController selectionController;
1149     selectionController.setSelection(Selection(visiblePos));
1150     selectionController.modify(SelectionController::EXTEND, SelectionController::RIGHT, LineBoundary);
1151     
1152     return VisiblePositionRange(selectionController.selection().visibleStart(), selectionController.selection().visibleEnd());
1153 }
1154     
1155 VisiblePosition AccessibilityRenderObject::visiblePositionForIndex(int index) const
1156 {
1157     if (isNativeTextControl())
1158         return static_cast<RenderTextControl*>(m_renderer)->visiblePositionForIndex(index);
1159     
1160     if (!isTextControl())
1161         return VisiblePosition();
1162     
1163     Node* node = m_renderer->node();
1164     if (!node)
1165         return VisiblePosition();
1166     
1167     if (index <= 0)
1168         return VisiblePosition(node, 0, DOWNSTREAM);
1169     
1170     ExceptionCode ec = 0;
1171     RefPtr<Range> range = Range::create(m_renderer->document());
1172     range->selectNodeContents(node, ec);
1173     CharacterIterator it(range.get());
1174     it.advance(index - 1);
1175     return VisiblePosition(it.range()->endContainer(ec), it.range()->endOffset(ec), UPSTREAM);
1176 }
1177     
1178 int AccessibilityRenderObject::indexForVisiblePosition(const VisiblePosition& pos) const
1179 {
1180     if (isNativeTextControl())
1181         return static_cast<RenderTextControl*>(m_renderer)->indexForVisiblePosition(pos);
1182     
1183     if (!isTextControl())
1184         return 0;
1185     
1186     Node* node = m_renderer->node();
1187     if (!node)
1188         return 0;
1189     
1190     Position indexPosition = pos.deepEquivalent();
1191     if (!indexPosition.node() || indexPosition.node()->rootEditableElement() != node)
1192         return 0;
1193     
1194     ExceptionCode ec = 0;
1195     RefPtr<Range> range = Range::create(m_renderer->document());
1196     range->setStart(node, 0, ec);
1197     range->setEnd(indexPosition.node(), indexPosition.offset(), ec);
1198     return TextIterator::rangeLength(range.get());
1199 }
1200
1201 IntRect AccessibilityRenderObject::doAXBoundsForTextMarkerRange(const VisiblePositionRange& visiblePositionRange) const
1202 {
1203     if (visiblePositionRange.isNull())
1204         return IntRect();
1205     
1206     // Create a mutable VisiblePositionRange.
1207     VisiblePositionRange range(visiblePositionRange);
1208     IntRect rect1 = range.start.caretRect();
1209     IntRect rect2 = range.end.caretRect();
1210     
1211     // 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
1212     if (rect2.y() != rect1.y()) {
1213         VisiblePosition endOfFirstLine = endOfLine(range.start);
1214         if (range.start == endOfFirstLine) {
1215             range.start.setAffinity(DOWNSTREAM);
1216             rect1 = range.start.caretRect();
1217         }
1218         if (range.end == endOfFirstLine) {
1219             range.end.setAffinity(UPSTREAM);
1220             rect2 = range.end.caretRect();
1221         }
1222     }
1223     
1224     IntRect ourrect = rect1;
1225     ourrect.unite(rect2);
1226     
1227     // if the rectangle spans lines and contains multiple text chars, use the range's bounding box intead
1228     if (rect1.bottom() != rect2.bottom()) {
1229         RefPtr<Range> dataRange = makeRange(range.start, range.end);
1230         IntRect boundingBox = dataRange->boundingBox();
1231         String rangeString = plainText(dataRange.get());
1232         if (rangeString.length() > 1 && !boundingBox.isEmpty())
1233             ourrect = boundingBox;
1234     }
1235     
1236 #if PLATFORM(MAC)
1237     return m_renderer->document()->view()->contentsToScreen(ourrect);
1238 #else
1239     return ourrect;
1240 #endif
1241 }
1242     
1243 void AccessibilityRenderObject::doSetAXSelectedTextMarkerRange(const VisiblePositionRange& textMarkerRange) const
1244 {
1245     if (textMarkerRange.start.isNull() || textMarkerRange.end.isNull())
1246         return;
1247     
1248     // make selection and tell the document to use it
1249     Selection newSelection = Selection(textMarkerRange.start, textMarkerRange.end);
1250     m_renderer->document()->frame()->selectionController()->setSelection(newSelection);
1251 }
1252
1253 VisiblePosition AccessibilityRenderObject::doAXTextMarkerForPosition(const IntPoint& point) const
1254 {
1255     // convert absolute point to view coordinates
1256     FrameView* frameView = m_renderer->document()->topDocument()->renderer()->view()->frameView();
1257     RenderObject* renderer = topRenderer();
1258     Node* innerNode = 0;
1259     
1260     // locate the node containing the point
1261     IntPoint pointResult;
1262     while (1) {
1263         IntPoint ourpoint;
1264 #if PLATFORM(MAC)
1265         ourpoint = frameView->screenToContents(point);
1266 #else
1267         ourpoint = point;
1268 #endif
1269         HitTestRequest request(true, true);
1270         HitTestResult result(ourpoint);
1271         renderer->layer()->hitTest(request, result);
1272         innerNode = result.innerNode();
1273         if (!innerNode || !innerNode->renderer())
1274             return VisiblePosition();
1275         
1276         pointResult = result.localPoint();
1277         
1278         // done if hit something other than a widget
1279         renderer = innerNode->renderer();
1280         if (!renderer->isWidget())
1281             break;
1282         
1283         // descend into widget (FRAME, IFRAME, OBJECT...)
1284         Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
1285         if (!widget || !widget->isFrameView())
1286             break;
1287         Frame* frame = static_cast<FrameView*>(widget)->frame();
1288         if (!frame)
1289             break;
1290         Document* document = frame->document();
1291         if (!document)
1292             break;
1293         renderer = document->renderer();
1294         frameView = static_cast<FrameView*>(widget);
1295     }
1296     
1297     return innerNode->renderer()->positionForPoint(pointResult);
1298 }
1299
1300 // NOTE: Consider providing this utility method as AX API
1301 VisiblePosition AccessibilityRenderObject::textMarkerForIndex(unsigned indexValue, bool lastIndexOK) const
1302 {
1303     if (!isTextControl())
1304         return VisiblePosition();
1305     
1306     // lastIndexOK specifies whether the position after the last character is acceptable
1307     if (indexValue >= text().length()) {
1308         if (!lastIndexOK || indexValue > text().length())
1309             return VisiblePosition();
1310     }
1311     VisiblePosition position = visiblePositionForIndex(indexValue);
1312     position.setAffinity(DOWNSTREAM);
1313     return position;
1314 }
1315
1316 // NOTE: Consider providing this utility method as AX API
1317 int AccessibilityRenderObject::indexForTextMarker(const VisiblePosition& position) const
1318 {
1319     if (!isTextControl())
1320         return -1;
1321     
1322     Node* node = position.deepEquivalent().node();
1323     if (!node)
1324         return -1;
1325     
1326     for (RenderObject* renderer = node->renderer(); renderer && renderer->element(); renderer = renderer->parent()) {
1327         if (renderer == m_renderer)
1328             return indexForVisiblePosition(position);
1329     }
1330     
1331     return -1;
1332 }
1333
1334 // Given a line number, the range of characters of the text associated with this accessibility
1335 // object that contains the line number.
1336 PlainTextRange AccessibilityRenderObject::doAXRangeForLine(unsigned lineNumber) const
1337 {
1338     if (!isTextControl())
1339         return PlainTextRange();
1340     
1341     // iterate to the specified line
1342     VisiblePosition visiblePos = visiblePositionForIndex(0);
1343     VisiblePosition savedVisiblePos;
1344     for (unsigned lineCount = lineNumber; lineCount != 0; lineCount -= 1) {
1345         savedVisiblePos = visiblePos;
1346         visiblePos = nextLinePosition(visiblePos, 0);
1347         if (visiblePos.isNull() || visiblePos == savedVisiblePos)
1348             return PlainTextRange();
1349     }
1350     
1351     // make a caret selection for the marker position, then extend it to the line
1352     // NOTE: ignores results of selectionController.modify because it returns false when
1353     // starting at an empty line.  The resulting selection in that case
1354     // will be a caret at visiblePos.
1355     SelectionController selectionController;
1356     selectionController.setSelection(Selection(visiblePos));
1357     selectionController.modify(SelectionController::EXTEND, SelectionController::LEFT, LineBoundary);
1358     selectionController.modify(SelectionController::EXTEND, SelectionController::RIGHT, LineBoundary);
1359     
1360     // calculate the indices for the selection start and end
1361     VisiblePosition startPosition = selectionController.selection().visibleStart();
1362     VisiblePosition endPosition = selectionController.selection().visibleEnd();
1363     int index1 = indexForVisiblePosition(startPosition);
1364     int index2 = indexForVisiblePosition(endPosition);
1365     
1366     // add one to the end index for a line break not caused by soft line wrap (to match AppKit)
1367     if (endPosition.affinity() == DOWNSTREAM && endPosition.next().isNotNull())
1368         index2 += 1;
1369     
1370     // return nil rather than an zero-length range (to match AppKit)
1371     if (index1 == index2)
1372         return PlainTextRange();
1373     
1374     return PlainTextRange(index1, index2 - index1);
1375 }
1376
1377 // The composed character range in the text associated with this accessibility object that
1378 // is specified by the given index value. This parameterized attribute returns the complete
1379 // range of characters (including surrogate pairs of multi-byte glyphs) at the given index.
1380 PlainTextRange AccessibilityRenderObject::doAXRangeForIndex(unsigned index) const
1381 {
1382     if (!isTextControl())
1383         return PlainTextRange();
1384     
1385     String elementText = text();
1386     if (!elementText.length() || index > elementText.length() - 1)
1387         return PlainTextRange();
1388     
1389     return PlainTextRange(index, 1);
1390 }
1391
1392 // A substring of the text associated with this accessibility object that is
1393 // specified by the given character range.
1394 String AccessibilityRenderObject::doAXStringForRange(const PlainTextRange& range) const
1395 {
1396     if (isPasswordField())
1397         return String();
1398     
1399     if (range.length == 0)
1400         return "";
1401     
1402     if (!isTextControl())
1403         return String();
1404     
1405     String elementText = text();
1406     if (range.start + range.length > elementText.length())
1407         return String();
1408     
1409     return elementText.substring(range.start, range.length);
1410 }
1411
1412 // The bounding rectangle of the text associated with this accessibility object that is
1413 // specified by the given range. This is the bounding rectangle a sighted user would see
1414 // on the display screen, in pixels.
1415 IntRect AccessibilityRenderObject::doAXBoundsForRange(const PlainTextRange& range) const
1416 {
1417     if (isTextControl())
1418         return doAXBoundsForTextMarkerRange(textMarkerRangeForRange(range));
1419     return IntRect();
1420 }
1421
1422 AccessibilityObject* AccessibilityRenderObject::doAccessibilityHitTest(const IntPoint& point) const
1423 {
1424     if (!m_renderer)
1425         return 0;
1426     
1427     RenderLayer* layer = m_renderer->layer();
1428     if (!layer)
1429         return 0;
1430     
1431     HitTestRequest request(true, true);
1432     HitTestResult hitTestResult = HitTestResult(point);
1433     layer->hitTest(request, hitTestResult);
1434     if (!hitTestResult.innerNode())
1435         return 0;
1436     Node* node = hitTestResult.innerNode()->shadowAncestorNode();
1437     RenderObject* obj = node->renderer();
1438     if (!obj)
1439         return 0;
1440     
1441     AccessibilityObject *result = obj->document()->axObjectCache()->get(obj);
1442
1443     if (obj->isListBox())
1444         return static_cast<AccessibilityListBox*>(result)->doAccessibilityHitTest(point);
1445         
1446     if (result->accessibilityIsIgnored())
1447         result = result->parentObjectUnignored();
1448
1449     return result;
1450 }
1451
1452 AccessibilityObject* AccessibilityRenderObject::focusedUIElement() const
1453 {
1454     // get the focused node in the page
1455     Page* page = m_renderer->document()->page();
1456     if (!page)
1457         return 0;
1458     
1459     Document* focusedDocument = page->focusController()->focusedOrMainFrame()->document();
1460     Node* focusedNode = focusedDocument->focusedNode();
1461     if (!focusedNode)
1462         focusedNode = focusedDocument;
1463     
1464     RenderObject* focusedNodeRenderer = focusedNode->renderer();
1465     if (!focusedNodeRenderer)
1466         return 0;
1467     
1468     AccessibilityObject* obj = focusedNodeRenderer->document()->axObjectCache()->get(focusedNodeRenderer);
1469     
1470     // the HTML element, for example, is focusable but has an AX object that is ignored
1471     if (obj->accessibilityIsIgnored())
1472         obj = obj->parentObjectUnignored();
1473     
1474     return obj;
1475 }
1476
1477 AccessibilityObject* AccessibilityRenderObject::observableObject() const
1478 {
1479     for (RenderObject* renderer = m_renderer; renderer && renderer->element(); renderer = renderer->parent()) {
1480         if (renderer->isTextField() || renderer->isTextArea())
1481             return renderer->document()->axObjectCache()->get(renderer);
1482     }
1483     
1484     return 0;
1485 }
1486     
1487 typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap;
1488
1489 static const ARIARoleMap& createARIARoleMap()
1490 {
1491     struct RoleEntry {
1492         String ariaRole;
1493         AccessibilityRole webcoreRole;
1494     };
1495
1496     static const RoleEntry roles[] = {
1497         { String("button"), ButtonRole },
1498         { String("checkbox"), CheckBoxRole },
1499         { String("heading"), HeadingRole },
1500         { String("img"), ImageRole },
1501         { String("link"), WebCoreLinkRole },
1502         { String("radio"), RadioButtonRole },
1503         { String("textbox"), TextAreaRole }
1504     };
1505     ARIARoleMap& roleMap = *new ARIARoleMap;
1506         
1507     const unsigned numRoles = sizeof(roles) / sizeof(roles[0]);
1508     for (unsigned i = 0; i < numRoles; ++i)
1509         roleMap.set(roles[i].ariaRole, roles[i].webcoreRole);
1510     return roleMap;
1511 }
1512
1513 static AccessibilityRole ariaRoleToWebCoreRole(String value)
1514 {
1515     ASSERT(!value.isEmpty() && !value.isNull());
1516     static const ARIARoleMap& roleMap = createARIARoleMap();
1517     return roleMap.get(value);
1518 }
1519
1520 AccessibilityRole AccessibilityRenderObject::ariaRoleAttribute() const
1521 {
1522     Node* node = m_renderer->node();
1523     if (!node || !node->isElementNode())
1524         return UnknownRole;
1525     
1526     Element* element = static_cast<Element*>(node);
1527     String ariaRole = element->getAttribute(roleAttr).string();
1528     if (ariaRole.isNull() || ariaRole.isEmpty())
1529         return UnknownRole;
1530     
1531     AccessibilityRole role = ariaRoleToWebCoreRole(ariaRole);
1532     if (role)
1533         return role;
1534     
1535     return UnknownRole;
1536 }
1537     
1538 AccessibilityRole AccessibilityRenderObject::roleValue() const
1539 {
1540     if (!m_renderer)
1541         return UnknownRole;
1542     
1543     Node* node = m_renderer->element();
1544     AccessibilityRole ariaRole = ariaRoleAttribute();
1545     if (ariaRole != UnknownRole)
1546         return ariaRole;
1547     
1548     if (m_areaElement)
1549         return WebCoreLinkRole;
1550     if (node && node->isLink()) {
1551         if (m_renderer->isImage())
1552             return ImageMapRole;
1553         return WebCoreLinkRole;
1554     }
1555     if (m_renderer->isListMarker())
1556         return ListMarkerRole;
1557     if (node && node->hasTagName(buttonTag))
1558         return ButtonRole;
1559     if (m_renderer->isText())
1560         return StaticTextRole;
1561     if (m_renderer->isImage()) {
1562         if (node && node->hasTagName(inputTag))
1563             return ButtonRole;
1564         return ImageRole;
1565     }
1566     if (m_renderer->isRenderView())
1567         return WebAreaRole;
1568     
1569     if (m_renderer->isTextField())
1570         return TextFieldRole;
1571     
1572     if (m_renderer->isTextArea())
1573         return TextAreaRole;
1574     
1575     if (node && node->hasTagName(inputTag)) {
1576         HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
1577         if (input->inputType() == HTMLInputElement::CHECKBOX)
1578             return CheckBoxRole;
1579         if (input->inputType() == HTMLInputElement::RADIO)
1580             return RadioButtonRole;
1581         if (input->isTextButton())
1582             return ButtonRole;
1583     }
1584
1585     if (node && node->hasTagName(buttonTag))
1586         return ButtonRole;
1587
1588     if (m_renderer->isMenuList())
1589         return PopUpButtonRole;
1590     
1591     if (headingLevel(m_renderer->element()) != 0)
1592         return HeadingRole;
1593     
1594     if (m_renderer->isBlockFlow())
1595         return GroupRole;
1596     
1597     return UnknownRole;
1598 }
1599
1600 bool AccessibilityRenderObject::canSetFocusAttribute() const
1601 {
1602     // NOTE: It would be more accurate to ask the document whether setFocusedNode() would
1603     // do anything.  For example, it setFocusedNode() will do nothing if the current focused
1604     // node will not relinquish the focus.
1605     if (!m_renderer->element() || !m_renderer->element()->isEnabled())
1606         return false;
1607     
1608     switch (roleValue()) {
1609         case WebCoreLinkRole:
1610         case TextFieldRole:
1611         case TextAreaRole:
1612         case ButtonRole:
1613         case PopUpButtonRole:
1614         case CheckBoxRole:
1615         case RadioButtonRole:
1616             return true;
1617         case UnknownRole:
1618         case SliderRole:
1619         case TabGroupRole:
1620         case StaticTextRole:
1621         case ScrollAreaRole:
1622         case MenuButtonRole:
1623         case TableRole:
1624         case ApplicationRole:
1625         case GroupRole:
1626         case RadioGroupRole:
1627         case ListRole:
1628         case ScrollBarRole:
1629         case ValueIndicatorRole:
1630         case ImageRole:
1631         case MenuBarRole:
1632         case MenuRole:
1633         case MenuItemRole:
1634         case ColumnRole:
1635         case RowRole:
1636         case ToolbarRole:
1637         case BusyIndicatorRole:
1638         case ProgressIndicatorRole:
1639         case WindowRole:
1640         case DrawerRole:
1641         case SystemWideRole:
1642         case OutlineRole:
1643         case IncrementorRole:
1644         case BrowserRole:
1645         case ComboBoxRole:
1646         case SplitGroupRole:
1647         case SplitterRole:
1648         case ColorWellRole:
1649         case GrowAreaRole:
1650         case SheetRole:
1651         case HelpTagRole:
1652         case MatteRole:
1653         case RulerRole:
1654         case RulerMarkerRole:
1655         case LinkRole:
1656         case DisclosureTriangleRole:
1657         case GridRole:
1658         case ImageMapRole:
1659         case ListMarkerRole:
1660         case WebAreaRole:
1661         case HeadingRole:
1662         case ListBoxRole:
1663         case ListBoxOptionRole:
1664             return false;
1665     }
1666     ASSERT_NOT_REACHED();
1667     return false;
1668 }
1669
1670 bool AccessibilityRenderObject::canSetValueAttribute() const
1671 {
1672     return isTextControl();
1673 }
1674
1675 bool AccessibilityRenderObject::canSetTextRangeAttributes() const
1676 {
1677     return isTextControl();
1678 }
1679
1680 void AccessibilityRenderObject::childrenChanged()
1681 {
1682     clearChildren();
1683     
1684     if (accessibilityIsIgnored()) {
1685         AccessibilityObject* parent = parentObject();
1686         if (parent)
1687             parent->childrenChanged();
1688     }
1689 }
1690
1691 const Vector<RefPtr<AccessibilityObject> >& AccessibilityRenderObject::children()
1692 {
1693     if (!m_haveChildren)
1694         addChildren();
1695     return m_children;
1696 }
1697
1698 void AccessibilityRenderObject::addChildren()
1699 {
1700     // If the need to add more children in addition to existing children arises, 
1701     // childrenChanged should have been called, leaving the object with no children.
1702     ASSERT(!m_haveChildren); 
1703     
1704     // nothing to add if there is no RenderObject
1705     if (!m_renderer)
1706         return;
1707     
1708     m_haveChildren = true;
1709     
1710     // add all unignored acc children
1711     for (RefPtr<AccessibilityObject> obj = firstChild(); obj; obj = obj->nextSibling()) {
1712         if (obj->accessibilityIsIgnored()) {
1713             if (!m_haveChildren)
1714                 obj->addChildren();
1715             Vector<RefPtr<AccessibilityObject> >children = obj->children();
1716             unsigned length = children.size();
1717             for (unsigned i = 0; i < length; ++i)
1718                 m_children.append(children[i]);
1719         } else
1720             m_children.append(obj);
1721     }
1722     
1723     // for a RenderImage, add the <area> elements as individual accessibility objects
1724     if (m_renderer->isRenderImage() && !m_areaElement) {
1725         HTMLMapElement* map = static_cast<RenderImage*>(m_renderer)->imageMap();
1726         if (map) {
1727             for (Node* current = map->firstChild(); current; current = current->traverseNextNode(map)) {
1728                 // add an <area> element for this child if it has a link
1729                 // NOTE: can't cache these because they all have the same renderer, which is the cache key, right?
1730                 // plus there may be little reason to since they are being added to the handy array
1731                 if (current->isLink()) {
1732                     RefPtr<AccessibilityRenderObject> obj = new AccessibilityRenderObject(m_renderer);
1733                     obj->m_areaElement = static_cast<HTMLAreaElement*>(current);
1734                     m_children.append(obj);
1735                 }
1736             }
1737         }
1738     }
1739 }
1740
1741 void AccessibilityRenderObject::removeAXObjectID()
1742 {
1743     if (!m_id)
1744         return;
1745 #if PLATFORM(MAC)
1746     m_renderer->document()->axObjectCache()->removeAXID(this);
1747 #endif
1748 }   
1749     
1750     const String& AccessibilityRenderObject::actionVerb() const
1751 {
1752     // FIXME: Need to add verbs for select elements.
1753     static const String buttonAction = AXButtonActionVerb();
1754     static const String textFieldAction = AXTextFieldActionVerb();
1755     static const String radioButtonAction = AXRadioButtonActionVerb();
1756     static const String checkedCheckBoxAction = AXCheckedCheckBoxActionVerb();
1757     static const String uncheckedCheckBoxAction = AXUncheckedCheckBoxActionVerb();
1758     static const String linkAction = AXLinkActionVerb();
1759     static const String noAction;
1760     
1761     switch (roleValue()) {
1762         case ButtonRole:
1763             return buttonAction;
1764         case TextFieldRole:
1765         case TextAreaRole:
1766             return textFieldAction;
1767         case RadioButtonRole:
1768             return radioButtonAction;
1769         case CheckBoxRole:
1770             return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction;
1771         case LinkRole:
1772         case WebCoreLinkRole:
1773             return linkAction;
1774         default:
1775             return noAction;
1776     }
1777 }
1778      
1779     
1780 } // namespace WebCore