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