4aaa537535dd73b5145e262efa8ff88835ee901f
[WebKit-https.git] / Source / WebKitLegacy / win / AccessibleTextImpl.cpp
1 /*
2  * Copyright (C) 2013 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES LOSS OF USE, DATA, OR
20  * PROFITS OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "AccessibleTextImpl.h"
27
28 #include "WebKitDLL.h"
29 #include "WebView.h"
30
31 #include <WebCore/Document.h>
32 #include <WebCore/Editing.h>
33 #include <WebCore/Editor.h>
34 #include <WebCore/Frame.h>
35 #include <WebCore/FrameSelection.h>
36 #include <WebCore/HTMLTextFormControlElement.h>
37 #include <WebCore/Node.h>
38 #include <WebCore/Position.h>
39 #include <WebCore/RenderTextControl.h>
40 #include <WebCore/VisibleSelection.h>
41 #include <WebCore/VisibleUnits.h>
42
43 using namespace WebCore;
44
45 AccessibleText::AccessibleText(WebCore::AccessibilityObject* obj, HWND window)
46     : AccessibleBase(obj, window)
47 {
48     ASSERT_ARG(obj, obj->isStaticText() || obj->isTextControl() || (obj->node() && obj->node()->isTextNode()));
49     ASSERT_ARG(obj, obj->isAccessibilityRenderObject());
50 }
51
52 // IAccessibleText
53 HRESULT AccessibleText::addSelection(long startOffset, long endOffset)
54 {
55     if (initialCheck() == E_POINTER)
56         return E_POINTER;
57
58     startOffset = convertSpecialOffset(startOffset);
59     endOffset = convertSpecialOffset(endOffset);
60
61     m_object->setSelectedTextRange(PlainTextRange(startOffset, endOffset-startOffset));
62     
63     return S_OK;
64 }
65
66 HRESULT AccessibleText::get_attributes(long offset, long* startOffset, long* endOffset, BSTR* textAttributes)
67 {
68     if (initialCheck() == E_POINTER)
69         return E_POINTER;
70
71     offset = convertSpecialOffset(offset);
72
73     return E_NOTIMPL;
74 }
75
76 HRESULT AccessibleText::get_caretOffset(long* offset)
77 {
78     if (initialCheck() == E_POINTER)
79         return E_POINTER;
80
81     VisiblePosition caretPosition = m_object->visiblePositionForPoint(m_object->document()->frame()->selection().absoluteCaretBounds().center());
82
83     int caretOffset = caretPosition.deepEquivalent().offsetInContainerNode();
84     if (caretOffset < 0)
85         return E_FAIL;
86     *offset = caretOffset;
87     return S_OK;
88 }
89
90 HRESULT AccessibleText::get_characterExtents(long offset, enum IA2CoordinateType coordType, long* x, long* y, long* width, long* height)
91 {
92     if (initialCheck() == E_POINTER)
93         return E_POINTER;
94
95     offset = convertSpecialOffset(offset);
96
97     Node* node = m_object->node();
98     if (!node)
99         return E_POINTER;
100
101     IntRect boundingRect = m_object->boundsForVisiblePositionRange(VisiblePositionRange(VisiblePosition(Position(node, offset, Position::PositionIsOffsetInAnchor)), VisiblePosition(Position(node, offset+1, Position::PositionIsOffsetInAnchor))));
102     *width = boundingRect.width();
103     *height = boundingRect.height();
104     switch (coordType) {
105     case IA2_COORDTYPE_SCREEN_RELATIVE:
106         POINT points[1];
107         points[0].x = boundingRect.x();
108         points[0].y = boundingRect.y();
109         MapWindowPoints(m_window, 0, points, 1);
110         *x = points[0].x;
111         *y = points[0].y;
112         break;
113     case IA2_COORDTYPE_PARENT_RELATIVE:
114         *x = boundingRect.x();
115         *y = boundingRect.y();
116         break;
117     default:
118         return E_INVALIDARG;
119     }
120
121     return S_OK;
122 }
123
124 HRESULT AccessibleText::get_nSelections(long* nSelections)
125 {
126     if (initialCheck() == E_POINTER)
127         return E_POINTER;
128
129     if (m_object->document()->frame()->selection().isNone())
130         *nSelections = 0;
131     else
132         *nSelections = 1;
133     return S_OK;
134 }
135
136 HRESULT AccessibleText::get_offsetAtPoint(long x, long y, enum IA2CoordinateType coordType, long* offset)
137 {
138     if (initialCheck() == E_POINTER)
139         return E_POINTER;
140
141     Node* node = m_object->node();
142     if (!node)
143         return E_POINTER;
144
145     VisiblePosition vpos;
146     switch (coordType) {
147     case IA2_COORDTYPE_SCREEN_RELATIVE:
148         POINT points[1];
149         points[0].x = x;
150         points[0].y = y;
151         MapWindowPoints(0, m_window, points, 1);
152         vpos = m_object->visiblePositionForPoint(IntPoint(points[0].x, points[0].y));
153         break;
154     case IA2_COORDTYPE_PARENT_RELATIVE:
155         vpos = m_object->visiblePositionForPoint(IntPoint(x, y));
156         break;
157     default:
158         return E_INVALIDARG;
159     }
160
161     int caretPosition = vpos.deepEquivalent().offsetInContainerNode();
162     if (caretPosition < 0 || caretPosition > m_object->stringValue().length())
163         return S_FALSE; 
164     return S_OK;
165 }
166
167 HRESULT AccessibleText::get_selection(long selectionIndex, long* startOffset, long* endOffset)
168 {
169     if (initialCheck() == E_POINTER)
170         return E_POINTER;
171
172     long selections;
173     get_nSelections(&selections);
174     if (selectionIndex < 0 || selectionIndex >= selections)
175         return E_INVALIDARG;
176
177     PlainTextRange selectionRange = m_object->selectedTextRange();
178
179     *startOffset = selectionRange.start;
180     *endOffset = selectionRange.length;
181     return S_OK;
182 }
183
184 HRESULT AccessibleText::get_text(long startOffset, long endOffset, BSTR* text)
185 {
186     if (initialCheck() == E_POINTER)
187         return E_POINTER;
188
189     startOffset = convertSpecialOffset(startOffset);
190     endOffset = convertSpecialOffset(endOffset);
191     WTF::String substringText = m_object->stringValue().substring(startOffset, endOffset - startOffset);
192
193     *text = BString(substringText).release();
194     if (substringText.length() && !*text)
195         return E_OUTOFMEMORY;
196
197     return S_OK;
198 }
199
200 HRESULT AccessibleText::get_textBeforeOffset(long offset, enum IA2TextBoundaryType boundaryType, long* startOffset, long* endOffset, BSTR* text)
201 {
202     if (initialCheck() == E_POINTER)
203         return E_POINTER;
204
205     if (!startOffset || !endOffset || !text)
206         return E_POINTER;
207     
208     offset = convertSpecialOffset(offset);
209
210     if (offset < 0 || offset > m_object->stringValue().length())
211         return E_INVALIDARG;
212
213     // Obtain the desired text range
214     VisiblePosition currentPosition = m_object->visiblePositionForIndex(offset);
215     VisiblePositionRange textRange;
216     int previousPos = std::max(0, static_cast<int>(offset-1));
217     switch (boundaryType) {
218     case IA2_TEXT_BOUNDARY_CHAR:
219         textRange = m_object->visiblePositionRangeForRange(PlainTextRange(previousPos, 1));
220         break;
221     case IA2_TEXT_BOUNDARY_WORD:
222         textRange = m_object->positionOfLeftWord(currentPosition);
223         textRange = m_object->positionOfRightWord(leftWordPosition(textRange.start, true));
224         break;
225     case IA2_TEXT_BOUNDARY_SENTENCE:
226         textRange.start = m_object->previousSentenceStartPosition(currentPosition);
227         textRange = m_object->sentenceForPosition(textRange.start);
228         if (isInRange(currentPosition, textRange))
229             textRange = m_object->sentenceForPosition(m_object->previousSentenceStartPosition(textRange.start.previous()));
230         break;
231     case IA2_TEXT_BOUNDARY_PARAGRAPH:
232         textRange.start = m_object->previousParagraphStartPosition(currentPosition);
233         textRange = m_object->paragraphForPosition(textRange.start);
234         if (isInRange(currentPosition, textRange))
235             textRange = m_object->paragraphForPosition(m_object->previousParagraphStartPosition(textRange.start.previous()));
236         break;
237     case IA2_TEXT_BOUNDARY_LINE:
238         textRange = m_object->visiblePositionRangeForLine(m_object->lineForPosition(currentPosition));
239         textRange = m_object->leftLineVisiblePositionRange(textRange.start.previous());
240         break;
241     case IA2_TEXT_BOUNDARY_ALL:
242         textRange = m_object->visiblePositionRangeForRange(PlainTextRange(0, offset));
243         break;
244     default:
245         return E_INVALIDARG;
246         break;
247     }
248
249     // Obtain string and offsets associated with text range
250     *startOffset = textRange.start.deepEquivalent().offsetInContainerNode();
251     *endOffset = textRange.end.deepEquivalent().offsetInContainerNode();
252
253     if (*startOffset == *endOffset)
254         return S_FALSE;
255
256     WTF::String substringText = m_object->text().substring(*startOffset, *endOffset - *startOffset);
257     *text = BString(substringText).release();
258
259     if (substringText.length() && !*text)
260         return E_OUTOFMEMORY;
261
262     if (!*text)
263         return S_FALSE;
264
265     return S_OK;
266 }
267
268 HRESULT AccessibleText::get_textAfterOffset(long offset, enum IA2TextBoundaryType boundaryType, long* startOffset, long* endOffset, BSTR* text)
269 {
270     if (initialCheck() == E_POINTER)
271         return E_POINTER;
272
273     if (!startOffset || !endOffset || !text)
274         return E_POINTER;
275
276     int textLength = m_object->stringValue().length();
277     offset = convertSpecialOffset(offset);
278
279     if (offset < 0 || offset > textLength)
280         return E_INVALIDARG;
281
282     VisiblePosition currentPosition = m_object->visiblePositionForIndex(offset);
283     VisiblePositionRange textRange;
284
285     // Obtain the desired text range
286     switch (boundaryType) {
287     case IA2_TEXT_BOUNDARY_CHAR:
288         textRange = m_object->visiblePositionRangeForRange(PlainTextRange(offset + 1, offset + 2));
289         break;
290     case IA2_TEXT_BOUNDARY_WORD:
291         textRange = m_object->positionOfRightWord(rightWordPosition(currentPosition, true));
292         break;
293     case IA2_TEXT_BOUNDARY_SENTENCE:
294         textRange.end = m_object->nextSentenceEndPosition(currentPosition);
295         textRange = m_object->sentenceForPosition(textRange.end);
296         if (isInRange(currentPosition, textRange))
297             textRange = m_object->sentenceForPosition(m_object->nextSentenceEndPosition(textRange.end.next()));
298         break;
299     case IA2_TEXT_BOUNDARY_PARAGRAPH:
300         textRange.end = m_object->nextParagraphEndPosition(currentPosition);
301         textRange = m_object->paragraphForPosition(textRange.end);
302         if (isInRange(currentPosition, textRange))
303             textRange = m_object->paragraphForPosition(m_object->nextParagraphEndPosition(textRange.end.next()));
304         break;
305     case IA2_TEXT_BOUNDARY_LINE:
306         textRange = m_object->visiblePositionRangeForLine(m_object->lineForPosition(currentPosition));
307         textRange = m_object->rightLineVisiblePositionRange(textRange.end.next());
308         break;
309     case IA2_TEXT_BOUNDARY_ALL:
310         textRange = m_object->visiblePositionRangeForRange(PlainTextRange(offset, textLength-offset));
311         break;
312     default:
313         return E_INVALIDARG;
314         break;
315     }
316
317     // Obtain string and offsets associated with text range
318     *startOffset = textRange.start.deepEquivalent().offsetInContainerNode();
319     *endOffset = textRange.end.deepEquivalent().offsetInContainerNode();
320
321     if (*startOffset == *endOffset)
322         return S_FALSE;
323
324     WTF::String substringText = m_object->text().substring(*startOffset, *endOffset - *startOffset);
325     *text = BString(substringText).release();
326     if (substringText.length() && !*text)
327         return E_OUTOFMEMORY;
328
329     if (!*text)
330         return S_FALSE;
331
332     return S_OK;
333 }
334
335 HRESULT AccessibleText::get_textAtOffset(long offset, enum IA2TextBoundaryType boundaryType, long* startOffset, long* endOffset, BSTR* text)
336 {
337     if (initialCheck() == E_POINTER)
338         return E_POINTER;
339
340     if (!startOffset || !endOffset || !text)
341         return E_POINTER;
342
343     int textLength = m_object->stringValue().length();
344
345     offset = convertSpecialOffset(offset);
346
347     if (offset < 0 || offset > textLength)
348         return E_INVALIDARG;
349
350     // Obtain the desired text range
351     VisiblePosition currentPosition = m_object->visiblePositionForIndex(offset);
352     VisiblePositionRange textRange;
353     switch (boundaryType) {
354     case IA2_TEXT_BOUNDARY_CHAR:
355         textRange = m_object->visiblePositionRangeForRange(PlainTextRange(offset, 1));
356         break;
357     case IA2_TEXT_BOUNDARY_WORD:
358         textRange = m_object->positionOfRightWord(leftWordPosition(currentPosition.next(), true));
359         break;
360     case IA2_TEXT_BOUNDARY_SENTENCE:
361         textRange = m_object->sentenceForPosition(currentPosition);
362         break;
363     case IA2_TEXT_BOUNDARY_PARAGRAPH:
364         textRange = m_object->paragraphForPosition(currentPosition);
365         break;
366     case IA2_TEXT_BOUNDARY_LINE:
367         textRange = m_object->leftLineVisiblePositionRange(currentPosition);
368         break;
369     case IA2_TEXT_BOUNDARY_ALL:
370         textRange = m_object->visiblePositionRangeForRange(PlainTextRange(0, m_object->text().length()));
371         break;
372     default:
373         return E_INVALIDARG;
374         break;
375     }
376
377     // Obtain string and offsets associated with text range
378     *startOffset = textRange.start.deepEquivalent().offsetInContainerNode();
379     *endOffset = textRange.end.deepEquivalent().offsetInContainerNode();
380
381     if (*startOffset == *endOffset)
382         return S_FALSE;
383
384     WTF::String substringText = m_object->text().substring(*startOffset, *endOffset - *startOffset);
385     *text = BString(substringText).release();
386
387     if (substringText.length() && !*text)
388         return E_OUTOFMEMORY;
389
390     if (!*text)
391         return S_FALSE;
392
393     return S_OK;
394 }
395
396 HRESULT AccessibleText::removeSelection(long selectionIndex)
397 {
398     if (initialCheck() == E_POINTER)
399         return E_POINTER;
400
401     long selections;
402     get_nSelections(&selections);
403     if (selectionIndex < 0 || selectionIndex >= selections)
404         return E_INVALIDARG;
405
406     m_object->document()->frame()->selection().clear();
407     return S_OK;
408 }
409
410 HRESULT AccessibleText::setCaretOffset(long offset)
411 {
412     if (initialCheck() == E_POINTER)
413         return E_POINTER;
414         
415     offset = convertSpecialOffset(offset);
416
417     Node* node = m_object->node();
418     if (!node)
419         return E_POINTER;
420
421     m_object->document()->frame()->selection().setSelection(VisibleSelection(VisiblePosition(Position(node, offset, Position::PositionIsOffsetInAnchor))));
422     return S_OK;
423 }
424
425 HRESULT AccessibleText::setSelection(long selectionIndex, long startOffset, long endOffset)
426 {
427     if (initialCheck() == E_POINTER)
428         return E_POINTER;
429
430     long selections;
431     get_nSelections(&selections);
432     if (selectionIndex < 0 || selectionIndex >= selections)
433         return E_INVALIDARG;
434
435     m_object->setSelectedTextRange(PlainTextRange(startOffset, endOffset - startOffset));
436     return S_OK;
437 }
438
439 HRESULT AccessibleText::get_nCharacters(long* characters)
440 {
441     if (initialCheck() == E_POINTER)
442         return E_POINTER;
443
444     int length = m_object->stringValue().length();
445     if (length < 0)
446         return E_FAIL;
447
448     *characters = length;
449     return S_OK;
450 }
451
452 HRESULT AccessibleText::scrollSubstringTo(long startIndex, long endIndex, enum IA2ScrollType scrollType)
453 {
454     if (initialCheck() == E_POINTER)
455         return E_POINTER;
456
457     startIndex = convertSpecialOffset(startIndex);
458     endIndex = convertSpecialOffset(endIndex);
459
460     VisiblePositionRange textRange = m_object->visiblePositionRangeForRange(PlainTextRange(startIndex, endIndex-startIndex));
461     if (textRange.start.isNull() || textRange.end.isNull())
462         return S_FALSE;
463
464     IntRect boundingBox = makeRange(textRange.start, textRange.end)->absoluteBoundingBox();
465     switch (scrollType) {
466     case IA2_SCROLL_TYPE_TOP_LEFT:
467         m_object->scrollToGlobalPoint(boundingBox.minXMinYCorner());
468         break;
469     case IA2_SCROLL_TYPE_BOTTOM_RIGHT:
470         m_object->scrollToGlobalPoint(boundingBox.maxXMaxYCorner());
471         break;
472     case IA2_SCROLL_TYPE_TOP_EDGE:
473         m_object->scrollToGlobalPoint(IntPoint((boundingBox.x() + boundingBox.maxX()) / 2, boundingBox.y()));
474         break;
475     case IA2_SCROLL_TYPE_BOTTOM_EDGE:
476         m_object->scrollToGlobalPoint(IntPoint((boundingBox.x() + boundingBox.maxX()) / 2, boundingBox.maxY()));
477         break;
478     case IA2_SCROLL_TYPE_LEFT_EDGE:
479         m_object->scrollToGlobalPoint(IntPoint(boundingBox.x(), (boundingBox.y() + boundingBox.maxY()) / 2));
480         break;
481     case IA2_SCROLL_TYPE_RIGHT_EDGE:
482         m_object->scrollToGlobalPoint(IntPoint(boundingBox.maxX(), (boundingBox.y() + boundingBox.maxY()) / 2));
483         break;
484     case IA2_SCROLL_TYPE_ANYWHERE:
485         m_object->scrollToGlobalPoint(boundingBox.center());
486         break;
487     default:
488         return E_INVALIDARG;
489     }
490     return S_OK;
491 }
492
493 HRESULT AccessibleText::scrollSubstringToPoint(long startIndex, long endIndex, enum IA2CoordinateType coordinateType, long x, long y)
494 {
495     if (initialCheck() == E_POINTER)
496         return E_POINTER;
497
498     startIndex = convertSpecialOffset(startIndex);
499     endIndex = convertSpecialOffset(endIndex);
500
501     switch (coordinateType) {
502     case IA2_COORDTYPE_SCREEN_RELATIVE:
503         POINT points[1];
504         points[0].x = x;
505         points[0].y = y;
506         MapWindowPoints(0, m_window, points, 1);
507         m_object->scrollToGlobalPoint(IntPoint(points[0].x, points[0].y));
508         break;
509     case IA2_COORDTYPE_PARENT_RELATIVE:
510         m_object->scrollToGlobalPoint(IntPoint(x, y));
511         break;
512     default:
513         return E_INVALIDARG;
514     }
515
516     return S_OK;
517 }
518
519 HRESULT AccessibleText::get_newText(IA2TextSegment* newText)
520 {
521     if (initialCheck() == E_POINTER)
522         return E_POINTER;
523     
524     return E_NOTIMPL;
525 }
526
527 HRESULT AccessibleText::get_oldText(IA2TextSegment* oldText)
528 {
529     if (initialCheck() == E_POINTER)
530         return E_POINTER;
531
532     return E_NOTIMPL;
533 }
534
535
536 // IAccessibleText2
537 HRESULT AccessibleText::get_attributeRange(long offset, BSTR filter, long* startOffset, long* endOffset, BSTR* attributeValues)
538 {
539     if (initialCheck() == E_POINTER)
540         return E_POINTER;
541
542     return E_NOTIMPL;
543 }
544
545 HRESULT AccessibleText::copyText(long startOffset, long endOffset)
546 {
547     if (initialCheck() == E_POINTER)
548         return E_POINTER;
549
550     startOffset = convertSpecialOffset(startOffset);
551     endOffset = convertSpecialOffset(endOffset);
552
553     Frame* frame = m_object->document()->frame();
554     if (!frame)
555         return E_POINTER;
556
557     addSelection(startOffset, endOffset);
558
559     frame->editor().copy();
560     return S_OK;
561 }
562
563 HRESULT AccessibleText::deleteText(long startOffset, long endOffset)
564 {
565     if (!m_object->canSetValueAttribute())
566         return S_FALSE;
567
568     if (initialCheck() == E_POINTER)
569         return E_POINTER;
570
571     Frame* frame = m_object->document()->frame();
572     if (!frame)
573         return E_POINTER;
574
575     addSelection(startOffset, endOffset);
576
577     frame->editor().deleteSelectionWithSmartDelete(false);
578     return S_OK;
579 }
580
581 HRESULT AccessibleText::insertText(long offset, BSTR* text)
582 {
583     if (!m_object->canSetValueAttribute())
584         return S_FALSE;
585
586     if (initialCheck() == E_POINTER)
587         return E_POINTER;
588
589     offset = convertSpecialOffset(offset);
590
591     Frame* frame = m_object->document()->frame();
592     if (!frame)
593         return E_POINTER;
594     
595     addSelection(offset, offset);
596
597     frame->editor().insertText(*text, 0);
598     return S_OK;
599 }
600
601 HRESULT AccessibleText::cutText(long startOffset, long endOffset)
602 {
603     if (!m_object->canSetValueAttribute())
604         return S_FALSE;
605
606     if (initialCheck() == E_POINTER)
607         return E_POINTER;
608
609     startOffset = convertSpecialOffset(startOffset);
610     endOffset = convertSpecialOffset(endOffset);
611
612     Frame* frame = m_object->document()->frame();
613     if (!frame)
614         return E_POINTER;
615
616     addSelection(startOffset, endOffset);
617
618     frame->editor().cut();
619     return S_OK;
620 }
621
622 HRESULT AccessibleText::pasteText(long offset)
623 {
624     if (!m_object->canSetValueAttribute())
625         return S_FALSE;
626
627     if (initialCheck() == E_POINTER)
628         return E_POINTER;
629
630     offset = convertSpecialOffset(offset);
631
632     Frame* frame = m_object->document()->frame();
633     if (!frame)
634         return E_POINTER;
635
636     addSelection(offset, offset);
637
638     frame->editor().paste();
639     return S_OK;
640 }
641
642 HRESULT AccessibleText::replaceText(long startOffset, long endOffset, BSTR* text)
643 {
644     if (!m_object->canSetValueAttribute())
645         return S_FALSE;
646
647     if (initialCheck() == E_POINTER)
648         return E_POINTER;
649
650     startOffset = convertSpecialOffset(startOffset);
651     endOffset = convertSpecialOffset(endOffset);
652
653     Frame* frame = m_object->document()->frame();
654     if (!frame)
655         return E_POINTER;
656
657     addSelection(startOffset, endOffset);
658
659     frame->editor().replaceSelectionWithText(*text, true, false);
660     return S_OK;
661 }
662
663 HRESULT AccessibleText::setAttributes(long startOffset, long endOffset, BSTR* attributes)
664 {
665     if (initialCheck() == E_POINTER)
666         return E_POINTER;
667
668     return E_NOTIMPL;
669 }
670
671 // IAccessible2
672 HRESULT AccessibleText::get_attributes(BSTR* attributes)
673 {
674     WTF::String text("text-model:a1");
675     *attributes = BString(text).release();
676     return S_OK;
677 }
678
679 // IUnknown
680 HRESULT AccessibleText::QueryInterface(_In_ REFIID riid, _COM_Outptr_ void** ppvObject)
681 {
682     if (!ppvObject)
683         return E_POINTER;
684     if (IsEqualGUID(riid, __uuidof(IAccessibleText)))
685         *ppvObject = static_cast<IAccessibleText*>(this);
686     else if (IsEqualGUID(riid, __uuidof(IAccessibleEditableText)))
687         *ppvObject = static_cast<IAccessibleEditableText*>(this);
688     else if (IsEqualGUID(riid, __uuidof(IAccessible)))
689         *ppvObject = static_cast<IAccessible*>(this);
690     else if (IsEqualGUID(riid, __uuidof(IDispatch)))
691         *ppvObject = static_cast<IAccessible*>(this);
692     else if (IsEqualGUID(riid, __uuidof(IUnknown)))
693         *ppvObject = static_cast<IAccessible*>(this);
694     else if (IsEqualGUID(riid, __uuidof(IAccessible2_2)))
695         *ppvObject = static_cast<IAccessible2_2*>(this);
696     else if (IsEqualGUID(riid, __uuidof(IAccessible2)))
697         *ppvObject = static_cast<IAccessible2*>(this);
698     else if (IsEqualGUID(riid, __uuidof(IAccessibleComparable)))
699         *ppvObject = static_cast<IAccessibleComparable*>(this);
700     else if (IsEqualGUID(riid, __uuidof(IServiceProvider)))
701         *ppvObject = static_cast<IServiceProvider*>(this);
702     else if (IsEqualGUID(riid, __uuidof(AccessibleBase)))
703         *ppvObject = static_cast<AccessibleBase*>(this);
704     else {
705         *ppvObject = nullptr;
706         return E_NOINTERFACE;
707     }
708     AddRef();
709     return S_OK;
710 }
711
712 ULONG AccessibleText::Release()
713 {
714     ASSERT(m_refCount > 0);
715     if (--m_refCount)
716         return m_refCount;
717     delete this;
718     return 0;
719 }
720
721 int AccessibleText::convertSpecialOffset(int offset)
722 {
723     ASSERT(m_object);
724     
725     if (offset == IA2_TEXT_OFFSET_LENGTH) 
726         return m_object->stringValue().length();
727     if (offset == IA2_TEXT_OFFSET_CARET) {
728         long caretOffset;
729         get_caretOffset(&caretOffset);
730         return caretOffset;
731     }
732     return offset;
733 }
734
735 HRESULT AccessibleText::initialCheck()
736 {
737     if (!m_object)
738         return E_FAIL;
739
740     Document* document = m_object->document();
741     if (!document)
742         return E_FAIL;
743
744     Frame* frame = document->frame();
745     if (!frame)
746         return E_FAIL;
747
748     return S_OK;
749 }
750
751 bool AccessibleText::isInRange(VisiblePosition& current, VisiblePositionRange& wordRange)
752 {
753     ASSERT(wordRange.start.isNotNull());
754     ASSERT(wordRange.end.isNotNull());
755     return comparePositions(current.deepEquivalent(), wordRange.start) >= 0 && comparePositions(current.deepEquivalent(), wordRange.end) <= 0;
756 }