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/AXObjectCache.h"
33 #include "core/dom/NodeTraversal.h"
34 #include "core/editing/VisibleUnits.h"
35 #include "core/editing/htmlediting.h"
36 #include "core/frame/Frame.h"
37 #include "core/rendering/RenderListItem.h"
38 #include "core/rendering/RenderTheme.h"
39 #include "core/rendering/RenderView.h"
40 #include "platform/UserGestureIndicator.h"
41 #include "platform/text/PlatformLocale.h"
42 #include "wtf/StdLibExtras.h"
43 #include "wtf/text/WTFString.h"
45 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 },
73 { "grid", TableRole },
74 { "gridcell", CellRole },
75 { "columnheader", ColumnHeaderRole },
76 { "combobox", ComboBoxRole },
77 { "definition", DefinitionRole },
78 { "document", DocumentRole },
79 { "rowheader", RowHeaderRole },
80 { "group", GroupRole },
81 { "heading", HeadingRole },
85 { "listitem", ListItemRole },
86 { "listbox", ListBoxRole },
88 // "option" isn't here because it may map to different roles depending on the parent element's role
90 { "marquee", MarqueeRole },
93 { "menubar", MenuBarRole },
94 { "menuitem", MenuItemRole },
95 { "menuitemcheckbox", MenuItemRole },
96 { "menuitemradio", MenuItemRole },
98 { "navigation", NavigationRole },
99 { "option", ListBoxOptionRole },
100 { "presentation", PresentationalRole },
101 { "progressbar", ProgressIndicatorRole },
102 { "radio", RadioButtonRole },
103 { "radiogroup", RadioGroupRole },
104 { "region", RegionRole },
106 { "scrollbar", ScrollBarRole },
107 { "search", SearchRole },
108 { "separator", SplitterRole },
109 { "slider", SliderRole },
110 { "spinbutton", SpinButtonRole },
111 { "status", StatusRole },
113 { "tablist", TabListRole },
114 { "tabpanel", TabPanelRole },
115 { "text", StaticTextRole },
116 { "textbox", TextAreaRole },
117 { "timer", TimerRole },
118 { "toolbar", ToolbarRole },
119 { "tooltip", UserInterfaceTooltipRole },
120 { "tree", TreeRole },
121 { "treegrid", TreeGridRole },
122 { "treeitem", TreeItemRole }
124 ARIARoleMap* roleMap = new ARIARoleMap;
126 for (size_t i = 0; i < WTF_ARRAY_LENGTH(roles); ++i)
127 roleMap->set(roles[i].ariaRole, roles[i].webcoreRole);
133 , m_haveChildren(false)
134 , m_role(UnknownRole)
135 , m_lastKnownIsIgnoredValue(DefaultBehavior)
140 AXObject::~AXObject()
142 ASSERT(isDetached());
145 void AXObject::detach()
147 // Clear any children and call detachFromParent on them so that
148 // no children are left with dangling pointers to their parent.
154 bool AXObject::isDetached() const
159 AXObjectCache* AXObject::axObjectCache() const
161 Document* doc = document();
163 return doc->axObjectCache();
167 void AXObject::updateBackingStore()
169 // Updating the layout may delete this object.
170 if (Document* document = this->document())
171 document->updateLayoutIgnorePendingStylesheets();
174 bool AXObject::isARIATextControl() const
176 return ariaRoleAttribute() == TextAreaRole || ariaRoleAttribute() == TextFieldRole;
179 bool AXObject::isButton() const
181 AccessibilityRole role = roleValue();
183 return role == ButtonRole || role == PopUpButtonRole || role == ToggleButtonRole;
186 bool AXObject::isLandmarkRelated() const
188 switch (roleValue()) {
189 case ApplicationRole:
192 case ComplementaryRole:
193 case ContentInfoRole:
205 bool AXObject::isMenuRelated() const
207 switch (roleValue()) {
218 bool AXObject::isTextControl() const
220 switch (roleValue()) {
230 bool AXObject::isClickable() const
232 switch (roleValue()) {
237 case EditableTextRole:
238 case ImageMapLinkRole:
240 case ListBoxOptionRole:
242 case PopUpButtonRole:
243 case RadioButtonRole:
247 case ToggleButtonRole:
254 bool AXObject::isExpanded() const
256 if (equalIgnoringCase(getAttribute(aria_expandedAttr), "true"))
262 bool AXObject::accessibilityIsIgnored() const
264 AXComputedObjectAttributeCache* attributeCache = axObjectCache()->computedObjectAttributeCache();
265 if (attributeCache) {
266 AXObjectInclusion ignored = attributeCache->getIgnored(axObjectID());
272 case DefaultBehavior:
277 bool result = computeAccessibilityIsIgnored();
280 attributeCache->setIgnored(axObjectID(), result ? IgnoreObject : IncludeObject);
285 bool AXObject::accessibilityIsIgnoredByDefault() const
287 return defaultObjectInclusion() == IgnoreObject;
290 AXObjectInclusion AXObject::accessibilityPlatformIncludesObject() const
292 if (isMenuListPopup() || isMenuListOption())
293 return IncludeObject;
295 return DefaultBehavior;
298 AXObjectInclusion AXObject::defaultObjectInclusion() const
300 if (isInertOrAriaHidden())
303 if (isPresentationalChildOfAriaRole())
306 return accessibilityPlatformIncludesObject();
309 bool AXObject::isInertOrAriaHidden() const
311 bool mightBeInInertSubtree = true;
312 for (const AXObject* object = this; object; object = object->parentObject()) {
313 if (equalIgnoringCase(object->getAttribute(aria_hiddenAttr), "true"))
315 if (mightBeInInertSubtree && object->node()) {
316 if (object->node()->isInert())
318 mightBeInInertSubtree = false;
325 bool AXObject::lastKnownIsIgnoredValue()
327 if (m_lastKnownIsIgnoredValue == DefaultBehavior)
328 m_lastKnownIsIgnoredValue = accessibilityIsIgnored() ? IgnoreObject : IncludeObject;
330 return m_lastKnownIsIgnoredValue == IgnoreObject;
333 void AXObject::setLastKnownIsIgnoredValue(bool isIgnored)
335 m_lastKnownIsIgnoredValue = isIgnored ? IgnoreObject : IncludeObject;
338 // Lacking concrete evidence of orientation, horizontal means width > height. vertical is height > width;
339 AccessibilityOrientation AXObject::orientation() const
341 LayoutRect bounds = elementRect();
342 if (bounds.size().width() > bounds.size().height())
343 return AccessibilityOrientationHorizontal;
344 if (bounds.size().height() > bounds.size().width())
345 return AccessibilityOrientationVertical;
347 // A tie goes to horizontal.
348 return AccessibilityOrientationHorizontal;
351 static String queryString(WebLocalizedString::Name name)
353 return Locale::defaultLocale().queryString(name);
356 String AXObject::actionVerb() const
358 // FIXME: Need to add verbs for select elements.
360 switch (roleValue()) {
362 case ToggleButtonRole:
363 return queryString(WebLocalizedString::AXButtonActionVerb);
366 return queryString(WebLocalizedString::AXTextFieldActionVerb);
367 case RadioButtonRole:
368 return queryString(WebLocalizedString::AXRadioButtonActionVerb);
370 return queryString(isChecked() ? WebLocalizedString::AXCheckedCheckBoxActionVerb : WebLocalizedString::AXUncheckedCheckBoxActionVerb);
372 return queryString(WebLocalizedString::AXLinkActionVerb);
373 case PopUpButtonRole:
376 case MenuListPopupRole:
380 return emptyString();
384 AccessibilityButtonState AXObject::checkboxOrRadioValue() const
386 // If this is a real checkbox or radio button, AXRenderObject will handle.
387 // If it's an ARIA checkbox or radio, the aria-checked attribute should be used.
389 const AtomicString& result = getAttribute(aria_checkedAttr);
390 if (equalIgnoringCase(result, "true"))
391 return ButtonStateOn;
392 if (equalIgnoringCase(result, "mixed"))
393 return ButtonStateMixed;
395 return ButtonStateOff;
398 const AtomicString& AXObject::placeholderValue() const
400 const AtomicString& placeholder = getAttribute(placeholderAttr);
401 if (!placeholder.isEmpty())
407 bool AXObject::ariaIsMultiline() const
409 return equalIgnoringCase(getAttribute(aria_multilineAttr), "true");
412 bool AXObject::ariaPressedIsPresent() const
414 return !getAttribute(aria_pressedAttr).isEmpty();
417 const AtomicString& AXObject::invalidStatus() const
419 DEFINE_STATIC_LOCAL(const AtomicString, invalidStatusFalse, ("false", AtomicString::ConstructFromLiteral));
421 // aria-invalid can return false (default), grammer, spelling, or true.
422 const AtomicString& ariaInvalid = getAttribute(aria_invalidAttr);
424 // If empty or not present, it should return false.
425 if (ariaInvalid.isEmpty())
426 return invalidStatusFalse;
431 bool AXObject::supportsARIAAttributes() const
433 return supportsARIALiveRegion()
434 || supportsARIADragging()
435 || supportsARIADropping()
436 || supportsARIAFlowTo()
437 || supportsARIAOwns()
438 || hasAttribute(aria_labelAttr);
441 bool AXObject::supportsRangeValue() const
443 return isProgressIndicator()
449 void AXObject::ariaTreeRows(AccessibilityChildrenVector& result)
451 AccessibilityChildrenVector axChildren = children();
452 unsigned count = axChildren.size();
453 for (unsigned k = 0; k < count; ++k) {
454 AXObject* obj = axChildren[k].get();
456 // Add tree items as the rows.
457 if (obj->roleValue() == TreeItemRole)
460 // Now see if this item also has rows hiding inside of it.
461 obj->ariaTreeRows(result);
465 bool AXObject::supportsARIALiveRegion() const
467 const AtomicString& liveRegion = ariaLiveRegionStatus();
468 return equalIgnoringCase(liveRegion, "polite") || equalIgnoringCase(liveRegion, "assertive");
471 void AXObject::markCachedElementRectDirty() const
473 for (unsigned i = 0; i < m_children.size(); ++i)
474 m_children[i].get()->markCachedElementRectDirty();
477 IntPoint AXObject::clickPoint()
479 LayoutRect rect = elementRect();
480 return roundedIntPoint(LayoutPoint(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2));
483 IntRect AXObject::boundingBoxForQuads(RenderObject* obj, const Vector<FloatQuad>& quads)
489 size_t count = quads.size();
494 for (size_t i = 0; i < count; ++i) {
495 IntRect r = quads[i].enclosingBoundingBox();
497 if (obj->style()->hasAppearance())
498 RenderTheme::theme().adjustRepaintRect(obj, r);
505 AXObject* AXObject::elementAccessibilityHitTest(const IntPoint& point) const
507 // Send the hit test back into the sub-frame if necessary.
508 if (isAttachment()) {
509 Widget* widget = widgetForAttachmentView();
510 // Normalize the point for the widget's bounds.
511 if (widget && widget->isFrameView())
512 return axObjectCache()->getOrCreate(widget)->accessibilityHitTest(IntPoint(point - widget->frameRect().location()));
515 // Check if there are any mock elements that need to be handled.
516 size_t count = m_children.size();
517 for (size_t k = 0; k < count; k++) {
518 if (m_children[k]->isMockObject() && m_children[k]->elementRect().contains(point))
519 return m_children[k]->elementAccessibilityHitTest(point);
522 return const_cast<AXObject*>(this);
525 const AXObject::AccessibilityChildrenVector& AXObject::children()
527 updateChildrenIfNecessary();
532 AXObject* AXObject::parentObjectUnignored() const
535 for (parent = parentObject(); parent && parent->accessibilityIsIgnored(); parent = parent->parentObject()) {
541 AXObject* AXObject::firstAccessibleObjectFromNode(const Node* node)
546 AXObjectCache* cache = node->document().axObjectCache();
547 AXObject* accessibleObject = cache->getOrCreate(node->renderer());
548 while (accessibleObject && accessibleObject->accessibilityIsIgnored()) {
549 node = NodeTraversal::next(*node);
551 while (node && !node->renderer())
552 node = NodeTraversal::nextSkippingChildren(*node);
557 accessibleObject = cache->getOrCreate(node->renderer());
560 return accessibleObject;
563 void AXObject::updateChildrenIfNecessary()
569 void AXObject::clearChildren()
571 // Some objects have weak pointers to their parents and those associations need to be detached.
572 size_t length = m_children.size();
573 for (size_t i = 0; i < length; i++)
574 m_children[i]->detachFromParent();
577 m_haveChildren = false;
580 AXObject* AXObject::focusedUIElement() const
582 Document* doc = document();
586 Page* page = doc->page();
590 return AXObjectCache::focusedUIElementForPage(page);
593 Document* AXObject::document() const
595 FrameView* frameView = documentFrameView();
599 return frameView->frame().document();
602 FrameView* AXObject::documentFrameView() const
604 const AXObject* object = this;
605 while (object && !object->isAXRenderObject())
606 object = object->parentObject();
611 return object->documentFrameView();
614 String AXObject::language() const
616 const AtomicString& lang = getAttribute(langAttr);
620 AXObject* parent = parentObject();
622 // as a last resort, fall back to the content language specified in the meta tag
624 Document* doc = document();
626 return doc->contentLanguage();
630 return parent->language();
633 bool AXObject::hasAttribute(const QualifiedName& attribute) const
635 Node* elementNode = node();
639 if (!elementNode->isElementNode())
642 Element* element = toElement(elementNode);
643 return element->fastHasAttribute(attribute);
646 const AtomicString& AXObject::getAttribute(const QualifiedName& attribute) const
648 Node* elementNode = node();
652 if (!elementNode->isElementNode())
655 Element* element = toElement(elementNode);
656 return element->fastGetAttribute(attribute);
659 bool AXObject::press() const
661 Element* actionElem = actionElement();
664 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture);
665 actionElem->accessKeyAction(true);
669 void AXObject::scrollToMakeVisible() const
671 IntRect objectRect = pixelSnappedIntRect(elementRect());
672 objectRect.setLocation(IntPoint());
673 scrollToMakeVisibleWithSubFocus(objectRect);
676 // This is a 1-dimensional scroll offset helper function that's applied
677 // separately in the horizontal and vertical directions, because the
678 // logic is the same. The goal is to compute the best scroll offset
679 // in order to make an object visible within a viewport.
681 // In case the whole object cannot fit, you can specify a
682 // subfocus - a smaller region within the object that should
683 // be prioritized. If the whole object can fit, the subfocus is
686 // Example: the viewport is scrolled to the right just enough
687 // that the object is in view.
689 // +----------Viewport---------+
694 // +----------Viewport---------+
698 // When constraints cannot be fully satisfied, the min
699 // (left/top) position takes precedence over the max (right/bottom).
701 // Note that the return value represents the ideal new scroll offset.
702 // This may be out of range - the calling function should clip this
703 // to the available range.
704 static int computeBestScrollOffset(int currentScrollOffset, int subfocusMin, int subfocusMax, int objectMin, int objectMax, int viewportMin, int viewportMax)
706 int viewportSize = viewportMax - viewportMin;
708 // If the focus size is larger than the viewport size, shrink it in the
709 // direction of subfocus.
710 if (objectMax - objectMin > viewportSize) {
711 // Subfocus must be within focus:
712 subfocusMin = std::max(subfocusMin, objectMin);
713 subfocusMax = std::min(subfocusMax, objectMax);
715 // Subfocus must be no larger than the viewport size; favor top/left.
716 if (subfocusMax - subfocusMin > viewportSize)
717 subfocusMax = subfocusMin + viewportSize;
719 if (subfocusMin + viewportSize > objectMax) {
720 objectMin = objectMax - viewportSize;
722 objectMin = subfocusMin;
723 objectMax = subfocusMin + viewportSize;
727 // Exit now if the focus is already within the viewport.
728 if (objectMin - currentScrollOffset >= viewportMin
729 && objectMax - currentScrollOffset <= viewportMax)
730 return currentScrollOffset;
732 // Scroll left if we're too far to the right.
733 if (objectMax - currentScrollOffset > viewportMax)
734 return objectMax - viewportMax;
736 // Scroll right if we're too far to the left.
737 if (objectMin - currentScrollOffset < viewportMin)
738 return objectMin - viewportMin;
740 ASSERT_NOT_REACHED();
742 // This shouldn't happen.
743 return currentScrollOffset;
746 void AXObject::scrollToMakeVisibleWithSubFocus(const IntRect& subfocus) const
748 // Search up the parent chain until we find the first one that's scrollable.
749 AXObject* scrollParent = parentObject();
750 ScrollableArea* scrollableArea;
751 for (scrollableArea = 0;
752 scrollParent && !(scrollableArea = scrollParent->getScrollableAreaIfScrollable());
753 scrollParent = scrollParent->parentObject()) { }
757 LayoutRect objectRect = elementRect();
758 IntPoint scrollPosition = scrollableArea->scrollPosition();
759 IntRect scrollVisibleRect = scrollableArea->visibleContentRect();
761 int desiredX = computeBestScrollOffset(
763 objectRect.x() + subfocus.x(), objectRect.x() + subfocus.maxX(),
764 objectRect.x(), objectRect.maxX(),
765 0, scrollVisibleRect.width());
766 int desiredY = computeBestScrollOffset(
768 objectRect.y() + subfocus.y(), objectRect.y() + subfocus.maxY(),
769 objectRect.y(), objectRect.maxY(),
770 0, scrollVisibleRect.height());
772 scrollParent->scrollTo(IntPoint(desiredX, desiredY));
774 // Recursively make sure the scroll parent itself is visible.
775 if (scrollParent->parentObject())
776 scrollParent->scrollToMakeVisible();
779 void AXObject::scrollToGlobalPoint(const IntPoint& globalPoint) const
781 // Search up the parent chain and create a vector of all scrollable parent objects
782 // and ending with this object itself.
783 Vector<const AXObject*> objects;
784 AXObject* parentObject;
785 for (parentObject = this->parentObject(); parentObject; parentObject = parentObject->parentObject()) {
786 if (parentObject->getScrollableAreaIfScrollable())
787 objects.prepend(parentObject);
789 objects.append(this);
791 // Start with the outermost scrollable (the main window) and try to scroll the
792 // next innermost object to the given point.
793 int offsetX = 0, offsetY = 0;
794 IntPoint point = globalPoint;
795 size_t levels = objects.size() - 1;
796 for (size_t i = 0; i < levels; i++) {
797 const AXObject* outer = objects[i];
798 const AXObject* inner = objects[i + 1];
800 ScrollableArea* scrollableArea = outer->getScrollableAreaIfScrollable();
802 LayoutRect innerRect = inner->isAXScrollView() ? inner->parentObject()->elementRect() : inner->elementRect();
803 LayoutRect objectRect = innerRect;
804 IntPoint scrollPosition = scrollableArea->scrollPosition();
806 // Convert the object rect into local coordinates.
807 objectRect.move(offsetX, offsetY);
808 if (!outer->isAXScrollView())
809 objectRect.move(scrollPosition.x(), scrollPosition.y());
811 int desiredX = computeBestScrollOffset(
813 objectRect.x(), objectRect.maxX(),
814 objectRect.x(), objectRect.maxX(),
815 point.x(), point.x());
816 int desiredY = computeBestScrollOffset(
818 objectRect.y(), objectRect.maxY(),
819 objectRect.y(), objectRect.maxY(),
820 point.y(), point.y());
821 outer->scrollTo(IntPoint(desiredX, desiredY));
823 if (outer->isAXScrollView() && !inner->isAXScrollView()) {
824 // If outer object we just scrolled is a scroll view (main window or iframe) but the
825 // inner object is not, keep track of the coordinate transformation to apply to
826 // future nested calculations.
827 scrollPosition = scrollableArea->scrollPosition();
828 offsetX -= (scrollPosition.x() + point.x());
829 offsetY -= (scrollPosition.y() + point.y());
830 point.move(scrollPosition.x() - innerRect.x(), scrollPosition.y() - innerRect.y());
831 } else if (inner->isAXScrollView()) {
832 // Otherwise, if the inner object is a scroll view, reset the coordinate transformation.
839 void AXObject::notifyIfIgnoredValueChanged()
841 bool isIgnored = accessibilityIsIgnored();
842 if (lastKnownIsIgnoredValue() != isIgnored) {
843 axObjectCache()->childrenChanged(parentObject());
844 setLastKnownIsIgnoredValue(isIgnored);
848 void AXObject::selectionChanged()
850 if (AXObject* parent = parentObjectIfExists())
851 parent->selectionChanged();
854 int AXObject::lineForPosition(const VisiblePosition& visiblePos) const
856 if (visiblePos.isNull() || !node())
859 // If the position is not in the same editable region as this AX object, return -1.
860 Node* containerNode = visiblePos.deepEquivalent().containerNode();
861 if (!containerNode->containsIncludingShadowDOM(node()) && !node()->containsIncludingShadowDOM(containerNode))
865 VisiblePosition currentVisiblePos = visiblePos;
866 VisiblePosition savedVisiblePos;
868 // move up until we get to the top
869 // FIXME: This only takes us to the top of the rootEditableElement, not the top of the
872 savedVisiblePos = currentVisiblePos;
873 VisiblePosition prevVisiblePos = previousLinePosition(currentVisiblePos, 0, HasEditableAXRole);
874 currentVisiblePos = prevVisiblePos;
876 } while (currentVisiblePos.isNotNull() && !(inSameLine(currentVisiblePos, savedVisiblePos)));
881 bool AXObject::isARIAControl(AccessibilityRole ariaRole)
883 return isARIAInput(ariaRole) || ariaRole == TextAreaRole || ariaRole == ButtonRole
884 || ariaRole == ComboBoxRole || ariaRole == SliderRole;
887 bool AXObject::isARIAInput(AccessibilityRole ariaRole)
889 return ariaRole == RadioButtonRole || ariaRole == CheckBoxRole || ariaRole == TextFieldRole;
892 AccessibilityRole AXObject::ariaRoleToWebCoreRole(const String& value)
894 ASSERT(!value.isEmpty());
896 static const ARIARoleMap* roleMap = createARIARoleMap();
898 Vector<String> roleVector;
899 value.split(' ', roleVector);
900 AccessibilityRole role = UnknownRole;
901 unsigned size = roleVector.size();
902 for (unsigned i = 0; i < size; ++i) {
903 String roleName = roleVector[i];
904 role = roleMap->get(roleName);
912 AccessibilityRole AXObject::buttonRoleType() const
914 // If aria-pressed is present, then it should be exposed as a toggle button.
915 // http://www.w3.org/TR/wai-aria/states_and_properties#aria-pressed
916 if (ariaPressedIsPresent())
917 return ToggleButtonRole;
919 return PopUpButtonRole;
920 // We don't contemplate RadioButtonRole, as it depends on the input
926 } // namespace WebCore