https://bugs.webkit.org/show_bug.cgi?id=32100
Reviewed by Beth Dakin.
WebCore:
Fixes a number of issues regarding the "tree" role and aria-activedescendant.
1. The indexes were being reported incorrectly by treeitems.
2. aria-activedescendant changes were not being sent to the containing item.
3. The tree's selected rows need to consult aria-activedescendant.
4. Since a tree changes what it returns as its children (it returns its rows)
the mac-specific array indexing methods need to correctly handle the tree case.
Tests: platform/mac/accessibility/aria-tree-activedescendant.html
platform/mac/accessibility/aria-tree-index-of-items.html
* accessibility/AXObjectCache.h:
(WebCore::AXObjectCache::):
* accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::shouldFocusActiveDescendant):
(WebCore::AccessibilityRenderObject::activeDescendant):
(WebCore::AccessibilityRenderObject::handleActiveDescendantChanged):
(WebCore::AccessibilityRenderObject::ariaTreeSelectedRows):
* accessibility/mac/AXObjectCacheMac.mm:
(WebCore::AXObjectCache::postPlatformNotification):
* accessibility/mac/AccessibilityObjectWrapper.mm:
(-[AccessibilityObjectWrapper accessibilityAttributeValue:]):
(-[AccessibilityObjectWrapper accessibilityIndexOfChild:]):
(-[AccessibilityObjectWrapper accessibilityArrayAttributeValues:index:maxCount:]):
* accessibility/win/AXObjectCacheWin.cpp:
(WebCore::AXObjectCache::postPlatformNotification):
LayoutTests:
* platform/mac/accessibility/aria-tree-activedescendant-expected.txt: Added.
* platform/mac/accessibility/aria-tree-activedescendant.html: Added.
* platform/mac/accessibility/aria-tree-index-of-items-expected.txt: Added.
* platform/mac/accessibility/aria-tree-index-of-items.html: Added.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@51684
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2009-12-03 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ WAI-ARIA: aria-activedescendant doesn't work as intended
+ https://bugs.webkit.org/show_bug.cgi?id=32100
+
+ * platform/mac/accessibility/aria-tree-activedescendant-expected.txt: Added.
+ * platform/mac/accessibility/aria-tree-activedescendant.html: Added.
+ * platform/mac/accessibility/aria-tree-index-of-items-expected.txt: Added.
+ * platform/mac/accessibility/aria-tree-index-of-items.html: Added.
+
2009-12-03 Chris Fleizach <cfleizach@apple.com>
Fixing layout test bustage on platforms.
--- /dev/null
+Animals
+Birds
+Cats
+Siamese
+Tabby
+This tests that the ARIA drag and drop attributes work as intended.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS axtree.selectedRowAtIndex(0).isEqual(activeDescendant) is true
+PASS axtree.selectedRowAtIndex(0).isEqual(newActiveDescendant) is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../../../fast/js/resources/js-test-style.css">
+<script>
+var successfullyParsed = false;
+</script>
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body id="body">
+
+<ul id="tree0" role="tree" aria-labelledby="treelabel" aria-activedescendant="tree0_item0" tabindex="0">
+<li id="tree0_item0" role="treeitem" aria-level="1" aria-expanded="true">
+<span><span class="expander"></span>Animals</span>
+<ul role="group">
+<li id="tree0_item0_0" role="treeitem" aria-level="2"><span>Birds</span></li>
+<li id="tree0_item0_1" role="treeitem" aria-level="2" aria-expanded="false">
+<span><span class="expander"></span>Cats</span>
+<ul role="group">
+<li id="tree0_item0_1_0" role="treeitem"aria-level="3"><span>Siamese</span></li>
+<li id="tree0_item0_1_1" role="treeitem" aria-level="3"><span>Tabby</span></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+
+ description("This tests that the ARIA drag and drop attributes work as intended.");
+
+ if (window.accessibilityController) {
+
+ var axtree = accessibilityController.rootElement.childAtIndex(0).childAtIndex(0);
+
+ var activeDescendant = axtree.childAtIndex(0);
+ shouldBe("axtree.selectedRowAtIndex(0).isEqual(activeDescendant)", "true");
+
+ var newActiveDescendant = axtree.childAtIndex(2);
+ document.getElementById("tree0").setAttribute("aria-activedescendant", "tree0_item0_1");
+
+ shouldBe("axtree.selectedRowAtIndex(0).isEqual(newActiveDescendant)", "true");
+ }
+
+ successfullyParsed = true;
+</script>
+
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+Animals
+Birds
+Cats
+Siamese
+Tabby
+This tests that the index attribute is correctly returned for all tree items, regardless of their hierarchical level.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS axtree.selectedRowAtIndex(0).indexInTable() is 0
+PASS axtree.selectedRowAtIndex(1).indexInTable() is 1
+PASS axtree.selectedRowAtIndex(2).indexInTable() is 2
+PASS axtree.selectedRowAtIndex(3).indexInTable() is 3
+PASS axtree.selectedRowAtIndex(4).indexInTable() is 4
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../../../fast/js/resources/js-test-style.css">
+<script>
+var successfullyParsed = false;
+</script>
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body id="body">
+
+<ul id="tree0" role="tree" aria-labelledby="treelabel" aria-multiselectable="true" tabindex="0">
+ <li id="tree0_item0" role="treeitem" aria-level="1" aria-selected="true" aria-expanded="true"><span>
+ <span class="expander"></span>Animals</span>
+ <ul role="group">
+ <li id="tree0_item0_0" aria-selected="true" role="treeitem" aria-level="2"><span>Birds</span></li>
+ <li id="tree0_item0_1" aria-selected="true" role="treeitem" aria-level="2" aria-expanded="false">
+ <span><span class="expander"></span>Cats</span>
+ <ul role="group">
+ <li id="tree0_item0_1_0" aria-selected="true" role="treeitem"aria-level="3"><span>Siamese</span></li>
+ <li id="tree0_item0_1_1" aria-selected="true" role="treeitem" aria-level="3"><span>Tabby</span></li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+
+ description("This tests that the index attribute is correctly returned for all tree items, regardless of their hierarchical level.");
+
+ if (window.accessibilityController) {
+
+ var tree = document.getElementById("tree0");
+ tree.focus();
+ var axtree = accessibilityController.focusedElement;
+
+ tree.setAttribute("activedescendant", "tree0_item0");
+ shouldBe("axtree.selectedRowAtIndex(0).indexInTable()", "0");
+
+ tree.setAttribute("activedescendant", "tree0_item0_0");
+ shouldBe("axtree.selectedRowAtIndex(1).indexInTable()", "1");
+
+ tree.setAttribute("activedescendant", "tree0_item0_1");
+ shouldBe("axtree.selectedRowAtIndex(2).indexInTable()", "2");
+
+ tree.setAttribute("activedescendant", "tree0_item0_1_0");
+ shouldBe("axtree.selectedRowAtIndex(3).indexInTable()", "3");
+
+ tree.setAttribute("activedescendant", "tree0_item0_1_1");
+ shouldBe("axtree.selectedRowAtIndex(4).indexInTable()", "4");
+ }
+
+ successfullyParsed = true;
+</script>
+
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
+2009-12-03 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ WAI-ARIA: aria-activedescendant doesn't work as intended
+ https://bugs.webkit.org/show_bug.cgi?id=32100
+
+ Fixes a number of issues regarding the "tree" role and aria-activedescendant.
+ 1. The indexes were being reported incorrectly by treeitems.
+ 2. aria-activedescendant changes were not being sent to the containing item.
+ 3. The tree's selected rows need to consult aria-activedescendant.
+ 4. Since a tree changes what it returns as its children (it returns its rows)
+ the mac-specific array indexing methods need to correctly handle the tree case.
+
+ Tests: platform/mac/accessibility/aria-tree-activedescendant.html
+ platform/mac/accessibility/aria-tree-index-of-items.html
+
+ * accessibility/AXObjectCache.h:
+ (WebCore::AXObjectCache::):
+ * accessibility/AccessibilityRenderObject.cpp:
+ (WebCore::AccessibilityRenderObject::shouldFocusActiveDescendant):
+ (WebCore::AccessibilityRenderObject::activeDescendant):
+ (WebCore::AccessibilityRenderObject::handleActiveDescendantChanged):
+ (WebCore::AccessibilityRenderObject::ariaTreeSelectedRows):
+ * accessibility/mac/AXObjectCacheMac.mm:
+ (WebCore::AXObjectCache::postPlatformNotification):
+ * accessibility/mac/AccessibilityObjectWrapper.mm:
+ (-[AccessibilityObjectWrapper accessibilityAttributeValue:]):
+ (-[AccessibilityObjectWrapper accessibilityIndexOfChild:]):
+ (-[AccessibilityObjectWrapper accessibilityArrayAttributeValues:index:maxCount:]):
+ * accessibility/win/AXObjectCacheWin.cpp:
+ (WebCore::AXObjectCache::postPlatformNotification):
+
2009-12-03 Zoltan Horvath <zoltan@webkit.org>
Reviewed by Eric Seidel.
static VisiblePosition visiblePositionForTextMarkerData(TextMarkerData&);
enum AXNotification {
+ AXActiveDescendantChanged,
AXCheckedStateChanged,
AXFocusedUIElementChanged,
AXLayoutComplete,
case ProgressIndicatorRole:
case ToolbarRole:
case OutlineRole:
+ case TreeRole:
+ case GridRole:
/* FIXME: replace these with actual roles when they are added to AccessibilityRole
composite
alert
alertdialog
- grid
status
timer
- tree
*/
return true;
default:
AccessibilityObject* AccessibilityRenderObject::activeDescendant() const
{
- if (renderer()->node() && !renderer()->node()->isElementNode())
+ if (!m_renderer)
return 0;
- Element* element = static_cast<Element*>(renderer()->node());
+
+ if (m_renderer->node() && !m_renderer->node()->isElementNode())
+ return 0;
+ Element* element = static_cast<Element*>(m_renderer->node());
String activeDescendantAttrStr = element->getAttribute(aria_activedescendantAttr).string();
if (activeDescendantAttrStr.isNull() || activeDescendantAttrStr.isEmpty())
return 0;
- Element* target = renderer()->document()->getElementById(activeDescendantAttrStr);
+ Element* target = document()->getElementById(activeDescendantAttrStr);
if (!target)
return 0;
- AccessibilityObject* obj = renderer()->document()->axObjectCache()->getOrCreate(target->renderer());
+ AccessibilityObject* obj = axObjectCache()->getOrCreate(target->renderer());
if (obj && obj->isAccessibilityRenderObject())
// an activedescendant is only useful if it has a renderer, because that's what's needed to post the notification
return obj;
AccessibilityRenderObject* activedescendant = static_cast<AccessibilityRenderObject*>(activeDescendant());
if (activedescendant && shouldFocusActiveDescendant())
- doc->axObjectCache()->postNotification(activedescendant->renderer(), AXObjectCache::AXFocusedUIElementChanged, true);
+ doc->axObjectCache()->postNotification(m_renderer, AXObjectCache::AXActiveDescendantChanged, true);
}
AccessibilityObject* AccessibilityRenderObject::correspondingControlForLabelElement() const
// Determine which rows are selected.
bool isMultiselectable = elementAttributeValue(aria_multiselectableAttr);
+ // Prefer active descendant over aria-selected.
+ AccessibilityObject* activeDesc = activeDescendant();
+ if (activeDesc && activeDesc->isTreeItem()) {
+ result.append(activeDesc);
+ if (!isMultiselectable)
+ return;
+ }
+
unsigned count = allRows.size();
for (unsigned k = 0; k < count; ++k) {
if (allRows[k]->isSelected()) {
// Some notifications are unique to Safari and do not have NSAccessibility equivalents.
String macNotification;
switch (notification) {
+ case AXActiveDescendantChanged:
+ // An active descendant change for trees means a selected rows change.
+ if (obj->isTree())
+ macNotification = NSAccessibilitySelectedRowsChangedNotification;
+ else
+ macNotification = NSAccessibilityFocusedUIElementChangedNotification;
+ break;
case AXCheckedStateChanged:
macNotification = "AXCheckedStateChanged";
break;
if (m_object->isTreeItem()) {
if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) {
AccessibilityObject* parent = m_object->parentObject();
+ for (; parent && !parent->isTree(); parent = parent->parentObject())
+ { }
+
if (!parent)
return nil;
// Find the index of this item by iterating the parents.
- const AccessibilityObject::AccessibilityChildrenVector& children = parent->children();
- unsigned count = children.size();
- for (unsigned k = 0; k < count; ++k)
- if (children[k]->wrapper() == self)
+ AccessibilityObject::AccessibilityChildrenVector rowsCopy;
+ parent->ariaTreeRows(rowsCopy);
+ size_t count = rowsCopy.size();
+ for (size_t k = 0; k < count; ++k)
+ if (rowsCopy[k]->wrapper() == self)
return [NSNumber numberWithUnsignedInt:k];
return nil;
m_object->updateBackingStore();
if (!m_object)
return NSNotFound;
-
+
+ // Tree objects return their rows as their children. We can use the original method
+ // here, because we won't gain any speed up.
+ if (m_object->isTree())
+ return [super accessibilityIndexOfChild:child];
+
const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
if (children.isEmpty())
NSUInteger arrayLength = min(childCount - index, maxCount);
return [children subarrayWithRange:NSMakeRange(index, arrayLength)];
+ } else if (m_object->isTree()) {
+ // Tree objects return their rows as their children. We can use the original method in this case.
+ return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
}
const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
DWORD msaaEvent;
switch (notification) {
case AXFocusedUIElementChanged:
+ case AXActiveDescendantChanged:
msaaEvent = EVENT_OBJECT_FOCUS;
break;