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