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