1/*
2 * Copyright (C) 2009 Google 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 are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "public/web/WebAXObject.h"
33
34#include "core/HTMLNames.h"
35#include "core/accessibility/AXObject.h"
36#include "core/accessibility/AXObjectCache.h"
37#include "core/accessibility/AXTable.h"
38#include "core/accessibility/AXTableCell.h"
39#include "core/accessibility/AXTableColumn.h"
40#include "core/accessibility/AXTableRow.h"
41#include "core/css/CSSPrimitiveValueMappings.h"
42#include "core/dom/Document.h"
43#include "core/dom/Node.h"
44#include "core/frame/FrameView.h"
45#include "core/page/EventHandler.h"
46#include "core/rendering/RenderView.h"
47#include "core/rendering/style/RenderStyle.h"
48#include "platform/PlatformKeyboardEvent.h"
49#include "public/platform/WebPoint.h"
50#include "public/platform/WebRect.h"
51#include "public/platform/WebString.h"
52#include "public/platform/WebURL.h"
53#include "public/web/WebDocument.h"
54#include "public/web/WebNode.h"
55#include "wtf/text/StringBuilder.h"
56
57namespace blink {
58
59#if ENABLE(ASSERT)
60// It's not safe to call some WebAXObject APIs if a layout is pending.
61// Clients should call updateLayoutAndCheckValidity first.
62static bool isLayoutClean(Document* document)
63{
64    if (!document || !document->view())
65        return false;
66    return document->lifecycle().state() >= DocumentLifecycle::LayoutClean
67        || (document->lifecycle().state() == DocumentLifecycle::StyleClean && !document->view()->needsLayout());
68}
69#endif
70
71void WebAXObject::reset()
72{
73    m_private.reset();
74}
75
76void WebAXObject::assign(const WebAXObject& other)
77{
78    m_private = other.m_private;
79}
80
81bool WebAXObject::equals(const WebAXObject& n) const
82{
83    return m_private.get() == n.m_private.get();
84}
85
86bool WebAXObject::isDetached() const
87{
88    if (m_private.isNull())
89        return true;
90
91    return m_private->isDetached();
92}
93
94int WebAXObject::axID() const
95{
96    if (isDetached())
97        return -1;
98
99    return m_private->axObjectID();
100}
101
102bool WebAXObject::updateLayoutAndCheckValidity()
103{
104    if (!isDetached()) {
105        Document* document = m_private->document();
106        if (!document || !document->topDocument().view())
107            return false;
108        document->topDocument().view()->updateLayoutAndStyleIfNeededRecursive();
109    }
110
111    // Doing a layout can cause this object to be invalid, so check again.
112    return !isDetached();
113}
114
115bool WebAXObject::updateBackingStoreAndCheckValidity()
116{
117    return updateLayoutAndCheckValidity();
118}
119
120WebString WebAXObject::accessibilityDescription() const
121{
122    if (isDetached())
123        return WebString();
124
125    ASSERT(isLayoutClean(m_private->document()));
126
127    return m_private->accessibilityDescription();
128}
129
130WebString WebAXObject::actionVerb() const
131{
132    if (isDetached())
133        return WebString();
134
135    return m_private->actionVerb();
136}
137
138bool WebAXObject::canDecrement() const
139{
140    if (isDetached())
141        return false;
142
143    return m_private->isSlider();
144}
145
146bool WebAXObject::canIncrement() const
147{
148    if (isDetached())
149        return false;
150
151    return m_private->isSlider();
152}
153
154bool WebAXObject::canPress() const
155{
156    if (isDetached())
157        return false;
158
159    return m_private->actionElement() || m_private->isButton() || m_private->isMenuRelated();
160}
161
162bool WebAXObject::canSetFocusAttribute() const
163{
164    if (isDetached())
165        return false;
166
167    return m_private->canSetFocusAttribute();
168}
169
170bool WebAXObject::canSetValueAttribute() const
171{
172    if (isDetached())
173        return false;
174
175    return m_private->canSetValueAttribute();
176}
177
178unsigned WebAXObject::childCount() const
179{
180    if (isDetached())
181        return 0;
182
183    return m_private->children().size();
184}
185
186WebAXObject WebAXObject::childAt(unsigned index) const
187{
188    if (isDetached())
189        return WebAXObject();
190
191    if (m_private->children().size() <= index)
192        return WebAXObject();
193
194    return WebAXObject(m_private->children()[index]);
195}
196
197WebAXObject WebAXObject::parentObject() const
198{
199    if (isDetached())
200        return WebAXObject();
201
202    return WebAXObject(m_private->parentObject());
203}
204
205bool WebAXObject::canSetSelectedAttribute() const
206{
207    if (isDetached())
208        return 0;
209
210    return m_private->canSetSelectedAttribute();
211}
212
213bool WebAXObject::isAnchor() const
214{
215    if (isDetached())
216        return 0;
217
218    return m_private->isAnchor();
219}
220
221bool WebAXObject::isAriaReadOnly() const
222{
223    if (isDetached())
224        return 0;
225
226    return equalIgnoringCase(m_private->getAttribute(HTMLNames::aria_readonlyAttr), "true");
227}
228
229bool WebAXObject::isButtonStateMixed() const
230{
231    if (isDetached())
232        return 0;
233
234    return m_private->checkboxOrRadioValue() == ButtonStateMixed;
235}
236
237bool WebAXObject::isChecked() const
238{
239    if (isDetached())
240        return 0;
241
242    return m_private->isChecked();
243}
244
245bool WebAXObject::isClickable() const
246{
247    if (isDetached())
248        return 0;
249
250    return m_private->isClickable();
251}
252
253bool WebAXObject::isCollapsed() const
254{
255    if (isDetached())
256        return 0;
257
258    return m_private->isCollapsed();
259}
260
261bool WebAXObject::isControl() const
262{
263    if (isDetached())
264        return 0;
265
266    return m_private->isControl();
267}
268
269bool WebAXObject::isEnabled() const
270{
271    if (isDetached())
272        return 0;
273
274    return m_private->isEnabled();
275}
276
277bool WebAXObject::isFocused() const
278{
279    if (isDetached())
280        return 0;
281
282    return m_private->isFocused();
283}
284
285bool WebAXObject::isHovered() const
286{
287    if (isDetached())
288        return 0;
289
290    return m_private->isHovered();
291}
292
293bool WebAXObject::isIndeterminate() const
294{
295    if (isDetached())
296        return 0;
297
298    return m_private->isIndeterminate();
299}
300
301bool WebAXObject::isLinked() const
302{
303    if (isDetached())
304        return 0;
305
306    return m_private->isLinked();
307}
308
309bool WebAXObject::isLoaded() const
310{
311    if (isDetached())
312        return 0;
313
314    return m_private->isLoaded();
315}
316
317bool WebAXObject::isMultiSelectable() const
318{
319    if (isDetached())
320        return 0;
321
322    return m_private->isMultiSelectable();
323}
324
325bool WebAXObject::isOffScreen() const
326{
327    if (isDetached())
328        return 0;
329
330    return m_private->isOffScreen();
331}
332
333bool WebAXObject::isPasswordField() const
334{
335    if (isDetached())
336        return 0;
337
338    return m_private->isPasswordField();
339}
340
341bool WebAXObject::isPressed() const
342{
343    if (isDetached())
344        return 0;
345
346    return m_private->isPressed();
347}
348
349bool WebAXObject::isReadOnly() const
350{
351    if (isDetached())
352        return 0;
353
354    return m_private->isReadOnly();
355}
356
357bool WebAXObject::isRequired() const
358{
359    if (isDetached())
360        return 0;
361
362    return m_private->isRequired();
363}
364
365bool WebAXObject::isSelected() const
366{
367    if (isDetached())
368        return 0;
369
370    return m_private->isSelected();
371}
372
373bool WebAXObject::isSelectedOptionActive() const
374{
375    if (isDetached())
376        return false;
377
378    return m_private->isSelectedOptionActive();
379}
380
381bool WebAXObject::isVertical() const
382{
383    if (isDetached())
384        return 0;
385
386    return m_private->orientation() == AccessibilityOrientationVertical;
387}
388
389bool WebAXObject::isVisible() const
390{
391    if (isDetached())
392        return 0;
393
394    return m_private->isVisible();
395}
396
397bool WebAXObject::isVisited() const
398{
399    if (isDetached())
400        return 0;
401
402    return m_private->isVisited();
403}
404
405WebString WebAXObject::accessKey() const
406{
407    if (isDetached())
408        return WebString();
409
410    return WebString(m_private->accessKey());
411}
412
413WebAXObject WebAXObject::ariaActiveDescendant() const
414{
415    if (isDetached())
416        return WebAXObject();
417
418    return WebAXObject(m_private->activeDescendant());
419}
420
421bool WebAXObject::ariaControls(WebVector<WebAXObject>& controlsElements) const
422{
423    if (isDetached())
424        return false;
425
426    AXObject::AccessibilityChildrenVector controls;
427    m_private->ariaControlsElements(controls);
428
429    WebVector<WebAXObject> result(controls.size());
430    for (size_t i = 0; i < controls.size(); i++)
431        result[i] = WebAXObject(controls[i]);
432    controlsElements.swap(result);
433
434    return true;
435}
436
437bool WebAXObject::ariaDescribedby(WebVector<WebAXObject>& describedbyElements) const
438{
439    if (isDetached())
440        return false;
441
442    AXObject::AccessibilityChildrenVector describedby;
443    m_private->ariaDescribedbyElements(describedby);
444
445    WebVector<WebAXObject> result(describedby.size());
446    for (size_t i = 0; i < describedby.size(); i++)
447        result[i] = WebAXObject(describedby[i]);
448    describedbyElements.swap(result);
449
450    return true;
451}
452
453bool WebAXObject::ariaHasPopup() const
454{
455    if (isDetached())
456        return 0;
457
458    return m_private->ariaHasPopup();
459}
460
461bool WebAXObject::ariaFlowTo(WebVector<WebAXObject>& flowToElements) const
462{
463    if (isDetached())
464        return false;
465
466    AXObject::AccessibilityChildrenVector flowTo;
467    m_private->ariaFlowToElements(flowTo);
468
469    WebVector<WebAXObject> result(flowTo.size());
470    for (size_t i = 0; i < flowTo.size(); i++)
471        result[i] = WebAXObject(flowTo[i]);
472    flowToElements.swap(result);
473
474    return true;
475}
476
477bool WebAXObject::ariaLabelledby(WebVector<WebAXObject>& labelledbyElements) const
478{
479    if (isDetached())
480        return false;
481
482    AXObject::AccessibilityChildrenVector labelledby;
483    m_private->ariaLabelledbyElements(labelledby);
484
485    WebVector<WebAXObject> result(labelledby.size());
486    for (size_t i = 0; i < labelledby.size(); i++)
487        result[i] = WebAXObject(labelledby[i]);
488    labelledbyElements.swap(result);
489
490    return true;
491}
492
493bool WebAXObject::ariaLiveRegionAtomic() const
494{
495    if (isDetached())
496        return 0;
497
498    return m_private->ariaLiveRegionAtomic();
499}
500
501bool WebAXObject::ariaLiveRegionBusy() const
502{
503    if (isDetached())
504        return 0;
505
506    return m_private->ariaLiveRegionBusy();
507}
508
509WebString WebAXObject::ariaLiveRegionRelevant() const
510{
511    if (isDetached())
512        return WebString();
513
514    return m_private->ariaLiveRegionRelevant();
515}
516
517WebString WebAXObject::ariaLiveRegionStatus() const
518{
519    if (isDetached())
520        return WebString();
521
522    return m_private->ariaLiveRegionStatus();
523}
524
525bool WebAXObject::ariaOwns(WebVector<WebAXObject>& ownsElements) const
526{
527    if (isDetached())
528        return false;
529
530    AXObject::AccessibilityChildrenVector owns;
531    m_private->ariaOwnsElements(owns);
532
533    WebVector<WebAXObject> result(owns.size());
534    for (size_t i = 0; i < owns.size(); i++)
535        result[i] = WebAXObject(owns[i]);
536    ownsElements.swap(result);
537
538    return true;
539}
540
541WebRect WebAXObject::boundingBoxRect() const
542{
543    if (isDetached())
544        return WebRect();
545
546    ASSERT(isLayoutClean(m_private->document()));
547
548    return pixelSnappedIntRect(m_private->elementRect());
549}
550
551bool WebAXObject::canvasHasFallbackContent() const
552{
553    if (isDetached())
554        return false;
555
556    return m_private->canvasHasFallbackContent();
557}
558
559WebPoint WebAXObject::clickPoint() const
560{
561    if (isDetached())
562        return WebPoint();
563
564    return WebPoint(m_private->clickPoint());
565}
566
567void WebAXObject::colorValue(int& r, int& g, int& b) const
568{
569    if (isDetached())
570        return;
571
572    m_private->colorValue(r, g, b);
573}
574
575double WebAXObject::estimatedLoadingProgress() const
576{
577    if (isDetached())
578        return 0.0;
579
580    return m_private->estimatedLoadingProgress();
581}
582
583WebString WebAXObject::helpText() const
584{
585    if (isDetached())
586        return WebString();
587
588    return m_private->helpText();
589}
590
591int WebAXObject::headingLevel() const
592{
593    if (isDetached())
594        return 0;
595
596    return m_private->headingLevel();
597}
598
599int WebAXObject::hierarchicalLevel() const
600{
601    if (isDetached())
602        return 0;
603
604    return m_private->hierarchicalLevel();
605}
606
607WebAXObject WebAXObject::hitTest(const WebPoint& point) const
608{
609    if (isDetached())
610        return WebAXObject();
611
612    IntPoint contentsPoint = m_private->documentFrameView()->windowToContents(point);
613    RefPtr<AXObject> hit = m_private->accessibilityHitTest(contentsPoint);
614
615    if (hit)
616        return WebAXObject(hit);
617
618    if (m_private->elementRect().contains(contentsPoint))
619        return *this;
620
621    return WebAXObject();
622}
623
624WebString WebAXObject::keyboardShortcut() const
625{
626    if (isDetached())
627        return WebString();
628
629    String accessKey = m_private->accessKey();
630    if (accessKey.isNull())
631        return WebString();
632
633    DEFINE_STATIC_LOCAL(String, modifierString, ());
634    if (modifierString.isNull()) {
635        unsigned modifiers = EventHandler::accessKeyModifiers();
636        // Follow the same order as Mozilla MSAA implementation:
637        // Ctrl+Alt+Shift+Meta+key. MSDN states that keyboard shortcut strings
638        // should not be localized and defines the separator as "+".
639        StringBuilder modifierStringBuilder;
640        if (modifiers & PlatformEvent::CtrlKey)
641            modifierStringBuilder.appendLiteral("Ctrl+");
642        if (modifiers & PlatformEvent::AltKey)
643            modifierStringBuilder.appendLiteral("Alt+");
644        if (modifiers & PlatformEvent::ShiftKey)
645            modifierStringBuilder.appendLiteral("Shift+");
646        if (modifiers & PlatformEvent::MetaKey)
647            modifierStringBuilder.appendLiteral("Win+");
648        modifierString = modifierStringBuilder.toString();
649    }
650
651    return String(modifierString + accessKey);
652}
653
654bool WebAXObject::performDefaultAction() const
655{
656    if (isDetached())
657        return false;
658
659    return m_private->performDefaultAction();
660}
661
662bool WebAXObject::increment() const
663{
664    if (isDetached())
665        return false;
666
667    if (canIncrement()) {
668        m_private->increment();
669        return true;
670    }
671    return false;
672}
673
674bool WebAXObject::decrement() const
675{
676    if (isDetached())
677        return false;
678
679    if (canDecrement()) {
680        m_private->decrement();
681        return true;
682    }
683    return false;
684}
685
686bool WebAXObject::press() const
687{
688    if (isDetached())
689        return false;
690
691    return m_private->press();
692}
693
694WebAXRole WebAXObject::role() const
695{
696    if (isDetached())
697        return WebAXRoleUnknown;
698
699    return static_cast<WebAXRole>(m_private->roleValue());
700}
701
702unsigned WebAXObject::selectionEnd() const
703{
704    if (isDetached())
705        return 0;
706
707    return m_private->selectedTextRange().start + m_private->selectedTextRange().length;
708}
709
710unsigned WebAXObject::selectionStart() const
711{
712    if (isDetached())
713        return 0;
714
715    return m_private->selectedTextRange().start;
716}
717
718unsigned WebAXObject::selectionEndLineNumber() const
719{
720    if (isDetached())
721        return 0;
722
723    VisiblePosition position = m_private->visiblePositionForIndex(selectionEnd());
724    int lineNumber = m_private->lineForPosition(position);
725    if (lineNumber < 0)
726        return 0;
727    return lineNumber;
728}
729
730unsigned WebAXObject::selectionStartLineNumber() const
731{
732    if (isDetached())
733        return 0;
734
735    VisiblePosition position = m_private->visiblePositionForIndex(selectionStart());
736    int lineNumber = m_private->lineForPosition(position);
737    if (lineNumber < 0)
738        return 0;
739    return lineNumber;
740}
741
742void WebAXObject::setFocused(bool on) const
743{
744    if (!isDetached())
745        m_private->setFocused(on);
746}
747
748void WebAXObject::setSelectedTextRange(int selectionStart, int selectionEnd) const
749{
750    if (isDetached())
751        return;
752
753    m_private->setSelectedTextRange(AXObject::PlainTextRange(selectionStart, selectionEnd - selectionStart));
754}
755
756WebString WebAXObject::stringValue() const
757{
758    if (isDetached())
759        return WebString();
760
761    return m_private->stringValue();
762}
763
764WebString WebAXObject::title() const
765{
766    if (isDetached())
767        return WebString();
768
769    ASSERT(isLayoutClean(m_private->document()));
770
771    return m_private->title();
772}
773
774WebAXObject WebAXObject::titleUIElement() const
775{
776    if (isDetached())
777        return WebAXObject();
778
779    if (!m_private->exposesTitleUIElement())
780        return WebAXObject();
781
782    return WebAXObject(m_private->titleUIElement());
783}
784
785WebURL WebAXObject::url() const
786{
787    if (isDetached())
788        return WebURL();
789
790    return m_private->url();
791}
792
793bool WebAXObject::supportsRangeValue() const
794{
795    if (isDetached())
796        return false;
797
798    return m_private->supportsRangeValue();
799}
800
801WebString WebAXObject::valueDescription() const
802{
803    if (isDetached())
804        return WebString();
805
806    return m_private->valueDescription();
807}
808
809float WebAXObject::valueForRange() const
810{
811    if (isDetached())
812        return 0.0;
813
814    return m_private->valueForRange();
815}
816
817float WebAXObject::maxValueForRange() const
818{
819    if (isDetached())
820        return 0.0;
821
822    return m_private->maxValueForRange();
823}
824
825float WebAXObject::minValueForRange() const
826{
827    if (isDetached())
828        return 0.0;
829
830    return m_private->minValueForRange();
831}
832
833WebNode WebAXObject::node() const
834{
835    if (isDetached())
836        return WebNode();
837
838    Node* node = m_private->node();
839    if (!node)
840        return WebNode();
841
842    return WebNode(node);
843}
844
845WebDocument WebAXObject::document() const
846{
847    if (isDetached())
848        return WebDocument();
849
850    Document* document = m_private->document();
851    if (!document)
852        return WebDocument();
853
854    return WebDocument(document);
855}
856
857bool WebAXObject::hasComputedStyle() const
858{
859    if (isDetached())
860        return false;
861
862    Document* document = m_private->document();
863    if (document)
864        document->updateRenderTreeIfNeeded();
865
866    Node* node = m_private->node();
867    if (!node)
868        return false;
869
870    return node->computedStyle();
871}
872
873WebString WebAXObject::computedStyleDisplay() const
874{
875    if (isDetached())
876        return WebString();
877
878    Document* document = m_private->document();
879    if (document)
880        document->updateRenderTreeIfNeeded();
881
882    Node* node = m_private->node();
883    if (!node)
884        return WebString();
885
886    RenderStyle* renderStyle = node->computedStyle();
887    if (!renderStyle)
888        return WebString();
889
890    return WebString(CSSPrimitiveValue::create(renderStyle->display())->getStringValue());
891}
892
893bool WebAXObject::accessibilityIsIgnored() const
894{
895    if (isDetached())
896        return false;
897
898    return m_private->accessibilityIsIgnored();
899}
900
901bool WebAXObject::lineBreaks(WebVector<int>& result) const
902{
903    if (isDetached())
904        return false;
905
906    Vector<int> lineBreaksVector;
907    m_private->lineBreaks(lineBreaksVector);
908
909    size_t vectorSize = lineBreaksVector.size();
910    WebVector<int> lineBreaksWebVector(vectorSize);
911    for (size_t i = 0; i< vectorSize; i++)
912        lineBreaksWebVector[i] = lineBreaksVector[i];
913    result.swap(lineBreaksWebVector);
914
915    return true;
916}
917
918unsigned WebAXObject::columnCount() const
919{
920    if (isDetached())
921        return false;
922
923    if (!m_private->isAXTable())
924        return 0;
925
926    return toAXTable(m_private.get())->columnCount();
927}
928
929unsigned WebAXObject::rowCount() const
930{
931    if (isDetached())
932        return false;
933
934    if (!m_private->isAXTable())
935        return 0;
936
937    return toAXTable(m_private.get())->rowCount();
938}
939
940WebAXObject WebAXObject::cellForColumnAndRow(unsigned column, unsigned row) const
941{
942    if (isDetached())
943        return WebAXObject();
944
945    if (!m_private->isAXTable())
946        return WebAXObject();
947
948    AXTableCell* cell = toAXTable(m_private.get())->cellForColumnAndRow(column, row);
949    return WebAXObject(static_cast<AXObject*>(cell));
950}
951
952WebAXObject WebAXObject::headerContainerObject() const
953{
954    if (isDetached())
955        return WebAXObject();
956
957    if (!m_private->isAXTable())
958        return WebAXObject();
959
960    return WebAXObject(toAXTable(m_private.get())->headerContainer());
961}
962
963WebAXObject WebAXObject::rowAtIndex(unsigned rowIndex) const
964{
965    if (isDetached())
966        return WebAXObject();
967
968    if (!m_private->isAXTable())
969        return WebAXObject();
970
971    const AXObject::AccessibilityChildrenVector& rows = toAXTable(m_private.get())->rows();
972    if (rowIndex < rows.size())
973        return WebAXObject(rows[rowIndex]);
974
975    return WebAXObject();
976}
977
978WebAXObject WebAXObject::columnAtIndex(unsigned columnIndex) const
979{
980    if (isDetached())
981        return WebAXObject();
982
983    if (!m_private->isAXTable())
984        return WebAXObject();
985
986    const AXObject::AccessibilityChildrenVector& columns = toAXTable(m_private.get())->columns();
987    if (columnIndex < columns.size())
988        return WebAXObject(columns[columnIndex]);
989
990    return WebAXObject();
991}
992
993unsigned WebAXObject::rowIndex() const
994{
995    if (isDetached())
996        return 0;
997
998    if (!m_private->isTableRow())
999        return 0;
1000
1001    return toAXTableRow(m_private.get())->rowIndex();
1002}
1003
1004WebAXObject WebAXObject::rowHeader() const
1005{
1006    if (isDetached())
1007        return WebAXObject();
1008
1009    if (!m_private->isTableRow())
1010        return WebAXObject();
1011
1012    return WebAXObject(toAXTableRow(m_private.get())->headerObject());
1013}
1014
1015unsigned WebAXObject::columnIndex() const
1016{
1017    if (isDetached())
1018        return 0;
1019
1020    if (m_private->roleValue() != ColumnRole)
1021        return 0;
1022
1023    return toAXTableColumn(m_private.get())->columnIndex();
1024}
1025
1026WebAXObject WebAXObject::columnHeader() const
1027{
1028    if (isDetached())
1029        return WebAXObject();
1030
1031    if (m_private->roleValue() != ColumnRole)
1032        return WebAXObject();
1033
1034    return WebAXObject(toAXTableColumn(m_private.get())->headerObject());
1035}
1036
1037unsigned WebAXObject::cellColumnIndex() const
1038{
1039    if (isDetached())
1040        return 0;
1041
1042    if (!m_private->isTableCell())
1043        return 0;
1044
1045    pair<unsigned, unsigned> columnRange;
1046    toAXTableCell(m_private.get())->columnIndexRange(columnRange);
1047    return columnRange.first;
1048}
1049
1050unsigned WebAXObject::cellColumnSpan() const
1051{
1052    if (isDetached())
1053        return 0;
1054
1055    if (!m_private->isTableCell())
1056        return 0;
1057
1058    pair<unsigned, unsigned> columnRange;
1059    toAXTableCell(m_private.get())->columnIndexRange(columnRange);
1060    return columnRange.second;
1061}
1062
1063unsigned WebAXObject::cellRowIndex() const
1064{
1065    if (isDetached())
1066        return 0;
1067
1068    if (!m_private->isTableCell())
1069        return 0;
1070
1071    pair<unsigned, unsigned> rowRange;
1072    toAXTableCell(m_private.get())->rowIndexRange(rowRange);
1073    return rowRange.first;
1074}
1075
1076unsigned WebAXObject::cellRowSpan() const
1077{
1078    if (isDetached())
1079        return 0;
1080
1081    if (!m_private->isTableCell())
1082        return 0;
1083
1084    pair<unsigned, unsigned> rowRange;
1085    toAXTableCell(m_private.get())->rowIndexRange(rowRange);
1086    return rowRange.second;
1087}
1088
1089WebAXTextDirection WebAXObject::textDirection() const
1090{
1091    if (isDetached())
1092        return WebAXTextDirectionLR;
1093
1094    return static_cast<WebAXTextDirection>(m_private->textDirection());
1095}
1096
1097void WebAXObject::characterOffsets(WebVector<int>& offsets) const
1098{
1099    if (isDetached())
1100        return;
1101
1102    Vector<int> offsetsVector;
1103    m_private->textCharacterOffsets(offsetsVector);
1104
1105    size_t vectorSize = offsetsVector.size();
1106    WebVector<int> offsetsWebVector(vectorSize);
1107    for (size_t i = 0; i < vectorSize; i++)
1108        offsetsWebVector[i] = offsetsVector[i];
1109    offsets.swap(offsetsWebVector);
1110}
1111
1112void WebAXObject::wordBoundaries(WebVector<int>& starts, WebVector<int>& ends) const
1113{
1114    if (isDetached())
1115        return;
1116
1117    Vector<AXObject::PlainTextRange> words;
1118    m_private->wordBoundaries(words);
1119
1120    WebVector<int> startsWebVector(words.size());
1121    WebVector<int> endsWebVector(words.size());
1122    for (size_t i = 0; i < words.size(); i++) {
1123        startsWebVector[i] = words[i].start;
1124        endsWebVector[i] = words[i].start + words[i].length;
1125    }
1126    starts.swap(startsWebVector);
1127    ends.swap(endsWebVector);
1128}
1129
1130void WebAXObject::scrollToMakeVisible() const
1131{
1132    if (!isDetached())
1133        m_private->scrollToMakeVisible();
1134}
1135
1136void WebAXObject::scrollToMakeVisibleWithSubFocus(const WebRect& subfocus) const
1137{
1138    if (!isDetached())
1139        m_private->scrollToMakeVisibleWithSubFocus(subfocus);
1140}
1141
1142void WebAXObject::scrollToGlobalPoint(const WebPoint& point) const
1143{
1144    if (!isDetached())
1145        m_private->scrollToGlobalPoint(point);
1146}
1147
1148WebAXObject::WebAXObject(const WTF::PassRefPtr<AXObject>& object)
1149    : m_private(object)
1150{
1151}
1152
1153WebAXObject& WebAXObject::operator=(const WTF::PassRefPtr<AXObject>& object)
1154{
1155    m_private = object;
1156    return *this;
1157}
1158
1159WebAXObject::operator WTF::PassRefPtr<AXObject>() const
1160{
1161    return m_private.get();
1162}
1163
1164} // namespace blink
1165