summaryrefslogtreecommitdiffstats
path: root/WebCore/accessibility
diff options
context:
space:
mode:
authorKristian Monsen <kristianm@google.com>2010-06-28 16:42:48 +0100
committerKristian Monsen <kristianm@google.com>2010-07-02 10:29:56 +0100
commit06ea8e899e48f1f2f396b70e63fae369f2f23232 (patch)
tree20c1428cd05c76f32394ab354ea35ed99acd86d8 /WebCore/accessibility
parent72aad67af14193199e29cdd5c4ddc095a8b9a8a8 (diff)
downloadexternal_webkit-06ea8e899e48f1f2f396b70e63fae369f2f23232.zip
external_webkit-06ea8e899e48f1f2f396b70e63fae369f2f23232.tar.gz
external_webkit-06ea8e899e48f1f2f396b70e63fae369f2f23232.tar.bz2
Merge WebKit at r61871: Initial merge by git.
Change-Id: I6cff43abca9cc4782e088a469ad4f03f166a65d5
Diffstat (limited to 'WebCore/accessibility')
-rw-r--r--WebCore/accessibility/AXObjectCache.cpp9
-rw-r--r--WebCore/accessibility/AXObjectCache.h8
-rw-r--r--WebCore/accessibility/AccessibilityObject.cpp4
-rw-r--r--WebCore/accessibility/AccessibilityObject.h6
-rw-r--r--WebCore/accessibility/AccessibilityRenderObject.cpp104
-rw-r--r--WebCore/accessibility/AccessibilityRenderObject.h13
-rw-r--r--WebCore/accessibility/AccessibilityTableCell.cpp2
-rw-r--r--WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp36
-rw-r--r--WebCore/accessibility/mac/AXObjectCacheMac.mm13
-rw-r--r--WebCore/accessibility/mac/AccessibilityObjectMac.mm5
-rw-r--r--WebCore/accessibility/mac/AccessibilityObjectWrapper.mm3
11 files changed, 155 insertions, 48 deletions
diff --git a/WebCore/accessibility/AXObjectCache.cpp b/WebCore/accessibility/AXObjectCache.cpp
index b7622b8..750c611 100644
--- a/WebCore/accessibility/AXObjectCache.cpp
+++ b/WebCore/accessibility/AXObjectCache.cpp
@@ -456,6 +456,15 @@ void AXObjectCache::selectedChildrenChanged(RenderObject* renderer)
#endif
#if HAVE(ACCESSIBILITY)
+void AXObjectCache::handleAriaExpandedChange(RenderObject *renderer)
+{
+ if (!renderer)
+ return;
+ AccessibilityObject* obj = getOrCreate(renderer);
+ if (obj)
+ obj->handleAriaExpandedChanged();
+}
+
void AXObjectCache::handleActiveDescendantChanged(RenderObject* renderer)
{
if (!renderer)
diff --git a/WebCore/accessibility/AXObjectCache.h b/WebCore/accessibility/AXObjectCache.h
index 25f5347..8d98fa3 100644
--- a/WebCore/accessibility/AXObjectCache.h
+++ b/WebCore/accessibility/AXObjectCache.h
@@ -88,7 +88,8 @@ public:
void handleAriaRoleChanged(RenderObject*);
void handleFocusedUIElementChanged(RenderObject* oldFocusedRenderer, RenderObject* newFocusedRenderer);
void handleScrolledToAnchor(const Node* anchorNode);
-
+ void handleAriaExpandedChange(RenderObject*);
+
static void enableAccessibility() { gAccessibilityEnabled = true; }
static void enableEnhancedUserInterfaceAccessibility() { gAccessibilityEnhancedUserInterfaceEnabled = true; }
@@ -116,6 +117,9 @@ public:
AXScrolledToAnchor,
AXLiveRegionChanged,
AXMenuListValueChanged,
+ AXRowCountChanged,
+ AXRowCollapsed,
+ AXRowExpanded,
};
void postNotification(RenderObject*, AXNotification, bool postToElement, PostType = PostAsynchronously);
@@ -150,10 +154,12 @@ inline void AXObjectCache::detachWrapper(AccessibilityObject*) { }
inline void AXObjectCache::attachWrapper(AccessibilityObject*) { }
inline void AXObjectCache::selectedChildrenChanged(RenderObject*) { }
inline void AXObjectCache::postNotification(RenderObject*, AXNotification, bool postToElement, PostType) { }
+inline void AXObjectCache::postNotification(AccessibilityObject*, Document*, AXNotification, bool postToElement, PostType) { }
inline void AXObjectCache::postPlatformNotification(AccessibilityObject*, AXNotification) { }
inline void AXObjectCache::handleFocusedUIElementChanged(RenderObject*, RenderObject*) { }
inline void AXObjectCache::handleScrolledToAnchor(const Node*) { }
inline void AXObjectCache::contentChanged(RenderObject*) { }
+inline void AXObjectCache::handleAriaExpandedChange(RenderObject*) { }
#endif
}
diff --git a/WebCore/accessibility/AccessibilityObject.cpp b/WebCore/accessibility/AccessibilityObject.cpp
index 8dedc36..555ba6f 100644
--- a/WebCore/accessibility/AccessibilityObject.cpp
+++ b/WebCore/accessibility/AccessibilityObject.cpp
@@ -902,7 +902,7 @@ static ARIARoleMap* createARIARoleMap()
{ "img", ImageRole },
{ "link", WebCoreLinkRole },
{ "list", ListRole },
- { "listitem", GroupRole },
+ { "listitem", ListItemRole },
{ "listbox", ListBoxRole },
{ "log", ApplicationLogRole },
// "option" isn't here because it may map to different roles depending on the parent element's role
@@ -917,7 +917,7 @@ static ARIARoleMap* createARIARoleMap()
{ "note", DocumentNoteRole },
{ "navigation", LandmarkNavigationRole },
{ "option", ListBoxOptionRole },
- { "presentation", IgnoredRole },
+ { "presentation", PresentationalRole },
{ "progressbar", ProgressIndicatorRole },
{ "radio", RadioButtonRole },
{ "radiogroup", RadioGroupRole },
diff --git a/WebCore/accessibility/AccessibilityObject.h b/WebCore/accessibility/AccessibilityObject.h
index 8b4923a..3c8d392 100644
--- a/WebCore/accessibility/AccessibilityObject.h
+++ b/WebCore/accessibility/AccessibilityObject.h
@@ -160,6 +160,7 @@ enum AccessibilityRole {
AnnotationRole,
SliderThumbRole,
IgnoredRole,
+ PresentationalRole,
TabRole,
TabListRole,
TabPanelRole,
@@ -296,6 +297,7 @@ public:
bool isTreeItem() const { return roleValue() == TreeItemRole; }
bool isScrollbar() const { return roleValue() == ScrollBarRole; }
bool isButton() const { return roleValue() == ButtonRole; }
+ bool isListItem() const { return roleValue() == ListItemRole; }
virtual bool isChecked() const { return false; }
virtual bool isEnabled() const { return false; }
@@ -442,13 +444,15 @@ public:
virtual void addChildren() { }
virtual bool canHaveChildren() const { return true; }
virtual bool hasChildren() const { return m_haveChildren; }
+ virtual void updateChildrenIfNecessary() { }
virtual void selectedChildren(AccessibilityChildrenVector&) { }
virtual void visibleChildren(AccessibilityChildrenVector&) { }
virtual void tabChildren(AccessibilityChildrenVector&) { }
virtual bool shouldFocusActiveDescendant() const { return false; }
virtual AccessibilityObject* activeDescendant() const { return 0; }
virtual void handleActiveDescendantChanged() { }
-
+ virtual void handleAriaExpandedChanged() { }
+
static AccessibilityRole ariaRoleToWebCoreRole(const String&);
static const AtomicString& getAttribute(Node*, const QualifiedName&);
diff --git a/WebCore/accessibility/AccessibilityRenderObject.cpp b/WebCore/accessibility/AccessibilityRenderObject.cpp
index ffe62f8..1ef6e09 100644
--- a/WebCore/accessibility/AccessibilityRenderObject.cpp
+++ b/WebCore/accessibility/AccessibilityRenderObject.cpp
@@ -1256,11 +1256,11 @@ static HTMLLabelElement* labelForElement(Element* element)
HTMLLabelElement* AccessibilityRenderObject::labelElementContainer() const
{
if (!m_renderer)
- return false;
+ return 0;
// the control element should not be considered part of the label
if (isControl())
- return false;
+ return 0;
// find if this has a parent that is a label
for (Node* parentNode = m_renderer->node(); parentNode; parentNode = parentNode->parentNode()) {
@@ -1735,6 +1735,9 @@ bool AccessibilityRenderObject::accessibilityIsIgnored() const
if (roleValue() == IgnoredRole)
return true;
+ if (roleValue() == PresentationalRole || inheritsPresentationalRole())
+ return true;
+
// An ARIA tree can only have tree items and static text as children.
if (!isAllowedChildOfTree())
return true;
@@ -2829,6 +2832,39 @@ AccessibilityObject* AccessibilityRenderObject::activeDescendant() const
return 0;
}
+void AccessibilityRenderObject::handleAriaExpandedChanged()
+{
+ // Find if a parent of this object should handle aria-expanded changes.
+ AccessibilityObject* containerParent = this->parentObject();
+ while (containerParent) {
+ bool foundParent = false;
+
+ switch (containerParent->roleValue()) {
+ case TreeRole:
+ case TreeGridRole:
+ case GridRole:
+ case TableRole:
+ case BrowserRole:
+ foundParent = true;
+ break;
+ default:
+ break;
+ }
+
+ if (foundParent)
+ break;
+
+ containerParent = containerParent->parentObject();
+ }
+
+ // Post that the row count changed.
+ if (containerParent)
+ axObjectCache()->postNotification(containerParent, document(), AXObjectCache::AXRowCountChanged, true);
+
+ // Post that the specific row either collapsed or expanded.
+ if (roleValue() == RowRole || roleValue() == TreeItemRole)
+ axObjectCache()->postNotification(this, document(), isExpanded() ? AXObjectCache::AXRowExpanded : AXObjectCache::AXRowCollapsed, true);
+}
void AccessibilityRenderObject::handleActiveDescendantChanged()
{
@@ -2954,6 +2990,8 @@ AccessibilityRole AccessibilityRenderObject::determineAccessibilityRole()
return ImageMapRole;
return WebCoreLinkRole;
}
+ if (m_renderer->isListItem())
+ return ListItemRole;
if (m_renderer->isListMarker())
return ListMarkerRole;
if (node && node->hasTagName(buttonTag))
@@ -3046,6 +3084,49 @@ AccessibilityOrientation AccessibilityRenderObject::orientation() const
return AccessibilityObject::orientation();
}
+bool AccessibilityRenderObject::inheritsPresentationalRole() const
+{
+ // ARIA spec says that when a parent object is presentational, and it has required child elements,
+ // those child elements are also presentational. For example, <li> becomes presentational from <ul>.
+ // http://www.w3.org/WAI/PF/aria/complete#presentation
+ DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, listItemParents, ());
+
+ HashSet<QualifiedName>* possibleParentTagNames = 0;
+ switch (roleValue()) {
+ case ListItemRole:
+ case ListMarkerRole:
+ if (listItemParents.isEmpty()) {
+ listItemParents.add(ulTag);
+ listItemParents.add(olTag);
+ listItemParents.add(dlTag);
+ }
+ possibleParentTagNames = &listItemParents;
+ break;
+ default:
+ break;
+ }
+
+ // Not all elements need to check for this, only ones that are required children.
+ if (!possibleParentTagNames)
+ return false;
+
+ for (AccessibilityObject* parent = parentObject(); parent; parent = parent->parentObject()) {
+ if (!parent->isAccessibilityRenderObject())
+ continue;
+
+ Node* elementNode = static_cast<AccessibilityRenderObject*>(parent)->node();
+ if (!elementNode || !elementNode->isElementNode())
+ continue;
+
+ // If native tag of the parent element matches an acceptable name, then return
+ // based on its presentational status.
+ if (possibleParentTagNames->contains(static_cast<Element*>(elementNode)->tagQName()))
+ return parent->roleValue() == PresentationalRole;
+ }
+
+ return false;
+}
+
bool AccessibilityRenderObject::isPresentationalChildOfAriaRole() const
{
// Walk the parent chain looking for a parent that has presentational children
@@ -3142,18 +3223,16 @@ void AccessibilityRenderObject::contentChanged()
void AccessibilityRenderObject::childrenChanged()
{
- // this method is meant as a quick way of marking dirty
- // a portion of the accessibility tree
-
+ // This method is meant as a quick way of marking a portion of the accessibility tree dirty.
if (!m_renderer)
return;
- // Go up the render parent chain, marking children as dirty.
- // We can't rely on the accessibilityParent() because it may not exist and we must not create an AX object here either
+ // Go up the accessibility parent chain, but only if the element already exists. This method is
+ // called during render layouts, minimal work should be done.
+ // If AX elements are created now, they could interrogate the render tree while it's in a funky state.
// At the same time, process ARIA live region changes.
- for (RenderObject* renderParent = m_renderer; renderParent; renderParent = renderParent->parent()) {
- AccessibilityObject* parent = m_renderer->document()->axObjectCache()->get(renderParent);
- if (!parent || !parent->isAccessibilityRenderObject())
+ for (AccessibilityObject* parent = this; parent; parent = parent->parentObjectIfExists()) {
+ if (!parent->isAccessibilityRenderObject())
continue;
AccessibilityRenderObject* axParent = static_cast<AccessibilityRenderObject*>(parent);
@@ -3165,7 +3244,7 @@ void AccessibilityRenderObject::childrenChanged()
// If this element supports ARIA live regions, then notify the AT of changes.
if (axParent->supportsARIALiveRegion())
- axObjectCache()->postNotification(renderParent, AXObjectCache::AXLiveRegionChanged, true);
+ axObjectCache()->postNotification(axParent->renderer(), AXObjectCache::AXLiveRegionChanged, true);
}
}
}
@@ -3232,8 +3311,7 @@ void AccessibilityRenderObject::addChildren()
// add all unignored acc children
for (RefPtr<AccessibilityObject> obj = firstChild(); obj; obj = obj->nextSibling()) {
if (obj->accessibilityIsIgnored()) {
- if (!obj->hasChildren())
- obj->addChildren();
+ obj->updateChildrenIfNecessary();
AccessibilityChildrenVector children = obj->children();
unsigned length = children.size();
for (unsigned i = 0; i < length; ++i)
diff --git a/WebCore/accessibility/AccessibilityRenderObject.h b/WebCore/accessibility/AccessibilityRenderObject.h
index 494e6bb..d4f798a 100644
--- a/WebCore/accessibility/AccessibilityRenderObject.h
+++ b/WebCore/accessibility/AccessibilityRenderObject.h
@@ -30,6 +30,7 @@
#define AccessibilityRenderObject_h
#include "AccessibilityObject.h"
+#include "RenderObject.h"
namespace WebCore {
@@ -47,7 +48,6 @@ class HTMLSelectElement;
class IntPoint;
class IntSize;
class Node;
-class RenderObject;
class RenderListBox;
class RenderTextControl;
class RenderView;
@@ -169,6 +169,11 @@ public:
void setRenderer(RenderObject* renderer) { m_renderer = renderer; }
RenderObject* renderer() const { return m_renderer; }
+ Node* node() const
+ {
+ return m_renderer ? m_renderer->node() : 0;
+ };
+
RenderView* topRenderer() const;
RenderTextControl* textControl() const;
Document* document() const;
@@ -199,7 +204,7 @@ public:
virtual const AccessibilityChildrenVector& children();
virtual void clearChildren();
- void updateChildrenIfNecessary();
+ virtual void updateChildrenIfNecessary();
virtual void setFocused(bool);
virtual void setSelectedTextRange(const PlainTextRange&);
@@ -222,7 +227,8 @@ public:
virtual bool shouldFocusActiveDescendant() const;
virtual AccessibilityObject* activeDescendant() const;
virtual void handleActiveDescendantChanged();
-
+ virtual void handleAriaExpandedChanged();
+
virtual VisiblePositionRange visiblePositionRange() const;
virtual VisiblePositionRange visiblePositionRangeForLine(unsigned) const;
virtual IntRect boundsForVisiblePositionRange(const VisiblePositionRange&) const;
@@ -305,6 +311,7 @@ private:
virtual bool ariaLiveRegionAtomic() const;
virtual bool ariaLiveRegionBusy() const;
+ bool inheritsPresentationalRole() const;
void setNeedsToUpdateChildren() const { m_childrenDirty = true; }
mutable AccessibilityRole m_roleForMSAA;
diff --git a/WebCore/accessibility/AccessibilityTableCell.cpp b/WebCore/accessibility/AccessibilityTableCell.cpp
index 318c619..7fadb88 100644
--- a/WebCore/accessibility/AccessibilityTableCell.cpp
+++ b/WebCore/accessibility/AccessibilityTableCell.cpp
@@ -71,7 +71,7 @@ bool AccessibilityTableCell::accessibilityIsIgnored() const
AccessibilityObject* AccessibilityTableCell::parentTable() const
{
if (!m_renderer || !m_renderer->isTableCell())
- return false;
+ return 0;
return axObjectCache()->getOrCreate(toRenderTableCell(m_renderer)->table());
}
diff --git a/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp b/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp
index 5158774..8e2aa2c 100644
--- a/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp
+++ b/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp
@@ -143,18 +143,7 @@ static AccessibilityObject* core(AtkDocument* document)
return core(ATK_OBJECT(document));
}
-static const gchar* nameFromChildren(AccessibilityObject* object)
-{
- if (!object)
- return 0;
-
- AccessibilityRenderObject::AccessibilityChildrenVector children = object->children();
- // Currently, object->stringValue() should be an empty String. This might not be the case down the road.
- String name = object->stringValue();
- for (unsigned i = 0; i < children.size(); ++i)
- name += children.at(i).get()->stringValue();
- return returnString(name);
-}
+static gchar* webkit_accessible_text_get_text(AtkText* text, gint startOffset, gint endOffset);
static const gchar* webkit_accessible_get_name(AtkObject* object)
{
@@ -165,8 +154,11 @@ static const gchar* webkit_accessible_get_name(AtkObject* object)
AccessibilityRenderObject* renderObject = static_cast<AccessibilityRenderObject*>(coreObject);
if (coreObject->isControl()) {
AccessibilityObject* label = renderObject->correspondingLabelForControlElement();
- if (label)
- return returnString(nameFromChildren(label));
+ if (label) {
+ AtkObject* atkObject = label->wrapper();
+ if (ATK_IS_TEXT(atkObject))
+ return webkit_accessible_text_get_text(ATK_TEXT(atkObject), 0, -1);
+ }
}
if (renderObject->isImage() || renderObject->isInputImage()) {
@@ -422,6 +414,7 @@ static AtkRole atkRole(AccessibilityRole role)
return ATK_ROLE_HEADING;
case ListBoxRole:
return ATK_ROLE_LIST;
+ case ListItemRole:
case ListBoxOptionRole:
return ATK_ROLE_LIST_ITEM;
default:
@@ -436,13 +429,6 @@ static AtkRole webkit_accessible_get_role(AtkObject* object)
if (!axObject)
return ATK_ROLE_UNKNOWN;
- // WebCore does not seem to have a role for list items
- if (axObject->isGroup()) {
- AccessibilityObject* parent = axObject->parentObjectUnignored();
- if (parent && parent->isList())
- return ATK_ROLE_LIST_ITEM;
- }
-
// WebCore does not know about paragraph role, label role, or section role
if (axObject->isAccessibilityRenderObject()) {
Node* node = static_cast<AccessibilityRenderObject*>(axObject)->renderer()->node();
@@ -1501,8 +1487,8 @@ static AtkObject* webkit_accessible_table_get_caption(AtkTable* table)
static const gchar* webkit_accessible_table_get_column_description(AtkTable* table, gint column)
{
AtkObject* columnHeader = atk_table_get_column_header(table, column);
- if (columnHeader)
- return returnString(nameFromChildren(core(columnHeader)));
+ if (columnHeader && ATK_IS_TEXT(columnHeader))
+ return webkit_accessible_text_get_text(ATK_TEXT(columnHeader), 0, -1);
return 0;
}
@@ -1510,8 +1496,8 @@ static const gchar* webkit_accessible_table_get_column_description(AtkTable* tab
static const gchar* webkit_accessible_table_get_row_description(AtkTable* table, gint row)
{
AtkObject* rowHeader = atk_table_get_row_header(table, row);
- if (rowHeader)
- return returnString(nameFromChildren(core(rowHeader)));
+ if (rowHeader && ATK_IS_TEXT(rowHeader))
+ return webkit_accessible_text_get_text(ATK_TEXT(rowHeader), 0, -1);
return 0;
}
diff --git a/WebCore/accessibility/mac/AXObjectCacheMac.mm b/WebCore/accessibility/mac/AXObjectCacheMac.mm
index 6f886fe..a02bc75 100644
--- a/WebCore/accessibility/mac/AXObjectCacheMac.mm
+++ b/WebCore/accessibility/mac/AXObjectCacheMac.mm
@@ -91,7 +91,18 @@ void AXObjectCache::postPlatformNotification(AccessibilityObject* obj, AXNotific
case AXLiveRegionChanged:
macNotification = NSAccessibilityLiveRegionChangedNotification;
break;
- // Does not exist on Mac.
+ case AXRowCountChanged:
+ macNotification = NSAccessibilityRowCountChangedNotification;
+ break;
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ case AXRowExpanded:
+ macNotification = NSAccessibilityRowExpandedNotification;
+ break;
+ case AXRowCollapsed:
+ macNotification = NSAccessibilityRowCollapsedNotification;
+ break;
+#endif
+ // Does not exist on Mac.
case AXCheckedStateChanged:
default:
return;
diff --git a/WebCore/accessibility/mac/AccessibilityObjectMac.mm b/WebCore/accessibility/mac/AccessibilityObjectMac.mm
index 37fa65a..1076972 100644
--- a/WebCore/accessibility/mac/AccessibilityObjectMac.mm
+++ b/WebCore/accessibility/mac/AccessibilityObjectMac.mm
@@ -46,6 +46,11 @@ AccessibilityObjectInclusion AccessibilityObject::accessibilityPlatformIncludesO
if (isMenuListPopup() || isMenuListOption())
return IgnoreObject;
+ // Never expose an unknown object on the Mac. Clients of the AX API will not know what to do with it.
+ // Special case is when the unknown object is actually an attachment.
+ if (roleValue() == UnknownRole && !isAttachment())
+ return IgnoreObject;
+
return DefaultBehavior;
}
diff --git a/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm b/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm
index 1fdb0cc..9de7e4d 100644
--- a/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm
+++ b/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm
@@ -957,7 +957,7 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi
else if (m_object->isControl())
objectAttributes = controlAttrs;
- else if (m_object->isGroup())
+ else if (m_object->isGroup() || m_object->isListItem())
objectAttributes = groupAttrs;
else if (m_object->isTabList())
objectAttributes = tabListAttrs;
@@ -1148,6 +1148,7 @@ static const AccessibilityRoleMap& createAccessibilityRoleMap()
{ TabPanelRole, NSAccessibilityGroupRole },
{ TreeRole, NSAccessibilityOutlineRole },
{ TreeItemRole, NSAccessibilityRowRole },
+ { ListItemRole, NSAccessibilityGroupRole }
};
AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap;