2 * Copyright (C) 2009 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
32 #include "public/web/WebAXObject.h"
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"
60 // It's not safe to call some WebAXObject APIs if a layout is pending.
61 // Clients should call updateLayoutAndCheckValidity first.
62 static bool isLayoutClean(Document* document)
64 if (!document || !document->view())
66 return document->lifecycle().state() >= DocumentLifecycle::LayoutClean
67 || (document->lifecycle().state() == DocumentLifecycle::StyleClean && !document->view()->needsLayout());
71 void WebAXObject::reset()
76 void WebAXObject::assign(const WebAXObject& other)
78 m_private = other.m_private;
81 bool WebAXObject::equals(const WebAXObject& n) const
83 return m_private.get() == n.m_private.get();
86 bool WebAXObject::isDetached() const
88 if (m_private.isNull())
91 return m_private->isDetached();
94 int WebAXObject::axID() const
99 return m_private->axObjectID();
102 bool WebAXObject::updateLayoutAndCheckValidity()
105 Document* document = m_private->document();
106 if (!document || !document->topDocument().view())
108 document->topDocument().view()->updateLayoutAndStyleIfNeededRecursive();
111 // Doing a layout can cause this object to be invalid, so check again.
112 return !isDetached();
115 bool WebAXObject::updateBackingStoreAndCheckValidity()
117 return updateLayoutAndCheckValidity();
120 WebString WebAXObject::accessibilityDescription() const
125 ASSERT(isLayoutClean(m_private->document()));
127 return m_private->accessibilityDescription();
130 WebString WebAXObject::actionVerb() const
135 return m_private->actionVerb();
138 bool WebAXObject::canDecrement() const
143 return m_private->isSlider();
146 bool WebAXObject::canIncrement() const
151 return m_private->isSlider();
154 bool WebAXObject::canPress() const
159 return m_private->actionElement() || m_private->isButton() || m_private->isMenuRelated();
162 bool WebAXObject::canSetFocusAttribute() const
167 return m_private->canSetFocusAttribute();
170 bool WebAXObject::canSetValueAttribute() const
175 return m_private->canSetValueAttribute();
178 unsigned WebAXObject::childCount() const
183 return m_private->children().size();
186 WebAXObject WebAXObject::childAt(unsigned index) const
189 return WebAXObject();
191 if (m_private->children().size() <= index)
192 return WebAXObject();
194 return WebAXObject(m_private->children()[index]);
197 WebAXObject WebAXObject::parentObject() const
200 return WebAXObject();
202 return WebAXObject(m_private->parentObject());
205 bool WebAXObject::canSetSelectedAttribute() const
210 return m_private->canSetSelectedAttribute();
213 bool WebAXObject::isAnchor() const
218 return m_private->isAnchor();
221 bool WebAXObject::isAriaReadOnly() const
226 return equalIgnoringCase(m_private->getAttribute(HTMLNames::aria_readonlyAttr), "true");
229 bool WebAXObject::isButtonStateMixed() const
234 return m_private->checkboxOrRadioValue() == ButtonStateMixed;
237 bool WebAXObject::isChecked() const
242 return m_private->isChecked();
245 bool WebAXObject::isClickable() const
250 return m_private->isClickable();
253 bool WebAXObject::isCollapsed() const
258 return m_private->isCollapsed();
261 bool WebAXObject::isControl() const
266 return m_private->isControl();
269 bool WebAXObject::isEnabled() const
274 return m_private->isEnabled();
277 bool WebAXObject::isFocused() const
282 return m_private->isFocused();
285 bool WebAXObject::isHovered() const
290 return m_private->isHovered();
293 bool WebAXObject::isIndeterminate() const
298 return m_private->isIndeterminate();
301 bool WebAXObject::isLinked() const
306 return m_private->isLinked();
309 bool WebAXObject::isLoaded() const
314 return m_private->isLoaded();
317 bool WebAXObject::isMultiSelectable() const
322 return m_private->isMultiSelectable();
325 bool WebAXObject::isOffScreen() const
330 return m_private->isOffScreen();
333 bool WebAXObject::isPasswordField() const
338 return m_private->isPasswordField();
341 bool WebAXObject::isPressed() const
346 return m_private->isPressed();
349 bool WebAXObject::isReadOnly() const
354 return m_private->isReadOnly();
357 bool WebAXObject::isRequired() const
362 return m_private->isRequired();
365 bool WebAXObject::isSelected() const
370 return m_private->isSelected();
373 bool WebAXObject::isSelectedOptionActive() const
378 return m_private->isSelectedOptionActive();
381 bool WebAXObject::isVertical() const
386 return m_private->orientation() == AccessibilityOrientationVertical;
389 bool WebAXObject::isVisible() const
394 return m_private->isVisible();
397 bool WebAXObject::isVisited() const
402 return m_private->isVisited();
405 WebString WebAXObject::accessKey() const
410 return WebString(m_private->accessKey());
413 WebAXObject WebAXObject::ariaActiveDescendant() const
416 return WebAXObject();
418 return WebAXObject(m_private->activeDescendant());
421 bool WebAXObject::ariaControls(WebVector<WebAXObject>& controlsElements) const
426 AXObject::AccessibilityChildrenVector controls;
427 m_private->ariaControlsElements(controls);
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);
437 bool WebAXObject::ariaDescribedby(WebVector<WebAXObject>& describedbyElements) const
442 AXObject::AccessibilityChildrenVector describedby;
443 m_private->ariaDescribedbyElements(describedby);
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);
453 bool WebAXObject::ariaHasPopup() const
458 return m_private->ariaHasPopup();
461 bool WebAXObject::ariaFlowTo(WebVector<WebAXObject>& flowToElements) const
466 AXObject::AccessibilityChildrenVector flowTo;
467 m_private->ariaFlowToElements(flowTo);
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);
477 bool WebAXObject::ariaLabelledby(WebVector<WebAXObject>& labelledbyElements) const
482 AXObject::AccessibilityChildrenVector labelledby;
483 m_private->ariaLabelledbyElements(labelledby);
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);
493 bool WebAXObject::ariaLiveRegionAtomic() const
498 return m_private->ariaLiveRegionAtomic();
501 bool WebAXObject::ariaLiveRegionBusy() const
506 return m_private->ariaLiveRegionBusy();
509 WebString WebAXObject::ariaLiveRegionRelevant() const
514 return m_private->ariaLiveRegionRelevant();
517 WebString WebAXObject::ariaLiveRegionStatus() const
522 return m_private->ariaLiveRegionStatus();
525 bool WebAXObject::ariaOwns(WebVector<WebAXObject>& ownsElements) const
530 AXObject::AccessibilityChildrenVector owns;
531 m_private->ariaOwnsElements(owns);
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);
541 WebRect WebAXObject::boundingBoxRect() const
546 ASSERT(isLayoutClean(m_private->document()));
548 return pixelSnappedIntRect(m_private->elementRect());
551 bool WebAXObject::canvasHasFallbackContent() const
556 return m_private->canvasHasFallbackContent();
559 WebPoint WebAXObject::clickPoint() const
564 return WebPoint(m_private->clickPoint());
567 void WebAXObject::colorValue(int& r, int& g, int& b) const
572 m_private->colorValue(r, g, b);
575 double WebAXObject::estimatedLoadingProgress() const
580 return m_private->estimatedLoadingProgress();
583 WebString WebAXObject::helpText() const
588 return m_private->helpText();
591 int WebAXObject::headingLevel() const
596 return m_private->headingLevel();
599 int WebAXObject::hierarchicalLevel() const
604 return m_private->hierarchicalLevel();
607 WebAXObject WebAXObject::hitTest(const WebPoint& point) const
610 return WebAXObject();
612 IntPoint contentsPoint = m_private->documentFrameView()->windowToContents(point);
613 RefPtr<AXObject> hit = m_private->accessibilityHitTest(contentsPoint);
616 return WebAXObject(hit);
618 if (m_private->elementRect().contains(contentsPoint))
621 return WebAXObject();
624 WebString WebAXObject::keyboardShortcut() const
629 String accessKey = m_private->accessKey();
630 if (accessKey.isNull())
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();
651 return String(modifierString + accessKey);
654 bool WebAXObject::performDefaultAction() const
659 return m_private->performDefaultAction();
662 bool WebAXObject::increment() const
667 if (canIncrement()) {
668 m_private->increment();
674 bool WebAXObject::decrement() const
679 if (canDecrement()) {
680 m_private->decrement();
686 bool WebAXObject::press() const
691 return m_private->press();
694 WebAXRole WebAXObject::role() const
697 return WebAXRoleUnknown;
699 return static_cast<WebAXRole>(m_private->roleValue());
702 unsigned WebAXObject::selectionEnd() const
707 return m_private->selectedTextRange().start + m_private->selectedTextRange().length;
710 unsigned WebAXObject::selectionStart() const
715 return m_private->selectedTextRange().start;
718 unsigned WebAXObject::selectionEndLineNumber() const
723 VisiblePosition position = m_private->visiblePositionForIndex(selectionEnd());
724 int lineNumber = m_private->lineForPosition(position);
730 unsigned WebAXObject::selectionStartLineNumber() const
735 VisiblePosition position = m_private->visiblePositionForIndex(selectionStart());
736 int lineNumber = m_private->lineForPosition(position);
742 void WebAXObject::setFocused(bool on) const
745 m_private->setFocused(on);
748 void WebAXObject::setSelectedTextRange(int selectionStart, int selectionEnd) const
753 m_private->setSelectedTextRange(AXObject::PlainTextRange(selectionStart, selectionEnd - selectionStart));
756 WebString WebAXObject::stringValue() const
761 return m_private->stringValue();
764 WebString WebAXObject::title() const
769 ASSERT(isLayoutClean(m_private->document()));
771 return m_private->title();
774 WebAXObject WebAXObject::titleUIElement() const
777 return WebAXObject();
779 if (!m_private->exposesTitleUIElement())
780 return WebAXObject();
782 return WebAXObject(m_private->titleUIElement());
785 WebURL WebAXObject::url() const
790 return m_private->url();
793 bool WebAXObject::supportsRangeValue() const
798 return m_private->supportsRangeValue();
801 WebString WebAXObject::valueDescription() const
806 return m_private->valueDescription();
809 float WebAXObject::valueForRange() const
814 return m_private->valueForRange();
817 float WebAXObject::maxValueForRange() const
822 return m_private->maxValueForRange();
825 float WebAXObject::minValueForRange() const
830 return m_private->minValueForRange();
833 WebNode WebAXObject::node() const
838 Node* node = m_private->node();
842 return WebNode(node);
845 WebDocument WebAXObject::document() const
848 return WebDocument();
850 Document* document = m_private->document();
852 return WebDocument();
854 return WebDocument(document);
857 bool WebAXObject::hasComputedStyle() const
862 Document* document = m_private->document();
864 document->updateRenderTreeIfNeeded();
866 Node* node = m_private->node();
870 return node->computedStyle();
873 WebString WebAXObject::computedStyleDisplay() const
878 Document* document = m_private->document();
880 document->updateRenderTreeIfNeeded();
882 Node* node = m_private->node();
886 RenderStyle* renderStyle = node->computedStyle();
890 return WebString(CSSPrimitiveValue::create(renderStyle->display())->getStringValue());
893 bool WebAXObject::accessibilityIsIgnored() const
898 return m_private->accessibilityIsIgnored();
901 bool WebAXObject::lineBreaks(WebVector<int>& result) const
906 Vector<int> lineBreaksVector;
907 m_private->lineBreaks(lineBreaksVector);
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);
918 unsigned WebAXObject::columnCount() const
923 if (!m_private->isAXTable())
926 return toAXTable(m_private.get())->columnCount();
929 unsigned WebAXObject::rowCount() const
934 if (!m_private->isAXTable())
937 return toAXTable(m_private.get())->rowCount();
940 WebAXObject WebAXObject::cellForColumnAndRow(unsigned column, unsigned row) const
943 return WebAXObject();
945 if (!m_private->isAXTable())
946 return WebAXObject();
948 AXTableCell* cell = toAXTable(m_private.get())->cellForColumnAndRow(column, row);
949 return WebAXObject(static_cast<AXObject*>(cell));
952 WebAXObject WebAXObject::headerContainerObject() const
955 return WebAXObject();
957 if (!m_private->isAXTable())
958 return WebAXObject();
960 return WebAXObject(toAXTable(m_private.get())->headerContainer());
963 WebAXObject WebAXObject::rowAtIndex(unsigned rowIndex) const
966 return WebAXObject();
968 if (!m_private->isAXTable())
969 return WebAXObject();
971 const AXObject::AccessibilityChildrenVector& rows = toAXTable(m_private.get())->rows();
972 if (rowIndex < rows.size())
973 return WebAXObject(rows[rowIndex]);
975 return WebAXObject();
978 WebAXObject WebAXObject::columnAtIndex(unsigned columnIndex) const
981 return WebAXObject();
983 if (!m_private->isAXTable())
984 return WebAXObject();
986 const AXObject::AccessibilityChildrenVector& columns = toAXTable(m_private.get())->columns();
987 if (columnIndex < columns.size())
988 return WebAXObject(columns[columnIndex]);
990 return WebAXObject();
993 unsigned WebAXObject::rowIndex() const
998 if (!m_private->isTableRow())
1001 return toAXTableRow(m_private.get())->rowIndex();
1004 WebAXObject WebAXObject::rowHeader() const
1007 return WebAXObject();
1009 if (!m_private->isTableRow())
1010 return WebAXObject();
1012 return WebAXObject(toAXTableRow(m_private.get())->headerObject());
1015 unsigned WebAXObject::columnIndex() const
1020 if (m_private->roleValue() != ColumnRole)
1023 return toAXTableColumn(m_private.get())->columnIndex();
1026 WebAXObject WebAXObject::columnHeader() const
1029 return WebAXObject();
1031 if (m_private->roleValue() != ColumnRole)
1032 return WebAXObject();
1034 return WebAXObject(toAXTableColumn(m_private.get())->headerObject());
1037 unsigned WebAXObject::cellColumnIndex() const
1042 if (!m_private->isTableCell())
1045 pair<unsigned, unsigned> columnRange;
1046 toAXTableCell(m_private.get())->columnIndexRange(columnRange);
1047 return columnRange.first;
1050 unsigned WebAXObject::cellColumnSpan() const
1055 if (!m_private->isTableCell())
1058 pair<unsigned, unsigned> columnRange;
1059 toAXTableCell(m_private.get())->columnIndexRange(columnRange);
1060 return columnRange.second;
1063 unsigned WebAXObject::cellRowIndex() const
1068 if (!m_private->isTableCell())
1071 pair<unsigned, unsigned> rowRange;
1072 toAXTableCell(m_private.get())->rowIndexRange(rowRange);
1073 return rowRange.first;
1076 unsigned WebAXObject::cellRowSpan() const
1081 if (!m_private->isTableCell())
1084 pair<unsigned, unsigned> rowRange;
1085 toAXTableCell(m_private.get())->rowIndexRange(rowRange);
1086 return rowRange.second;
1089 WebAXTextDirection WebAXObject::textDirection() const
1092 return WebAXTextDirectionLR;
1094 return static_cast<WebAXTextDirection>(m_private->textDirection());
1097 void WebAXObject::characterOffsets(WebVector<int>& offsets) const
1102 Vector<int> offsetsVector;
1103 m_private->textCharacterOffsets(offsetsVector);
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);
1112 void WebAXObject::wordBoundaries(WebVector<int>& starts, WebVector<int>& ends) const
1117 Vector<AXObject::PlainTextRange> words;
1118 m_private->wordBoundaries(words);
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;
1126 starts.swap(startsWebVector);
1127 ends.swap(endsWebVector);
1130 void WebAXObject::scrollToMakeVisible() const
1133 m_private->scrollToMakeVisible();
1136 void WebAXObject::scrollToMakeVisibleWithSubFocus(const WebRect& subfocus) const
1139 m_private->scrollToMakeVisibleWithSubFocus(subfocus);
1142 void WebAXObject::scrollToGlobalPoint(const WebPoint& point) const
1145 m_private->scrollToGlobalPoint(point);
1148 WebAXObject::WebAXObject(const WTF::PassRefPtr<AXObject>& object)
1153 WebAXObject& WebAXObject::operator=(const WTF::PassRefPtr<AXObject>& object)
1159 WebAXObject::operator WTF::PassRefPtr<AXObject>() const
1161 return m_private.get();
1164 } // namespace blink