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