2 * Copyright (C) 2008, 2009, 2011 Apple 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
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.
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.
30 #include "core/accessibility/AXObject.h"
32 #include "core/accessibility/AXObjectCacheImpl.h"
33 #include "core/dom/NodeTraversal.h"
34 #include "core/editing/VisibleUnits.h"
35 #include "core/editing/htmlediting.h"
36 #include "core/frame/LocalFrame.h"
37 #include "core/frame/Settings.h"
38 #include "core/rendering/RenderListItem.h"
39 #include "core/rendering/RenderTheme.h"
40 #include "core/rendering/RenderView.h"
41 #include "platform/UserGestureIndicator.h"
42 #include "platform/text/PlatformLocale.h"
43 #include "wtf/StdLibExtras.h"
44 #include "wtf/text/WTFString.h"
46 using blink::WebLocalizedString;
50 using namespace HTMLNames;
52 typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap;
56 AccessibilityRole webcoreRole;
59 static ARIARoleMap* createARIARoleMap()
61 const RoleEntry roles[] = {
62 { "alert", AlertRole },
63 { "alertdialog", AlertDialogRole },
64 { "application", ApplicationRole },
65 { "article", ArticleRole },
66 { "banner", BannerRole },
67 { "button", ButtonRole },
68 { "checkbox", CheckBoxRole },
69 { "complementary", ComplementaryRole },
70 { "contentinfo", ContentInfoRole },
71 { "dialog", DialogRole },
72 { "directory", DirectoryRole },
74 { "gridcell", CellRole },
75 { "columnheader", ColumnHeaderRole },
76 { "combobox", ComboBoxRole },
77 { "definition", DefinitionRole },
78 { "document", DocumentRole },
79 { "rowheader", RowHeaderRole },
81 { "group", GroupRole },
82 { "heading", HeadingRole },
86 { "listitem", ListItemRole },
87 { "listbox", ListBoxRole },
89 // "option" isn't here because it may map to different roles depending on the parent element's role
91 { "marquee", MarqueeRole },
94 { "menubar", MenuBarRole },
95 { "menuitem", MenuItemRole },
96 { "menuitemcheckbox", MenuItemCheckBoxRole },
97 { "menuitemradio", MenuItemRadioRole },
99 { "navigation", NavigationRole },
100 { "none", NoneRole },
101 { "option", ListBoxOptionRole },
102 { "presentation", PresentationalRole },
103 { "progressbar", ProgressIndicatorRole },
104 { "radio", RadioButtonRole },
105 { "radiogroup", RadioGroupRole },
106 { "region", RegionRole },
108 { "scrollbar", ScrollBarRole },
109 { "search", SearchRole },
110 { "separator", SplitterRole },
111 { "slider", SliderRole },
112 { "spinbutton", SpinButtonRole },
113 { "status", StatusRole },
115 { "tablist", TabListRole },
116 { "tabpanel", TabPanelRole },
117 { "text", StaticTextRole },
118 { "textbox", TextAreaRole },
119 { "timer", TimerRole },
120 { "toolbar", ToolbarRole },
121 { "tooltip", UserInterfaceTooltipRole },
122 { "tree", TreeRole },
123 { "treegrid", TreeGridRole },
124 { "treeitem", TreeItemRole }
126 ARIARoleMap* roleMap = new ARIARoleMap;
128 for (size_t i = 0; i < WTF_ARRAY_LENGTH(roles); ++i)
129 roleMap->set(roles[i].ariaRole, roles[i].webcoreRole);
135 , m_haveChildren(false)
136 , m_role(UnknownRole)
137 , m_lastKnownIsIgnoredValue(DefaultBehavior)
140 , m_lastModificationCount(-1)
141 , m_cachedIsIgnored(false)
142 , m_cachedLiveRegionRoot(0)
146 AXObject::~AXObject()
148 ASSERT(isDetached());
151 void AXObject::detach()
153 // Clear any children and call detachFromParent on them so that
154 // no children are left with dangling pointers to their parent.
160 bool AXObject::isDetached() const
165 AXObjectCacheImpl* AXObject::axObjectCache() const
167 Document* doc = document();
169 return toAXObjectCacheImpl(doc->axObjectCache());
173 bool AXObject::isARIATextControl() const
175 return ariaRoleAttribute() == TextAreaRole || ariaRoleAttribute() == TextFieldRole;
178 bool AXObject::isButton() const
180 AccessibilityRole role = roleValue();
182 return role == ButtonRole || role == PopUpButtonRole || role == ToggleButtonRole;
185 bool AXObject::isLandmarkRelated() const
187 switch (roleValue()) {
188 case ApplicationRole:
191 case ComplementaryRole:
192 case ContentInfoRole:
205 bool AXObject::isMenuRelated() const
207 switch (roleValue()) {
212 case MenuItemCheckBoxRole:
213 case MenuItemRadioRole:
220 bool AXObject::isPasswordFieldAndShouldHideValue() const
222 Settings* settings = document()->settings();
223 if (!settings || settings->accessibilityPasswordValuesEnabled())
226 return isPasswordField();
229 bool AXObject::isTextControl() const
231 switch (roleValue()) {
241 bool AXObject::isClickable() const
243 switch (roleValue()) {
248 case EditableTextRole:
249 case ImageMapLinkRole:
251 case ListBoxOptionRole:
253 case PopUpButtonRole:
254 case RadioButtonRole:
258 case ToggleButtonRole:
265 bool AXObject::accessibilityIsIgnored() const
267 updateCachedAttributeValuesIfNeeded();
268 return m_cachedIsIgnored;
271 void AXObject::updateCachedAttributeValuesIfNeeded() const
273 AXObjectCacheImpl* cache = axObjectCache();
277 if (cache->modificationCount() == m_lastModificationCount)
280 m_lastModificationCount = cache->modificationCount();
281 m_cachedIsIgnored = computeAccessibilityIsIgnored();
282 m_cachedLiveRegionRoot = isLiveRegion() ?
284 (parentObjectIfExists() ? parentObjectIfExists()->liveRegionRoot() : 0);
287 bool AXObject::accessibilityIsIgnoredByDefault() const
289 return defaultObjectInclusion() == IgnoreObject;
292 AXObjectInclusion AXObject::accessibilityPlatformIncludesObject() const
294 if (isMenuListPopup() || isMenuListOption())
295 return IncludeObject;
297 return DefaultBehavior;
300 AXObjectInclusion AXObject::defaultObjectInclusion() const
302 if (isInertOrAriaHidden())
305 if (isPresentationalChildOfAriaRole())
308 return accessibilityPlatformIncludesObject();
311 bool AXObject::isInertOrAriaHidden() const
313 bool mightBeInInertSubtree = true;
314 for (const AXObject* object = this; object; object = object->parentObject()) {
315 if (equalIgnoringCase(object->getAttribute(aria_hiddenAttr), "true"))
317 if (mightBeInInertSubtree && object->node()) {
318 if (object->node()->isInert())
320 mightBeInInertSubtree = false;
327 bool AXObject::lastKnownIsIgnoredValue()
329 if (m_lastKnownIsIgnoredValue == DefaultBehavior)
330 m_lastKnownIsIgnoredValue = accessibilityIsIgnored() ? IgnoreObject : IncludeObject;
332 return m_lastKnownIsIgnoredValue == IgnoreObject;
335 void AXObject::setLastKnownIsIgnoredValue(bool isIgnored)
337 m_lastKnownIsIgnoredValue = isIgnored ? IgnoreObject : IncludeObject;
340 // Lacking concrete evidence of orientation, horizontal means width > height. vertical is height > width;
341 AccessibilityOrientation AXObject::orientation() const
343 LayoutRect bounds = elementRect();
344 if (bounds.size().width() > bounds.size().height())
345 return AccessibilityOrientationHorizontal;
346 if (bounds.size().height() > bounds.size().width())
347 return AccessibilityOrientationVertical;
349 // A tie goes to horizontal.
350 return AccessibilityOrientationHorizontal;
353 static String queryString(WebLocalizedString::Name name)
355 return Locale::defaultLocale().queryString(name);
358 String AXObject::actionVerb() const
360 // FIXME: Need to add verbs for select elements.
362 switch (roleValue()) {
364 case ToggleButtonRole:
365 return queryString(WebLocalizedString::AXButtonActionVerb);
368 return queryString(WebLocalizedString::AXTextFieldActionVerb);
369 case RadioButtonRole:
370 return queryString(WebLocalizedString::AXRadioButtonActionVerb);
372 return queryString(isChecked() ? WebLocalizedString::AXCheckedCheckBoxActionVerb : WebLocalizedString::AXUncheckedCheckBoxActionVerb);
374 return queryString(WebLocalizedString::AXLinkActionVerb);
375 case PopUpButtonRole:
378 case MenuListPopupRole:
382 return emptyString();
386 AccessibilityButtonState AXObject::checkboxOrRadioValue() const
388 // If this is a real checkbox or radio button, AXRenderObject will handle.
389 // If it's an ARIA checkbox or radio, the aria-checked attribute should be used.
391 const AtomicString& result = getAttribute(aria_checkedAttr);
392 if (equalIgnoringCase(result, "true"))
393 return ButtonStateOn;
394 if (equalIgnoringCase(result, "mixed"))
395 return ButtonStateMixed;
397 return ButtonStateOff;
400 bool AXObject::ariaIsMultiline() const
402 return equalIgnoringCase(getAttribute(aria_multilineAttr), "true");
405 bool AXObject::ariaPressedIsPresent() const
407 return !getAttribute(aria_pressedAttr).isEmpty();
410 bool AXObject::supportsARIAAttributes() const
412 return isLiveRegion()
413 || supportsARIADragging()
414 || supportsARIADropping()
415 || supportsARIAFlowTo()
416 || supportsARIAOwns()
417 || hasAttribute(aria_labelAttr);
420 bool AXObject::supportsRangeValue() const
422 return isProgressIndicator()
428 void AXObject::ariaTreeRows(AccessibilityChildrenVector& result)
430 AccessibilityChildrenVector axChildren = children();
431 unsigned count = axChildren.size();
432 for (unsigned k = 0; k < count; ++k) {
433 AXObject* obj = axChildren[k].get();
435 // Add tree items as the rows.
436 if (obj->roleValue() == TreeItemRole)
439 // Now see if this item also has rows hiding inside of it.
440 obj->ariaTreeRows(result);
444 bool AXObject::isLiveRegion() const
446 const AtomicString& liveRegion = liveRegionStatus();
447 return equalIgnoringCase(liveRegion, "polite") || equalIgnoringCase(liveRegion, "assertive");
450 const AXObject* AXObject::liveRegionRoot() const
452 updateCachedAttributeValuesIfNeeded();
453 return m_cachedLiveRegionRoot;
456 const AtomicString& AXObject::containerLiveRegionStatus() const
458 updateCachedAttributeValuesIfNeeded();
459 return m_cachedLiveRegionRoot ? m_cachedLiveRegionRoot->liveRegionStatus() : nullAtom;
462 const AtomicString& AXObject::containerLiveRegionRelevant() const
464 updateCachedAttributeValuesIfNeeded();
465 return m_cachedLiveRegionRoot ? m_cachedLiveRegionRoot->liveRegionRelevant() : nullAtom;
468 bool AXObject::containerLiveRegionAtomic() const
470 updateCachedAttributeValuesIfNeeded();
471 return m_cachedLiveRegionRoot ? m_cachedLiveRegionRoot->liveRegionAtomic() : false;
474 bool AXObject::containerLiveRegionBusy() const
476 updateCachedAttributeValuesIfNeeded();
477 return m_cachedLiveRegionRoot ? m_cachedLiveRegionRoot->liveRegionBusy() : false;
480 void AXObject::markCachedElementRectDirty() const
482 for (unsigned i = 0; i < m_children.size(); ++i)
483 m_children[i].get()->markCachedElementRectDirty();
486 IntPoint AXObject::clickPoint()
488 LayoutRect rect = elementRect();
489 return roundedIntPoint(LayoutPoint(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2));
492 IntRect AXObject::boundingBoxForQuads(RenderObject* obj, const Vector<FloatQuad>& quads)
498 size_t count = quads.size();
503 for (size_t i = 0; i < count; ++i) {
504 IntRect r = quads[i].enclosingBoundingBox();
506 if (obj->style()->hasAppearance())
507 RenderTheme::theme().adjustPaintInvalidationRect(obj, r);
514 AXObject* AXObject::elementAccessibilityHitTest(const IntPoint& point) const
516 // Send the hit test back into the sub-frame if necessary.
517 if (isAttachment()) {
518 Widget* widget = widgetForAttachmentView();
519 // Normalize the point for the widget's bounds.
520 if (widget && widget->isFrameView())
521 return axObjectCache()->getOrCreate(widget)->accessibilityHitTest(IntPoint(point - widget->frameRect().location()));
524 // Check if there are any mock elements that need to be handled.
525 size_t count = m_children.size();
526 for (size_t k = 0; k < count; k++) {
527 if (m_children[k]->isMockObject() && m_children[k]->elementRect().contains(point))
528 return m_children[k]->elementAccessibilityHitTest(point);
531 return const_cast<AXObject*>(this);
534 const AXObject::AccessibilityChildrenVector& AXObject::children()
536 updateChildrenIfNecessary();
541 AXObject* AXObject::parentObject() const
549 return computeParent();
552 AXObject* AXObject::parentObjectIfExists() const
560 return computeParentIfExists();
563 AXObject* AXObject::parentObjectUnignored() const
566 for (parent = parentObject(); parent && parent->accessibilityIsIgnored(); parent = parent->parentObject()) {
572 AXObject* AXObject::firstAccessibleObjectFromNode(const Node* node)
577 AXObjectCacheImpl* cache = toAXObjectCacheImpl(node->document().axObjectCache());
578 AXObject* accessibleObject = cache->getOrCreate(node->renderer());
579 while (accessibleObject && accessibleObject->accessibilityIsIgnored()) {
580 node = NodeTraversal::next(*node);
582 while (node && !node->renderer())
583 node = NodeTraversal::nextSkippingChildren(*node);
588 accessibleObject = cache->getOrCreate(node->renderer());
591 return accessibleObject;
594 void AXObject::updateChildrenIfNecessary()
600 void AXObject::clearChildren()
602 // Detach all weak pointers from objects to their parents.
603 size_t length = m_children.size();
604 for (size_t i = 0; i < length; i++)
605 m_children[i]->detachFromParent();
608 m_haveChildren = false;
611 AXObject* AXObject::focusedUIElement() const
613 Document* doc = document();
617 Page* page = doc->page();
621 return AXObjectCacheImpl::focusedUIElementForPage(page);
624 Document* AXObject::document() const
626 FrameView* frameView = documentFrameView();
630 return frameView->frame().document();
633 FrameView* AXObject::documentFrameView() const
635 const AXObject* object = this;
636 while (object && !object->isAXRenderObject())
637 object = object->parentObject();
642 return object->documentFrameView();
645 String AXObject::language() const
647 const AtomicString& lang = getAttribute(langAttr);
651 AXObject* parent = parentObject();
653 // as a last resort, fall back to the content language specified in the meta tag
655 Document* doc = document();
657 return doc->contentLanguage();
661 return parent->language();
664 bool AXObject::hasAttribute(const QualifiedName& attribute) const
666 Node* elementNode = node();
670 if (!elementNode->isElementNode())
673 Element* element = toElement(elementNode);
674 return element->fastHasAttribute(attribute);
677 const AtomicString& AXObject::getAttribute(const QualifiedName& attribute) const
679 Node* elementNode = node();
683 if (!elementNode->isElementNode())
686 Element* element = toElement(elementNode);
687 return element->fastGetAttribute(attribute);
690 bool AXObject::press() const
692 Element* actionElem = actionElement();
695 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture);
696 actionElem->accessKeyAction(true);
700 void AXObject::scrollToMakeVisible() const
702 IntRect objectRect = pixelSnappedIntRect(elementRect());
703 objectRect.setLocation(IntPoint());
704 scrollToMakeVisibleWithSubFocus(objectRect);
707 // This is a 1-dimensional scroll offset helper function that's applied
708 // separately in the horizontal and vertical directions, because the
709 // logic is the same. The goal is to compute the best scroll offset
710 // in order to make an object visible within a viewport.
712 // If the object is already fully visible, returns the same scroll
715 // In case the whole object cannot fit, you can specify a
716 // subfocus - a smaller region within the object that should
717 // be prioritized. If the whole object can fit, the subfocus is
720 // If possible, the object and subfocus are centered within the
723 // Example 1: the object is already visible, so nothing happens.
724 // +----------Viewport---------+
728 // Example 2: the object is not fully visible, so it's centered
729 // within the viewport.
731 // +----------Viewport---------+
736 // +----------Viewport---------+
740 // Example 3: the object is larger than the viewport, so the
741 // viewport moves to show as much of the object as possible,
742 // while also trying to center the subfocus.
744 // +----------Viewport---------+
745 // +---------------Object--------------+
749 // +----------Viewport---------+
750 // +---------------Object--------------+
753 // When constraints cannot be fully satisfied, the min
754 // (left/top) position takes precedence over the max (right/bottom).
756 // Note that the return value represents the ideal new scroll offset.
757 // This may be out of range - the calling function should clip this
758 // to the available range.
759 static int computeBestScrollOffset(int currentScrollOffset, int subfocusMin, int subfocusMax, int objectMin, int objectMax, int viewportMin, int viewportMax)
761 int viewportSize = viewportMax - viewportMin;
763 // If the object size is larger than the viewport size, consider
764 // only a portion that's as large as the viewport, centering on
765 // the subfocus as much as possible.
766 if (objectMax - objectMin > viewportSize) {
767 // Since it's impossible to fit the whole object in the
768 // viewport, exit now if the subfocus is already within the viewport.
769 if (subfocusMin - currentScrollOffset >= viewportMin
770 && subfocusMax - currentScrollOffset <= viewportMax)
771 return currentScrollOffset;
773 // Subfocus must be within focus.
774 subfocusMin = std::max(subfocusMin, objectMin);
775 subfocusMax = std::min(subfocusMax, objectMax);
777 // Subfocus must be no larger than the viewport size; favor top/left.
778 if (subfocusMax - subfocusMin > viewportSize)
779 subfocusMax = subfocusMin + viewportSize;
781 // Compute the size of an object centered on the subfocus, the size of the viewport.
782 int centeredObjectMin = (subfocusMin + subfocusMax - viewportSize) / 2;
783 int centeredObjectMax = centeredObjectMin + viewportSize;
785 objectMin = std::max(objectMin, centeredObjectMin);
786 objectMax = std::min(objectMax, centeredObjectMax);
789 // Exit now if the focus is already within the viewport.
790 if (objectMin - currentScrollOffset >= viewportMin
791 && objectMax - currentScrollOffset <= viewportMax)
792 return currentScrollOffset;
794 // Center the object in the viewport.
795 return (objectMin + objectMax - viewportMin - viewportMax) / 2;
798 void AXObject::scrollToMakeVisibleWithSubFocus(const IntRect& subfocus) const
800 // Search up the parent chain until we find the first one that's scrollable.
801 AXObject* scrollParent = parentObject();
802 ScrollableArea* scrollableArea = 0;
803 while (scrollParent) {
804 scrollableArea = scrollParent->getScrollableAreaIfScrollable();
807 scrollParent = scrollParent->parentObject();
812 IntRect objectRect = pixelSnappedIntRect(elementRect());
813 IntPoint scrollPosition = scrollableArea->scrollPosition();
814 IntRect scrollVisibleRect = scrollableArea->visibleContentRect();
816 int desiredX = computeBestScrollOffset(
818 objectRect.x() + subfocus.x(), objectRect.x() + subfocus.maxX(),
819 objectRect.x(), objectRect.maxX(),
820 0, scrollVisibleRect.width());
821 int desiredY = computeBestScrollOffset(
823 objectRect.y() + subfocus.y(), objectRect.y() + subfocus.maxY(),
824 objectRect.y(), objectRect.maxY(),
825 0, scrollVisibleRect.height());
827 scrollParent->scrollTo(IntPoint(desiredX, desiredY));
829 // Convert the subfocus into the coordinates of the scroll parent.
830 IntRect newSubfocus = subfocus;
831 IntRect newElementRect = pixelSnappedIntRect(elementRect());
832 IntRect scrollParentRect = pixelSnappedIntRect(scrollParent->elementRect());
833 newSubfocus.move(newElementRect.x(), newElementRect.y());
834 newSubfocus.move(-scrollParentRect.x(), -scrollParentRect.y());
836 // Recursively make sure the scroll parent itself is visible.
837 if (scrollParent->parentObject())
838 scrollParent->scrollToMakeVisibleWithSubFocus(newSubfocus);
841 void AXObject::scrollToGlobalPoint(const IntPoint& globalPoint) const
843 // Search up the parent chain and create a vector of all scrollable parent objects
844 // and ending with this object itself.
845 Vector<const AXObject*> objects;
846 AXObject* parentObject;
847 for (parentObject = this->parentObject(); parentObject; parentObject = parentObject->parentObject()) {
848 if (parentObject->getScrollableAreaIfScrollable())
849 objects.prepend(parentObject);
851 objects.append(this);
853 // Start with the outermost scrollable (the main window) and try to scroll the
854 // next innermost object to the given point.
855 int offsetX = 0, offsetY = 0;
856 IntPoint point = globalPoint;
857 size_t levels = objects.size() - 1;
858 for (size_t i = 0; i < levels; i++) {
859 const AXObject* outer = objects[i];
860 const AXObject* inner = objects[i + 1];
862 ScrollableArea* scrollableArea = outer->getScrollableAreaIfScrollable();
864 IntRect innerRect = inner->isAXScrollView() ? pixelSnappedIntRect(inner->parentObject()->elementRect()) : pixelSnappedIntRect(inner->elementRect());
865 IntRect objectRect = innerRect;
866 IntPoint scrollPosition = scrollableArea->scrollPosition();
868 // Convert the object rect into local coordinates.
869 objectRect.move(offsetX, offsetY);
870 if (!outer->isAXScrollView())
871 objectRect.move(scrollPosition.x(), scrollPosition.y());
873 int desiredX = computeBestScrollOffset(
875 objectRect.x(), objectRect.maxX(),
876 objectRect.x(), objectRect.maxX(),
877 point.x(), point.x());
878 int desiredY = computeBestScrollOffset(
880 objectRect.y(), objectRect.maxY(),
881 objectRect.y(), objectRect.maxY(),
882 point.y(), point.y());
883 outer->scrollTo(IntPoint(desiredX, desiredY));
885 if (outer->isAXScrollView() && !inner->isAXScrollView()) {
886 // If outer object we just scrolled is a scroll view (main window or iframe) but the
887 // inner object is not, keep track of the coordinate transformation to apply to
888 // future nested calculations.
889 scrollPosition = scrollableArea->scrollPosition();
890 offsetX -= (scrollPosition.x() + point.x());
891 offsetY -= (scrollPosition.y() + point.y());
892 point.move(scrollPosition.x() - innerRect.x(), scrollPosition.y() - innerRect.y());
893 } else if (inner->isAXScrollView()) {
894 // Otherwise, if the inner object is a scroll view, reset the coordinate transformation.
901 void AXObject::notifyIfIgnoredValueChanged()
903 bool isIgnored = accessibilityIsIgnored();
904 if (lastKnownIsIgnoredValue() != isIgnored) {
905 axObjectCache()->childrenChanged(parentObject());
906 setLastKnownIsIgnoredValue(isIgnored);
910 void AXObject::selectionChanged()
912 if (AXObject* parent = parentObjectIfExists())
913 parent->selectionChanged();
916 int AXObject::lineForPosition(const VisiblePosition& visiblePos) const
918 if (visiblePos.isNull() || !node())
921 // If the position is not in the same editable region as this AX object, return -1.
922 Node* containerNode = visiblePos.deepEquivalent().containerNode();
923 if (!containerNode->containsIncludingShadowDOM(node()) && !node()->containsIncludingShadowDOM(containerNode))
927 VisiblePosition currentVisiblePos = visiblePos;
928 VisiblePosition savedVisiblePos;
930 // move up until we get to the top
931 // FIXME: This only takes us to the top of the rootEditableElement, not the top of the
934 savedVisiblePos = currentVisiblePos;
935 VisiblePosition prevVisiblePos = previousLinePosition(currentVisiblePos, 0, HasEditableAXRole);
936 currentVisiblePos = prevVisiblePos;
938 } while (currentVisiblePos.isNotNull() && !(inSameLine(currentVisiblePos, savedVisiblePos)));
943 bool AXObject::isARIAControl(AccessibilityRole ariaRole)
945 return isARIAInput(ariaRole) || ariaRole == TextAreaRole || ariaRole == ButtonRole
946 || ariaRole == ComboBoxRole || ariaRole == SliderRole;
949 bool AXObject::isARIAInput(AccessibilityRole ariaRole)
951 return ariaRole == RadioButtonRole || ariaRole == CheckBoxRole || ariaRole == TextFieldRole;
954 AccessibilityRole AXObject::ariaRoleToWebCoreRole(const String& value)
956 ASSERT(!value.isEmpty());
958 static const ARIARoleMap* roleMap = createARIARoleMap();
960 Vector<String> roleVector;
961 value.split(' ', roleVector);
962 AccessibilityRole role = UnknownRole;
963 unsigned size = roleVector.size();
964 for (unsigned i = 0; i < size; ++i) {
965 String roleName = roleVector[i];
966 role = roleMap->get(roleName);
974 AccessibilityRole AXObject::buttonRoleType() const
976 // If aria-pressed is present, then it should be exposed as a toggle button.
977 // http://www.w3.org/TR/wai-aria/states_and_properties#aria-pressed
978 if (ariaPressedIsPresent())
979 return ToggleButtonRole;
981 return PopUpButtonRole;
982 // We don't contemplate RadioButtonRole, as it depends on the input