Index: Source/modules/accessibility/AXObject.cpp |
diff --git a/Source/modules/accessibility/AXObject.cpp b/Source/modules/accessibility/AXObject.cpp |
index 301c43574572699b9ae04c7ab1d163555605a9ca..f92a3e37ff0bbd02ad933a8d7052859633def010 100644 |
--- a/Source/modules/accessibility/AXObject.cpp |
+++ b/Source/modules/accessibility/AXObject.cpp |
@@ -40,6 +40,9 @@ |
#include "modules/accessibility/AXObjectCacheImpl.h" |
#include "platform/UserGestureIndicator.h" |
#include "platform/text/PlatformLocale.h" |
+// #include "public/web/WebElement.h" |
+// #include "public/web/WebNode.h" |
+#include "wtf/HashSet.h" |
#include "wtf/StdLibExtras.h" |
#include "wtf/text/WTFString.h" |
@@ -51,6 +54,7 @@ using namespace HTMLNames; |
namespace { |
typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap; |
+typedef HashSet<String, CaseFoldingHash> ARIAWidgetSet; |
struct RoleEntry { |
const char* ariaRole; |
@@ -143,6 +147,68 @@ static Vector<AtomicString>* createRoleNameVector() |
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", // Interactive only if this attribute has a value of "true". |
+ "aria-multiselectable", |
+ "aria-pressed", |
+ "aria-required", |
+ "aria-selected" |
+}; |
+ |
} // namespace |
AXObject::AXObject(AXObjectCacheImpl* axObjectCache) |
@@ -956,6 +1022,53 @@ AccessibilityRole AXObject::ariaRoleToWebCoreRole(const String& value) |
return role; |
} |
+bool AXObject::isARIAWidget(const WebNode& webNode) |
+{ |
+ WebNode curNode = webNode; |
+ do { |
+ if (curNode.isElementNode()) { |
+ const WebElement& element = curNode.toConst<blink::WebElement>(); |
+ if (element.isFocusable()) |
dmazzoni
2015/02/05 00:40:23
It seems odd to check for focusability in a functi
Donn Denman
2015/02/06 22:53:36
I changed the name, thanks for the suggestion!
|
+ 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.isNull() && curNode.nodeName() != "BODY"); |
dmazzoni
2015/02/05 00:40:23
Now that you're inside Blink you can call isHTMLBo
Donn Denman
2015/02/06 22:53:36
Done.
|
+ return false; |
+} |
+ |
+bool AXObject::hasInteractiveARIAAttribute(const WebElement& element) |
+{ |
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(ariaInteractiveWidgetAttributes); ++i) { |
+ const char* attribute = ariaInteractiveWidgetAttributes[i]; |
+ if (element.hasAttribute(WebString::fromUTF8(attribute))) { |
+ if (!strcmp("aria-haspopup", attribute)) |
+ return element.getAttribute(WebString::fromUTF8(attribute)) == "true"; |
+ 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. |