• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
AccessibilityObject()62 AccessibilityObject::AccessibilityObject()
63     : m_id(0)
64     , m_haveChildren(false)
65 #if PLATFORM(GTK)
66     , m_wrapper(0)
67 #endif
68 {
69 }
70 
~AccessibilityObject()71 AccessibilityObject::~AccessibilityObject()
72 {
73     ASSERT(isDetached());
74 }
75 
detach()76 void AccessibilityObject::detach()
77 {
78     removeAXObjectID();
79 #if HAVE(ACCESSIBILITY)
80     setWrapper(0);
81 #endif
82 }
83 
firstChild() const84 AccessibilityObject* AccessibilityObject::firstChild() const
85 {
86     return 0;
87 }
88 
lastChild() const89 AccessibilityObject* AccessibilityObject::lastChild() const
90 {
91     return 0;
92 }
93 
previousSibling() const94 AccessibilityObject* AccessibilityObject::previousSibling() const
95 {
96     return 0;
97 }
98 
nextSibling() const99 AccessibilityObject* AccessibilityObject::nextSibling() const
100 {
101     return 0;
102 }
103 
parentObject() const104 AccessibilityObject* AccessibilityObject::parentObject() const
105 {
106     return 0;
107 }
108 
parentObjectUnignored() const109 AccessibilityObject* AccessibilityObject::parentObjectUnignored() const
110 {
111     AccessibilityObject* parent;
112     for (parent = parentObject(); parent && parent->accessibilityIsIgnored(); parent = parent->parentObject())
113         ;
114     return parent;
115 }
116 
layoutCount() const117 int AccessibilityObject::layoutCount() const
118 {
119     return 0;
120 }
121 
text() const122 String AccessibilityObject::text() const
123 {
124     return String();
125 }
126 
helpText() const127 String AccessibilityObject::helpText() const
128 {
129     return String();
130 }
131 
textUnderElement() const132 String AccessibilityObject::textUnderElement() const
133 {
134     return String();
135 }
136 
isARIAInput(AccessibilityRole ariaRole)137 bool AccessibilityObject::isARIAInput(AccessibilityRole ariaRole)
138 {
139     return ariaRole == RadioButtonRole || ariaRole == CheckBoxRole || ariaRole == TextFieldRole;
140 }
141 
isARIAControl(AccessibilityRole ariaRole)142 bool AccessibilityObject::isARIAControl(AccessibilityRole ariaRole)
143 {
144     return isARIAInput(ariaRole) || ariaRole == TextAreaRole || ariaRole == ButtonRole
145     || ariaRole == ComboBoxRole || ariaRole == SliderRole;
146 }
147 
intValue() const148 int AccessibilityObject::intValue() const
149 {
150     return 0;
151 }
152 
stringValue() const153 String AccessibilityObject::stringValue() const
154 {
155     return String();
156 }
157 
ariaAccessiblityName(const String &) const158 String AccessibilityObject::ariaAccessiblityName(const String&) const
159 {
160     return String();
161 }
162 
ariaLabeledByAttribute() const163 String AccessibilityObject::ariaLabeledByAttribute() const
164 {
165     return String();
166 }
167 
title() const168 String AccessibilityObject::title() const
169 {
170     return String();
171 }
172 
ariaDescribedByAttribute() const173 String AccessibilityObject::ariaDescribedByAttribute() const
174 {
175     return String();
176 }
177 
accessibilityDescription() const178 String AccessibilityObject::accessibilityDescription() const
179 {
180     return String();
181 }
182 
boundingBoxRect() const183 IntRect AccessibilityObject::boundingBoxRect() const
184 {
185     return IntRect();
186 }
187 
elementRect() const188 IntRect AccessibilityObject::elementRect() const
189 {
190     return IntRect();
191 }
192 
size() const193 IntSize AccessibilityObject::size() const
194 {
195     return IntSize();
196 }
197 
clickPoint() const198 IntPoint AccessibilityObject::clickPoint() const
199 {
200     IntRect rect = elementRect();
201     return IntPoint(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2);
202 }
203 
linkedUIElements(AccessibilityChildrenVector &) const204 void AccessibilityObject::linkedUIElements(AccessibilityChildrenVector&) const
205 {
206     return;
207 }
208 
titleUIElement() const209 AccessibilityObject* AccessibilityObject::titleUIElement() const
210 {
211      return 0;
212 }
213 
textLength() const214 int AccessibilityObject::textLength() const
215 {
216     return 0;
217 }
218 
ariaSelectedTextDOMRange() const219 PassRefPtr<Range> AccessibilityObject::ariaSelectedTextDOMRange() const
220 {
221     return 0;
222 }
223 
selectedText() const224 String AccessibilityObject::selectedText() const
225 {
226     return String();
227 }
228 
accessKey() const229 const AtomicString& AccessibilityObject::accessKey() const
230 {
231     return nullAtom;
232 }
233 
selection() const234 Selection AccessibilityObject::selection() const
235 {
236     return Selection();
237 }
238 
selectedTextRange() const239 PlainTextRange AccessibilityObject::selectedTextRange() const
240 {
241     return PlainTextRange();
242 }
243 
selectionStart() const244 unsigned AccessibilityObject::selectionStart() const
245 {
246     return selectedTextRange().start;
247 }
248 
selectionEnd() const249 unsigned AccessibilityObject::selectionEnd() const
250 {
251     return selectedTextRange().length;
252 }
253 
setSelectedText(const String &)254 void AccessibilityObject::setSelectedText(const String&)
255 {
256     // TODO: set selected text (ReplaceSelectionCommand). <rdar://problem/4712125>
257     notImplemented();
258 }
259 
setSelectedTextRange(const PlainTextRange &)260 void AccessibilityObject::setSelectedTextRange(const PlainTextRange&)
261 {
262 }
263 
makeRangeVisible(const PlainTextRange &)264 void AccessibilityObject::makeRangeVisible(const PlainTextRange&)
265 {
266     // TODO: make range visible (scrollRectToVisible).  <rdar://problem/4712101>
267     notImplemented();
268 }
269 
url() const270 KURL AccessibilityObject::url() const
271 {
272     return KURL();
273 }
274 
setFocused(bool)275 void AccessibilityObject::setFocused(bool)
276 {
277 }
278 
setValue(const String &)279 void AccessibilityObject::setValue(const String&)
280 {
281 }
282 
setSelected(bool)283 void AccessibilityObject::setSelected(bool)
284 {
285 }
286 
press() const287 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 
axObjectCache() const298 AXObjectCache* AccessibilityObject::axObjectCache() const
299 {
300     return 0;
301 }
302 
widget() const303 Widget* AccessibilityObject::widget() const
304 {
305     return 0;
306 }
307 
widgetForAttachmentView() const308 Widget* AccessibilityObject::widgetForAttachmentView() const
309 {
310     return 0;
311 }
312 
anchorElement() const313 Element* AccessibilityObject::anchorElement() const
314 {
315     return 0;
316 }
317 
actionElement() const318 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
visiblePositionRange() const325 VisiblePositionRange AccessibilityObject::visiblePositionRange() const
326 {
327     return VisiblePositionRange();
328 }
329 
visiblePositionRangeForLine(unsigned) const330 VisiblePositionRange AccessibilityObject::visiblePositionRangeForLine(unsigned) const
331 {
332     return VisiblePositionRange();
333 }
334 
visiblePositionForIndex(int) const335 VisiblePosition AccessibilityObject::visiblePositionForIndex(int) const
336 {
337     return VisiblePosition();
338 }
339 
indexForVisiblePosition(const VisiblePosition &) const340 int AccessibilityObject::indexForVisiblePosition(const VisiblePosition&) const
341 {
342     return 0;
343 }
344 
visiblePositionRangeForUnorderedPositions(const VisiblePosition & visiblePos1,const VisiblePosition & visiblePos2) const345 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 = Selection(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 
positionOfLeftWord(const VisiblePosition & visiblePos) const373 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 
positionOfRightWord(const VisiblePosition & visiblePos) const380 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 
updateAXLineStartForVisiblePosition(const VisiblePosition & visiblePosition)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 
leftLineVisiblePositionRange(const VisiblePosition & visiblePos) const416 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 
rightLineVisiblePositionRange(const VisiblePosition & visiblePos) const445 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 
sentenceForPosition(const VisiblePosition & visiblePos) const478 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 
paragraphForPosition(const VisiblePosition & visiblePos) const487 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 
startOfStyleRange(const VisiblePosition visiblePos)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 
endOfStyleRange(const VisiblePosition visiblePos)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 
styleRangeForPosition(const VisiblePosition & visiblePos) const540 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
visiblePositionRangeForRange(const PlainTextRange & range) const549 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 
replacedNodeNeedsCharacter(Node * replacedNode)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 
stringForVisiblePositionRange(const VisiblePositionRange & visiblePositionRange) const576 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 
boundsForVisiblePositionRange(const VisiblePositionRange &) const603 IntRect AccessibilityObject::boundsForVisiblePositionRange(const VisiblePositionRange&) const
604 {
605     return IntRect();
606 }
607 
lengthForVisiblePositionRange(const VisiblePositionRange & visiblePositionRange) const608 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 
setSelectedVisiblePositionRange(const VisiblePositionRange &) const635 void AccessibilityObject::setSelectedVisiblePositionRange(const VisiblePositionRange&) const
636 {
637 }
638 
visiblePositionForPoint(const IntPoint &) const639 VisiblePosition AccessibilityObject::visiblePositionForPoint(const IntPoint&) const
640 {
641     return VisiblePosition();
642 }
643 
nextVisiblePosition(const VisiblePosition & visiblePos) const644 VisiblePosition AccessibilityObject::nextVisiblePosition(const VisiblePosition& visiblePos) const
645 {
646     return visiblePos.next();
647 }
648 
previousVisiblePosition(const VisiblePosition & visiblePos) const649 VisiblePosition AccessibilityObject::previousVisiblePosition(const VisiblePosition& visiblePos) const
650 {
651     return visiblePos.previous();
652 }
653 
nextWordEnd(const VisiblePosition & visiblePos) const654 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 
previousWordStart(const VisiblePosition & visiblePos) const667 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 
nextLineEndPosition(const VisiblePosition & visiblePos) const680 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 
previousLineStartPosition(const VisiblePosition & visiblePos) const702 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 
nextSentenceEndPosition(const VisiblePosition & visiblePos) const727 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 
previousSentenceStartPosition(const VisiblePosition & visiblePos) const752 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 
nextParagraphEndPosition(const VisiblePosition & visiblePos) const776 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 
previousParagraphStartPosition(const VisiblePosition & visiblePos) const789 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
visiblePositionForIndex(unsigned,bool) const803 VisiblePosition AccessibilityObject::visiblePositionForIndex(unsigned, bool) const
804 {
805     return VisiblePosition();
806 }
807 
accessibilityObjectForPosition(const VisiblePosition & visiblePos) const808 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 
lineForPosition(const VisiblePosition & visiblePos) const820 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
plainTextRangeForVisiblePositionRange(const VisiblePositionRange & positionRange) const843 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
index(const VisiblePosition &) const854 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.
doAXRangeForLine(unsigned) const861 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?
doAXRangeForPosition(const IntPoint & point) const872 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.
doAXRangeForIndex(unsigned) const884 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.
doAXStyleRangeForIndex(unsigned index) const891 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.
doAXStringForRange(const PlainTextRange &) const899 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.
doAXBoundsForRange(const PlainTextRange &) const907 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.
doAXLineForIndex(unsigned index)914 unsigned AccessibilityObject::doAXLineForIndex(unsigned index)
915 {
916     return lineForPosition(visiblePositionForIndex(index, false));
917 }
918 
documentFrameView() const919 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 
doAccessibilityHitTest(const IntPoint &) const931 AccessibilityObject* AccessibilityObject::doAccessibilityHitTest(const IntPoint&) const
932 {
933     return 0;
934 }
935 
focusedUIElement() const936 AccessibilityObject* AccessibilityObject::focusedUIElement() const
937 {
938     return 0;
939 }
940 
observableObject() const941 AccessibilityObject* AccessibilityObject::observableObject() const
942 {
943     return 0;
944 }
945 
roleValue() const946 AccessibilityRole AccessibilityObject::roleValue() const
947 {
948     return UnknownRole;
949 }
950 
ariaRoleAttribute() const951 AccessibilityRole AccessibilityObject::ariaRoleAttribute() const
952 {
953     return UnknownRole;
954 }
955 
isPresentationalChildOfAriaRole() const956 bool AccessibilityObject::isPresentationalChildOfAriaRole() const
957 {
958     return false;
959 }
960 
ariaRoleHasPresentationalChildren() const961 bool AccessibilityObject::ariaRoleHasPresentationalChildren() const
962 {
963     return false;
964 }
965 
clearChildren()966 void AccessibilityObject::clearChildren()
967 {
968     m_haveChildren = false;
969     m_children.clear();
970 }
971 
childrenChanged()972 void AccessibilityObject::childrenChanged()
973 {
974     return;
975 }
976 
addChildren()977 void AccessibilityObject::addChildren()
978 {
979 }
980 
selectedChildren(AccessibilityChildrenVector &)981 void AccessibilityObject::selectedChildren(AccessibilityChildrenVector&)
982 {
983 }
984 
visibleChildren(AccessibilityChildrenVector &)985 void AccessibilityObject::visibleChildren(AccessibilityChildrenVector&)
986 {
987 }
988 
axObjectID() const989 unsigned AccessibilityObject::axObjectID() const
990 {
991     return m_id;
992 }
993 
setAXObjectID(unsigned axObjectID)994 void AccessibilityObject::setAXObjectID(unsigned axObjectID)
995 {
996     m_id = axObjectID;
997 }
998 
removeAXObjectID()999 void AccessibilityObject::removeAXObjectID()
1000 {
1001     return;
1002 }
1003 
actionVerb() const1004 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 
updateBackingStore()1033 void AccessibilityObject::updateBackingStore()
1034 {
1035 }
1036 
1037 } // namespace WebCore
1038