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