Index: Source/modules/accessibility/AXObject.cpp |
=================================================================== |
--- Source/modules/accessibility/AXObject.cpp (revision 191329) |
+++ Source/modules/accessibility/AXObject.cpp (working copy) |
@@ -40,6 +40,7 @@ |
#include "modules/accessibility/AXObjectCacheImpl.h" |
#include "platform/UserGestureIndicator.h" |
#include "platform/text/PlatformLocale.h" |
+#include "wtf/HashSet.h" |
#include "wtf/StdLibExtras.h" |
#include "wtf/text/WTFString.h" |
@@ -51,6 +52,7 @@ |
namespace { |
typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap; |
+typedef HashSet<String, CaseFoldingHash> ARIAWidgetSet; |
struct RoleEntry { |
const char* ariaRole; |
@@ -157,6 +159,68 @@ |
return roleNameVector; |
} |
+const char* ariaWidgets[] = { |
+ // From http://www.w3.org/TR/wai-aria/roles#widget_roles |
+ "alert", |
+ "alertdialog", |
+ "button", |
+ "checkbox", |
+ "dialog", |
+ "gridcell", |
+ "link", |
+ "log", |
+ "marquee", |
+ "menuitem", |
+ "menuitemcheckbox", |
+ "menuitemradio", |
+ "option", |
+ "progressbar", |
+ "radio", |
+ "scrollbar", |
+ "slider", |
+ "spinbutton", |
+ "status", |
+ "tab", |
+ "tabpanel", |
+ "textbox", |
+ "timer", |
+ "tooltip", |
+ "treeitem", |
+ // Composite user interface widgets. This list is also from w3.org site refrerenced above. |
+ "combobox", |
+ "grid", |
+ "listbox", |
+ "menu", |
+ "menubar", |
+ "radiogroup", |
+ "tablist", |
+ "tree", |
+ "treegrid" |
+}; |
+ |
+static ARIAWidgetSet* createARIARoleWidgetSet() |
+{ |
+ ARIAWidgetSet* widgetSet = new HashSet<String, CaseFoldingHash>(); |
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(ariaWidgets); ++i) |
+ widgetSet->add(String(ariaWidgets[i])); |
+ return widgetSet; |
+} |
+ |
+const char* ariaInteractiveWidgetAttributes[] = { |
+ // These attributes implicitly indicate the given widget is interactive. |
+ // From http://www.w3.org/TR/wai-aria/states_and_properties#attrs_widgets |
+ "aria-activedescendant", |
+ "aria-checked", |
+ "aria-controls", |
+ "aria-disabled", // If it's disabled, it can be made interactive. |
+ "aria-expanded", |
+ "aria-haspopup", |
+ "aria-multiselectable", |
+ "aria-pressed", |
+ "aria-required", |
+ "aria-selected" |
+}; |
+ |
} // namespace |
AXObject::AXObject(AXObjectCacheImpl* axObjectCache) |
@@ -993,6 +1057,51 @@ |
return role; |
} |
+bool AXObject::isInsideFocusableElementOrARIAWidget(const Node& node) |
+{ |
+ const Node* curNode = &node; |
+ do { |
+ if (curNode->isElementNode()) { |
+ const Element* element = toElement(curNode); |
+ if (element->isFocusable()) |
+ return true; |
+ String role = element->getAttribute("role"); |
+ if (!role.isEmpty() && AXObject::includesARIAWidgetRole(role)) |
+ return true; |
+ if (hasInteractiveARIAAttribute(*element)) |
+ return true; |
+ } |
+ curNode = curNode->parentNode(); |
+ } while (curNode && !isHTMLBodyElement(node)); |
+ return false; |
+} |
+ |
+bool AXObject::hasInteractiveARIAAttribute(const Element& element) |
+{ |
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(ariaInteractiveWidgetAttributes); ++i) { |
+ const char* attribute = ariaInteractiveWidgetAttributes[i]; |
+ if (element.hasAttribute(attribute)) { |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+bool AXObject::includesARIAWidgetRole(const String& role) |
+{ |
+ static const HashSet<String, CaseFoldingHash>* roleSet = createARIARoleWidgetSet(); |
+ |
+ Vector<String> roleVector; |
+ role.split(' ', roleVector); |
+ unsigned size = roleVector.size(); |
+ for (unsigned i = 0; i < size; ++i) { |
+ String roleName = roleVector[i]; |
+ if (roleSet->contains(roleName)) |
+ return true; |
+ } |
+ return false; |
+} |
+ |
AccessibilityRole AXObject::buttonRoleType() const |
{ |
// If aria-pressed is present, then it should be exposed as a toggle button. |