61a7d4095ff61d68e5b698bcf8305f2f3a5470ef
[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 "AccessibilityRenderObject.h"
33 #include "AXObjectCache.h"
34 #include "CharacterNames.h"
35 #include "FloatRect.h"
36 #include "FocusController.h"
37 #include "Frame.h"
38 #include "FrameLoader.h"
39 #include "LocalizedStrings.h"
40 #include "NodeList.h"
41 #include "NotImplemented.h"
42 #include "Page.h"
43 #include "RenderImage.h"
44 #include "RenderListMarker.h"
45 #include "RenderMenuList.h"
46 #include "RenderTextControl.h"
47 #include "RenderTheme.h"
48 #include "RenderView.h"
49 #include "RenderWidget.h"
50 #include "SelectionController.h"
51 #include "TextIterator.h"
52 #include "htmlediting.h"
53 #include "visible_units.h"
54 #include <wtf/StdLibExtras.h>
55
56 using namespace std;
57
58 namespace WebCore {
59
60 using namespace HTMLNames;
61
62 AccessibilityObject::AccessibilityObject()
63     : m_id(0)
64     , m_haveChildren(false)
65 #if PLATFORM(GTK)
66     , m_wrapper(0)
67 #endif
68 {
69 }
70
71 AccessibilityObject::~AccessibilityObject()
72 {
73     ASSERT(isDetached());
74 }
75
76 void AccessibilityObject::detach()
77 {
78     removeAXObjectID();
79 #if HAVE(ACCESSIBILITY)
80     setWrapper(0);
81 #endif    
82 }
83
84 AccessibilityObject* AccessibilityObject::firstChild() const
85 {
86     return 0;
87 }
88
89 AccessibilityObject* AccessibilityObject::lastChild() const
90 {
91     return 0;
92 }
93
94 AccessibilityObject* AccessibilityObject::previousSibling() const
95 {
96     return 0;
97 }
98
99 AccessibilityObject* AccessibilityObject::nextSibling() const
100 {
101     return 0;
102 }
103
104 AccessibilityObject* AccessibilityObject::parentObject() const
105 {
106     return 0;
107 }
108
109 AccessibilityObject* AccessibilityObject::parentObjectUnignored() const
110 {
111     AccessibilityObject* parent;
112     for (parent = parentObject(); parent && parent->accessibilityIsIgnored(); parent = parent->parentObject())
113         ;
114     return parent;
115 }
116
117 int AccessibilityObject::layoutCount() const
118 {
119     return 0;
120 }
121     
122 String AccessibilityObject::text() const
123 {
124     return String();
125 }
126     
127 String AccessibilityObject::helpText() const
128 {
129     return String();   
130 }
131
132 String AccessibilityObject::textUnderElement() const
133 {
134     return String();
135 }
136
137 bool AccessibilityObject::isARIAInput(AccessibilityRole ariaRole)
138 {
139     return ariaRole == RadioButtonRole || ariaRole == CheckBoxRole || ariaRole == TextFieldRole;
140 }    
141     
142 bool AccessibilityObject::isARIAControl(AccessibilityRole ariaRole)
143 {
144     return isARIAInput(ariaRole) || ariaRole == TextAreaRole || ariaRole == ButtonRole 
145     || ariaRole == ComboBoxRole || ariaRole == SliderRole; 
146 }
147     
148 int AccessibilityObject::intValue() const
149 {
150     return 0;
151 }
152
153 String AccessibilityObject::stringValue() const
154 {
155     return String();
156 }
157
158 String AccessibilityObject::ariaAccessiblityName(const String&) const
159 {
160     return String();
161 }
162
163 String AccessibilityObject::ariaLabeledByAttribute() const
164 {
165     return String();
166 }
167
168 String AccessibilityObject::title() const
169 {
170     return String();
171 }
172
173 String AccessibilityObject::ariaDescribedByAttribute() const
174 {
175     return String();
176 }
177
178 String AccessibilityObject::accessibilityDescription() const
179 {
180     return String();
181 }
182
183 IntRect AccessibilityObject::boundingBoxRect() const
184 {
185     return IntRect();
186 }
187
188 IntRect AccessibilityObject::elementRect() const
189 {
190     return IntRect();
191 }
192
193 IntSize AccessibilityObject::size() const
194 {
195     return IntSize();
196 }
197
198 IntPoint AccessibilityObject::clickPoint() const
199 {
200     IntRect rect = elementRect();
201     return IntPoint(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2);
202 }
203     
204 void AccessibilityObject::linkedUIElements(AccessibilityChildrenVector&) const
205 {
206     return;
207 }
208     
209 AccessibilityObject* AccessibilityObject::titleUIElement() const
210 {
211      return 0;   
212 }
213
214 int AccessibilityObject::textLength() const
215 {
216     return 0;
217 }
218
219 PassRefPtr<Range> AccessibilityObject::ariaSelectedTextDOMRange() const
220 {
221     return 0;
222 }
223
224 String AccessibilityObject::selectedText() const
225 {
226     return String();
227 }
228
229 const AtomicString& AccessibilityObject::accessKey() const
230 {
231     return nullAtom;
232 }
233
234 VisibleSelection AccessibilityObject::selection() const
235 {
236     return VisibleSelection();
237 }
238
239 PlainTextRange AccessibilityObject::selectedTextRange() const
240 {
241     return PlainTextRange();
242 }
243
244 unsigned AccessibilityObject::selectionStart() const
245 {
246     return selectedTextRange().start;
247 }
248
249 unsigned AccessibilityObject::selectionEnd() const
250 {
251     return selectedTextRange().length;
252 }
253
254 void AccessibilityObject::setSelectedText(const String&)
255 {
256     // TODO: set selected text (ReplaceSelectionCommand). <rdar://problem/4712125>
257     notImplemented();
258 }
259
260 void AccessibilityObject::setSelectedTextRange(const PlainTextRange&)
261 {
262 }
263
264 void AccessibilityObject::makeRangeVisible(const PlainTextRange&)
265 {
266     // TODO: make range visible (scrollRectToVisible).  <rdar://problem/4712101>
267     notImplemented();
268 }
269
270 KURL AccessibilityObject::url() const
271 {
272     return KURL();
273 }
274
275 void AccessibilityObject::setFocused(bool)
276 {
277 }
278
279 void AccessibilityObject::setValue(const String&)
280 {
281 }
282
283 void AccessibilityObject::setSelected(bool)
284 {
285 }
286
287 bool AccessibilityObject::press() const
288 {
289     Element* actionElem = actionElement();
290     if (!actionElem)
291         return false;
292     if (Frame* f = actionElem->document()->frame())
293         f->loader()->resetMultipleFormSubmissionProtection();
294     actionElem->accessKeyAction(true);
295     return true;
296 }
297
298 AXObjectCache* AccessibilityObject::axObjectCache() const
299 {
300     return 0;
301 }
302
303 Widget* AccessibilityObject::widget() const
304 {
305     return 0;
306 }
307
308 Widget* AccessibilityObject::widgetForAttachmentView() const
309 {
310     return 0;
311 }
312
313 Element* AccessibilityObject::anchorElement() const
314 {
315     return 0;   
316 }
317
318 Element* AccessibilityObject::actionElement() const
319 {
320     return 0;
321 }
322
323 // This function is like a cross-platform version of - (WebCoreTextMarkerRange*)textMarkerRange. It returns
324 // a Range that we can convert to a WebCoreRange in the Obj-C file
325 VisiblePositionRange AccessibilityObject::visiblePositionRange() const
326 {
327     return VisiblePositionRange();
328 }
329
330 VisiblePositionRange AccessibilityObject::visiblePositionRangeForLine(unsigned) const
331 {
332     return VisiblePositionRange();
333 }
334
335 VisiblePosition AccessibilityObject::visiblePositionForIndex(int) const
336 {
337     return VisiblePosition();
338 }
339     
340 int AccessibilityObject::indexForVisiblePosition(const VisiblePosition&) const
341 {
342     return 0;
343 }
344     
345 VisiblePositionRange AccessibilityObject::visiblePositionRangeForUnorderedPositions(const VisiblePosition& visiblePos1, const VisiblePosition& visiblePos2) const
346 {
347     if (visiblePos1.isNull() || visiblePos2.isNull())
348         return VisiblePositionRange();
349
350     VisiblePosition startPos;
351     VisiblePosition endPos;
352     bool alreadyInOrder;
353
354     // upstream is ordered before downstream for the same position
355     if (visiblePos1 == visiblePos2 && visiblePos2.affinity() == UPSTREAM)
356         alreadyInOrder = false;
357
358     // use selection order to see if the positions are in order
359     else
360         alreadyInOrder = VisibleSelection(visiblePos1, visiblePos2).isBaseFirst();
361
362     if (alreadyInOrder) {
363         startPos = visiblePos1;
364         endPos = visiblePos2;
365     } else {
366         startPos = visiblePos2;
367         endPos = visiblePos1;
368     }
369
370     return VisiblePositionRange(startPos, endPos);
371 }
372
373 VisiblePositionRange AccessibilityObject::positionOfLeftWord(const VisiblePosition& visiblePos) const
374 {
375     VisiblePosition startPosition = startOfWord(visiblePos, LeftWordIfOnBoundary);
376     VisiblePosition endPosition = endOfWord(startPosition);
377     return VisiblePositionRange(startPosition, endPosition);
378 }
379
380 VisiblePositionRange AccessibilityObject::positionOfRightWord(const VisiblePosition& visiblePos) const
381 {
382     VisiblePosition startPosition = startOfWord(visiblePos, RightWordIfOnBoundary);
383     VisiblePosition endPosition = endOfWord(startPosition);
384     return VisiblePositionRange(startPosition, endPosition);
385 }
386
387 static VisiblePosition updateAXLineStartForVisiblePosition(const VisiblePosition& visiblePosition)
388 {
389     // A line in the accessibility sense should include floating objects, such as aligned image, as part of a line.
390     // So let's update the position to include that.
391     VisiblePosition tempPosition;
392     VisiblePosition startPosition = visiblePosition;
393     Position p;
394     RenderObject* renderer;
395     while (true) {
396         tempPosition = startPosition.previous();
397         if (tempPosition.isNull())
398             break;
399         p = tempPosition.deepEquivalent();
400         if (!p.node())
401             break;
402         renderer = p.node()->renderer();
403         if (!renderer || renderer->isRenderBlock() && !p.offset())
404             break;
405         InlineBox* box;
406         int ignoredCaretOffset;
407         p.getInlineBoxAndOffset(tempPosition.affinity(), box, ignoredCaretOffset);
408         if (box)
409             break;
410         startPosition = tempPosition;
411     }
412
413     return startPosition;
414 }
415
416 VisiblePositionRange AccessibilityObject::leftLineVisiblePositionRange(const VisiblePosition& visiblePos) const
417 {
418     if (visiblePos.isNull())
419         return VisiblePositionRange();
420
421     // make a caret selection for the position before marker position (to make sure
422     // we move off of a line start)
423     VisiblePosition prevVisiblePos = visiblePos.previous();
424     if (prevVisiblePos.isNull())
425         return VisiblePositionRange();
426
427     VisiblePosition startPosition = startOfLine(prevVisiblePos);
428
429     // keep searching for a valid line start position.  Unless the VisiblePosition is at the very beginning, there should
430     // always be a valid line range.  However, startOfLine will return null for position next to a floating object,
431     // since floating object doesn't really belong to any line.
432     // This check will reposition the marker before the floating object, to ensure we get a line start.
433     if (startPosition.isNull()) {
434         while (startPosition.isNull() && prevVisiblePos.isNotNull()) {
435             prevVisiblePos = prevVisiblePos.previous();
436             startPosition = startOfLine(prevVisiblePos);
437         }
438     } else
439         startPosition = updateAXLineStartForVisiblePosition(startPosition);
440
441     VisiblePosition endPosition = endOfLine(prevVisiblePos);
442     return VisiblePositionRange(startPosition, endPosition);
443 }
444
445 VisiblePositionRange AccessibilityObject::rightLineVisiblePositionRange(const VisiblePosition& visiblePos) const
446 {
447     if (visiblePos.isNull())
448         return VisiblePositionRange();
449
450     // make sure we move off of a line end
451     VisiblePosition nextVisiblePos = visiblePos.next();
452     if (nextVisiblePos.isNull())
453         return VisiblePositionRange();
454
455     VisiblePosition startPosition = startOfLine(nextVisiblePos);
456
457     // fetch for a valid line start position
458     if (startPosition.isNull() ) {
459         startPosition = visiblePos;
460         nextVisiblePos = nextVisiblePos.next();
461     } else
462         startPosition = updateAXLineStartForVisiblePosition(startPosition);
463
464     VisiblePosition endPosition = endOfLine(nextVisiblePos);
465
466     // as long as the position hasn't reached the end of the doc,  keep searching for a valid line end position
467     // Unless the VisiblePosition is at the very end, there should always be a valid line range.  However, endOfLine will
468     // return null for position by a floating object, since floating object doesn't really belong to any line.
469     // This check will reposition the marker after the floating object, to ensure we get a line end.
470     while (endPosition.isNull() && nextVisiblePos.isNotNull()) {
471         nextVisiblePos = nextVisiblePos.next();
472         endPosition = endOfLine(nextVisiblePos);
473     }
474
475     return VisiblePositionRange(startPosition, endPosition);
476 }
477
478 VisiblePositionRange AccessibilityObject::sentenceForPosition(const VisiblePosition& visiblePos) const
479 {
480     // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
481     // Related? <rdar://problem/3927736> Text selection broken in 8A336
482     VisiblePosition startPosition = startOfSentence(visiblePos);
483     VisiblePosition endPosition = endOfSentence(startPosition);
484     return VisiblePositionRange(startPosition, endPosition);
485 }
486
487 VisiblePositionRange AccessibilityObject::paragraphForPosition(const VisiblePosition& visiblePos) const
488 {
489     VisiblePosition startPosition = startOfParagraph(visiblePos);
490     VisiblePosition endPosition = endOfParagraph(startPosition);
491     return VisiblePositionRange(startPosition, endPosition);
492 }
493
494 static VisiblePosition startOfStyleRange(const VisiblePosition visiblePos)
495 {
496     RenderObject* renderer = visiblePos.deepEquivalent().node()->renderer();
497     RenderObject* startRenderer = renderer;
498     RenderStyle* style = renderer->style();
499
500     // traverse backward by renderer to look for style change
501     for (RenderObject* r = renderer->previousInPreOrder(); r; r = r->previousInPreOrder()) {
502         // skip non-leaf nodes
503         if (r->firstChild())
504             continue;
505
506         // stop at style change
507         if (r->style() != style)
508             break;
509
510         // remember match
511         startRenderer = r;
512     }
513
514     return VisiblePosition(startRenderer->node(), 0, VP_DEFAULT_AFFINITY);
515 }
516
517 static VisiblePosition endOfStyleRange(const VisiblePosition visiblePos)
518 {
519     RenderObject* renderer = visiblePos.deepEquivalent().node()->renderer();
520     RenderObject* endRenderer = renderer;
521     RenderStyle* style = renderer->style();
522
523     // traverse forward by renderer to look for style change
524     for (RenderObject* r = renderer->nextInPreOrder(); r; r = r->nextInPreOrder()) {
525         // skip non-leaf nodes
526         if (r->firstChild())
527             continue;
528
529         // stop at style change
530         if (r->style() != style)
531             break;
532
533         // remember match
534         endRenderer = r;
535     }
536
537     return VisiblePosition(endRenderer->node(), maxDeepOffset(endRenderer->node()), VP_DEFAULT_AFFINITY);
538 }
539
540 VisiblePositionRange AccessibilityObject::styleRangeForPosition(const VisiblePosition& visiblePos) const
541 {
542     if (visiblePos.isNull())
543         return VisiblePositionRange();
544
545     return VisiblePositionRange(startOfStyleRange(visiblePos), endOfStyleRange(visiblePos));
546 }
547
548 // NOTE: Consider providing this utility method as AX API
549 VisiblePositionRange AccessibilityObject::visiblePositionRangeForRange(const PlainTextRange& range) const
550 {
551     if (range.start + range.length > text().length())
552         return VisiblePositionRange();
553
554     VisiblePosition startPosition = visiblePositionForIndex(range.start);
555     startPosition.setAffinity(DOWNSTREAM);
556     VisiblePosition endPosition = visiblePositionForIndex(range.start + range.length);
557     return VisiblePositionRange(startPosition, endPosition);
558 }
559
560 static bool replacedNodeNeedsCharacter(Node* replacedNode)
561 {
562     // we should always be given a rendered node and a replaced node, but be safe
563     // replaced nodes are either attachments (widgets) or images
564     if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode()) {
565         return false;
566     }
567
568     // create an AX object, but skip it if it is not supposed to be seen
569     AccessibilityObject* object = replacedNode->renderer()->document()->axObjectCache()->get(replacedNode->renderer());
570     if (object->accessibilityIsIgnored())
571         return false;
572
573     return true;
574 }
575
576 String AccessibilityObject::stringForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const
577 {
578     if (visiblePositionRange.isNull())
579         return String();
580
581     Vector<UChar> resultVector;
582     RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end);
583     for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
584         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
585         if (it.length() != 0) {
586             resultVector.append(it.characters(), it.length());
587         } else {
588             // locate the node and starting offset for this replaced range
589             int exception = 0;
590             Node* node = it.range()->startContainer(exception);
591             ASSERT(node == it.range()->endContainer(exception));
592             int offset = it.range()->startOffset(exception);
593
594             if (replacedNodeNeedsCharacter(node->childNode(offset))) {
595                 resultVector.append(objectReplacementCharacter);
596             }
597         }
598     }
599
600     return String::adopt(resultVector);
601 }
602
603 IntRect AccessibilityObject::boundsForVisiblePositionRange(const VisiblePositionRange&) const
604 {
605     return IntRect();
606 }
607
608 int AccessibilityObject::lengthForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const
609 {
610     // FIXME: Multi-byte support
611     if (visiblePositionRange.isNull())
612         return -1;
613     
614     int length = 0;
615     RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end);
616     for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
617         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
618         if (it.length() != 0) {
619             length += it.length();
620         } else {
621             // locate the node and starting offset for this replaced range
622             int exception = 0;
623             Node* node = it.range()->startContainer(exception);
624             ASSERT(node == it.range()->endContainer(exception));
625             int offset = it.range()->startOffset(exception);
626
627             if (replacedNodeNeedsCharacter(node->childNode(offset)))
628                 length++;
629         }
630     }
631     
632     return length;
633 }
634
635 void AccessibilityObject::setSelectedVisiblePositionRange(const VisiblePositionRange&) const
636 {
637 }
638
639 VisiblePosition AccessibilityObject::visiblePositionForPoint(const IntPoint&) const
640 {
641     return VisiblePosition();
642 }
643
644 VisiblePosition AccessibilityObject::nextVisiblePosition(const VisiblePosition& visiblePos) const
645 {
646     return visiblePos.next();
647 }
648
649 VisiblePosition AccessibilityObject::previousVisiblePosition(const VisiblePosition& visiblePos) const
650 {
651     return visiblePos.previous();
652 }
653
654 VisiblePosition AccessibilityObject::nextWordEnd(const VisiblePosition& visiblePos) const
655 {
656     if (visiblePos.isNull())
657         return VisiblePosition();
658
659     // make sure we move off of a word end
660     VisiblePosition nextVisiblePos = visiblePos.next();
661     if (nextVisiblePos.isNull())
662         return VisiblePosition();
663
664     return endOfWord(nextVisiblePos, LeftWordIfOnBoundary);
665 }
666
667 VisiblePosition AccessibilityObject::previousWordStart(const VisiblePosition& visiblePos) const
668 {
669     if (visiblePos.isNull())
670         return VisiblePosition();
671
672     // make sure we move off of a word start
673     VisiblePosition prevVisiblePos = visiblePos.previous();
674     if (prevVisiblePos.isNull())
675         return VisiblePosition();
676
677     return startOfWord(prevVisiblePos, RightWordIfOnBoundary);
678 }
679
680 VisiblePosition AccessibilityObject::nextLineEndPosition(const VisiblePosition& visiblePos) const
681 {
682     if (visiblePos.isNull())
683         return VisiblePosition();
684
685     // to make sure we move off of a line end
686     VisiblePosition nextVisiblePos = visiblePos.next();
687     if (nextVisiblePos.isNull())
688         return VisiblePosition();
689
690     VisiblePosition endPosition = endOfLine(nextVisiblePos);
691
692     // as long as the position hasn't reached the end of the doc,  keep searching for a valid line end position
693     // 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.
694     while (endPosition.isNull() && nextVisiblePos.isNotNull()) {
695         nextVisiblePos = nextVisiblePos.next();
696         endPosition = endOfLine(nextVisiblePos);
697     }
698
699     return endPosition;
700 }
701
702 VisiblePosition AccessibilityObject::previousLineStartPosition(const VisiblePosition& visiblePos) const
703 {
704     if (visiblePos.isNull())
705         return VisiblePosition();
706
707     // make sure we move off of a line start
708     VisiblePosition prevVisiblePos = visiblePos.previous();
709     if (prevVisiblePos.isNull())
710         return VisiblePosition();
711
712     VisiblePosition startPosition = startOfLine(prevVisiblePos);
713
714     // as long as the position hasn't reached the beginning of the doc,  keep searching for a valid line start position
715     // 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.
716     if (startPosition.isNull()) {
717         while (startPosition.isNull() && prevVisiblePos.isNotNull()) {
718             prevVisiblePos = prevVisiblePos.previous();
719             startPosition = startOfLine(prevVisiblePos);
720         }
721     } else
722         startPosition = updateAXLineStartForVisiblePosition(startPosition);
723
724     return startPosition;
725 }
726
727 VisiblePosition AccessibilityObject::nextSentenceEndPosition(const VisiblePosition& visiblePos) const
728 {
729     // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
730     // Related? <rdar://problem/3927736> Text selection broken in 8A336
731     if (visiblePos.isNull())
732         return VisiblePosition();
733
734     // make sure we move off of a sentence end
735     VisiblePosition nextVisiblePos = visiblePos.next();
736     if (nextVisiblePos.isNull())
737         return VisiblePosition();
738
739     // an empty line is considered a sentence. If it's skipped, then the sentence parser will not
740     // see this empty line.  Instead, return the end position of the empty line.
741     VisiblePosition endPosition;
742     
743     String lineString = plainText(makeRange(startOfLine(nextVisiblePos), endOfLine(nextVisiblePos)).get());
744     if (lineString.isEmpty())
745         endPosition = nextVisiblePos;
746     else
747         endPosition = endOfSentence(nextVisiblePos);
748
749     return endPosition;
750 }
751
752 VisiblePosition AccessibilityObject::previousSentenceStartPosition(const VisiblePosition& visiblePos) const
753 {
754     // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
755     // Related? <rdar://problem/3927736> Text selection broken in 8A336
756     if (visiblePos.isNull())
757         return VisiblePosition();
758
759     // make sure we move off of a sentence start
760     VisiblePosition previousVisiblePos = visiblePos.previous();
761     if (previousVisiblePos.isNull())
762         return VisiblePosition();
763
764     // treat empty line as a separate sentence.
765     VisiblePosition startPosition;
766     
767     String lineString = plainText(makeRange(startOfLine(previousVisiblePos), endOfLine(previousVisiblePos)).get());
768     if (lineString.isEmpty())
769         startPosition = previousVisiblePos;
770     else
771         startPosition = startOfSentence(previousVisiblePos);
772
773     return startPosition;
774 }
775
776 VisiblePosition AccessibilityObject::nextParagraphEndPosition(const VisiblePosition& visiblePos) const
777 {
778     if (visiblePos.isNull())
779         return VisiblePosition();
780
781     // make sure we move off of a paragraph end
782     VisiblePosition nextPos = visiblePos.next();
783     if (nextPos.isNull())
784         return VisiblePosition();
785
786     return endOfParagraph(nextPos);
787 }
788
789 VisiblePosition AccessibilityObject::previousParagraphStartPosition(const VisiblePosition& visiblePos) const
790 {
791     if (visiblePos.isNull())
792         return VisiblePosition();
793
794     // make sure we move off of a paragraph start
795     VisiblePosition previousPos = visiblePos.previous();
796     if (previousPos.isNull())
797         return VisiblePosition();
798
799     return startOfParagraph(previousPos);
800 }
801
802 // NOTE: Consider providing this utility method as AX API
803 VisiblePosition AccessibilityObject::visiblePositionForIndex(unsigned, bool) const
804 {
805     return VisiblePosition();
806 }
807
808 AccessibilityObject* AccessibilityObject::accessibilityObjectForPosition(const VisiblePosition& visiblePos) const
809 {
810     if (visiblePos.isNull())
811         return 0;
812
813     RenderObject* obj = visiblePos.deepEquivalent().node()->renderer();
814     if (!obj)
815         return 0;
816
817     return obj->document()->axObjectCache()->get(obj);
818 }
819
820 int AccessibilityObject::lineForPosition(const VisiblePosition& visiblePos) const
821 {
822     if (visiblePos.isNull())
823         return 0;
824
825     unsigned lineCount = 0;
826     VisiblePosition currentVisiblePos = visiblePos;
827     VisiblePosition savedVisiblePos;
828
829     // move up until we get to the top
830     // FIXME: This only takes us to the top of the rootEditableElement, not the top of the
831     // top document.
832     while (currentVisiblePos.isNotNull() && !(inSameLine(currentVisiblePos, savedVisiblePos))) {
833         ++lineCount;
834         savedVisiblePos = currentVisiblePos;
835         VisiblePosition prevVisiblePos = previousLinePosition(currentVisiblePos, 0);
836         currentVisiblePos = prevVisiblePos;
837     }
838
839     return lineCount - 1;
840 }
841
842 // NOTE: Consider providing this utility method as AX API
843 PlainTextRange AccessibilityObject::plainTextRangeForVisiblePositionRange(const VisiblePositionRange& positionRange) const
844 {
845     int index1 = index(positionRange.start);
846     int index2 = index(positionRange.end);
847     if (index1 < 0 || index2 < 0 || index1 > index2)
848         return PlainTextRange();
849
850     return PlainTextRange(index1, index2 - index1);
851 }
852
853 // NOTE: Consider providing this utility method as AX API
854 int AccessibilityObject::index(const VisiblePosition&) const
855 {
856     return -1;
857 }
858
859 // Given a line number, the range of characters of the text associated with this accessibility
860 // object that contains the line number.
861 PlainTextRange AccessibilityObject::doAXRangeForLine(unsigned) const
862 {
863     return PlainTextRange();
864 }
865
866 // The composed character range in the text associated with this accessibility object that
867 // is specified by the given screen coordinates. This parameterized attribute returns the
868 // complete range of characters (including surrogate pairs of multi-byte glyphs) at the given
869 // screen coordinates.
870 // NOTE: This varies from AppKit when the point is below the last line. AppKit returns an
871 // an error in that case. We return textControl->text().length(), 1. Does this matter?
872 PlainTextRange AccessibilityObject::doAXRangeForPosition(const IntPoint& point) const
873 {
874     int i = index(visiblePositionForPoint(point));
875     if (i < 0)
876         return PlainTextRange();
877
878     return PlainTextRange(i, 1);
879 }
880
881 // The composed character range in the text associated with this accessibility object that
882 // is specified by the given index value. This parameterized attribute returns the complete
883 // range of characters (including surrogate pairs of multi-byte glyphs) at the given index.
884 PlainTextRange AccessibilityObject::doAXRangeForIndex(unsigned) const
885 {
886     return PlainTextRange();
887 }
888
889 // Given a character index, the range of text associated with this accessibility object
890 // over which the style in effect at that character index applies.
891 PlainTextRange AccessibilityObject::doAXStyleRangeForIndex(unsigned index) const
892 {
893     VisiblePositionRange range = styleRangeForPosition(visiblePositionForIndex(index, false));
894     return plainTextRangeForVisiblePositionRange(range);
895 }
896
897 // A substring of the text associated with this accessibility object that is
898 // specified by the given character range.
899 String AccessibilityObject::doAXStringForRange(const PlainTextRange&) const
900 {
901     return String();
902 }
903
904 // The bounding rectangle of the text associated with this accessibility object that is
905 // specified by the given range. This is the bounding rectangle a sighted user would see
906 // on the display screen, in pixels.
907 IntRect AccessibilityObject::doAXBoundsForRange(const PlainTextRange&) const
908 {
909     return IntRect();
910 }
911
912 // Given an indexed character, the line number of the text associated with this accessibility
913 // object that contains the character.
914 unsigned AccessibilityObject::doAXLineForIndex(unsigned index)
915 {
916     return lineForPosition(visiblePositionForIndex(index, false));
917 }
918
919 FrameView* AccessibilityObject::documentFrameView() const 
920
921     const AccessibilityObject* object = this;
922     while (object && !object->isAccessibilityRenderObject()) 
923         object = object->parentObject();
924         
925     if (!object)
926         return 0;
927
928     return object->documentFrameView();
929 }    
930
931 AccessibilityObject* AccessibilityObject::doAccessibilityHitTest(const IntPoint&) const
932 {
933     return 0;
934 }
935
936 AccessibilityObject* AccessibilityObject::focusedUIElement() const
937 {
938     return 0;
939 }
940
941 AccessibilityObject* AccessibilityObject::observableObject() const
942 {
943     return 0;
944 }
945
946 AccessibilityRole AccessibilityObject::roleValue() const
947 {
948     return UnknownRole;
949 }
950     
951 AccessibilityRole AccessibilityObject::ariaRoleAttribute() const
952 {
953     return UnknownRole;
954 }
955
956 bool AccessibilityObject::isPresentationalChildOfAriaRole() const
957 {
958     return false;
959 }
960
961 bool AccessibilityObject::ariaRoleHasPresentationalChildren() const
962 {
963     return false;
964 }
965
966 void AccessibilityObject::clearChildren()
967 {
968     m_haveChildren = false;
969     m_children.clear();
970 }
971
972 void AccessibilityObject::childrenChanged()
973 {
974     return;
975 }
976
977 void AccessibilityObject::addChildren()
978 {
979 }
980
981 void AccessibilityObject::selectedChildren(AccessibilityChildrenVector&)
982 {
983 }
984
985 void AccessibilityObject::visibleChildren(AccessibilityChildrenVector&)
986 {
987 }
988     
989 unsigned AccessibilityObject::axObjectID() const
990 {
991     return m_id;
992 }
993
994 void AccessibilityObject::setAXObjectID(unsigned axObjectID)
995 {
996     m_id = axObjectID;
997 }
998
999 void AccessibilityObject::removeAXObjectID()
1000 {
1001     return;
1002 }
1003
1004 const String& AccessibilityObject::actionVerb() const
1005 {
1006     // FIXME: Need to add verbs for select elements.
1007     DEFINE_STATIC_LOCAL(const String, buttonAction, (AXButtonActionVerb()));
1008     DEFINE_STATIC_LOCAL(const String, textFieldAction, (AXTextFieldActionVerb()));
1009     DEFINE_STATIC_LOCAL(const String, radioButtonAction, (AXRadioButtonActionVerb()));
1010     DEFINE_STATIC_LOCAL(const String, checkedCheckBoxAction, (AXCheckedCheckBoxActionVerb()));
1011     DEFINE_STATIC_LOCAL(const String, uncheckedCheckBoxAction, (AXUncheckedCheckBoxActionVerb()));
1012     DEFINE_STATIC_LOCAL(const String, linkAction, (AXLinkActionVerb()));
1013     DEFINE_STATIC_LOCAL(const String, noAction, ());
1014
1015     switch (roleValue()) {
1016         case ButtonRole:
1017             return buttonAction;
1018         case TextFieldRole:
1019         case TextAreaRole:
1020             return textFieldAction;
1021         case RadioButtonRole:
1022             return radioButtonAction;
1023         case CheckBoxRole:
1024             return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction;
1025         case LinkRole:
1026         case WebCoreLinkRole:
1027             return linkAction;
1028         default:
1029             return noAction;
1030     }
1031 }
1032
1033 void AccessibilityObject::updateBackingStore()
1034 {
1035 }
1036     
1037 } // namespace WebCore