summaryrefslogtreecommitdiffstats
path: root/WebCore/accessibility
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/accessibility')
-rw-r--r--WebCore/accessibility/AXObjectCache.cpp50
-rw-r--r--WebCore/accessibility/AXObjectCache.h191
-rw-r--r--WebCore/accessibility/AccessibilityARIAGrid.cpp4
-rwxr-xr-xWebCore/accessibility/AccessibilityAllInOne.cpp2
-rw-r--r--WebCore/accessibility/AccessibilityImageMapLink.cpp26
-rw-r--r--WebCore/accessibility/AccessibilityImageMapLink.h8
-rw-r--r--WebCore/accessibility/AccessibilityList.cpp10
-rw-r--r--WebCore/accessibility/AccessibilityList.h2
-rw-r--r--WebCore/accessibility/AccessibilityListBox.cpp2
-rw-r--r--WebCore/accessibility/AccessibilityListBox.h2
-rw-r--r--WebCore/accessibility/AccessibilityListBoxOption.cpp4
-rw-r--r--WebCore/accessibility/AccessibilityListBoxOption.h2
-rw-r--r--WebCore/accessibility/AccessibilityMediaControls.cpp8
-rw-r--r--WebCore/accessibility/AccessibilityMediaControls.h98
-rw-r--r--WebCore/accessibility/AccessibilityObject.cpp183
-rw-r--r--WebCore/accessibility/AccessibilityObject.h153
-rw-r--r--WebCore/accessibility/AccessibilityRenderObject.cpp761
-rw-r--r--WebCore/accessibility/AccessibilityRenderObject.h47
-rw-r--r--WebCore/accessibility/AccessibilitySlider.cpp22
-rw-r--r--WebCore/accessibility/AccessibilitySlider.h76
-rw-r--r--WebCore/accessibility/AccessibilityTable.cpp16
-rw-r--r--WebCore/accessibility/AccessibilityTableColumn.cpp4
-rw-r--r--WebCore/accessibility/AccessibilityTableHeaderContainer.cpp5
-rw-r--r--WebCore/accessibility/AccessibilityTableRow.cpp2
-rw-r--r--WebCore/accessibility/chromium/AccessibilityObjectWrapper.h4
-rw-r--r--WebCore/accessibility/gtk/AXObjectCacheAtk.cpp4
-rw-r--r--WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp572
-rw-r--r--WebCore/accessibility/mac/AXObjectCacheMac.mm7
-rw-r--r--WebCore/accessibility/mac/AccessibilityObjectMac.mm18
-rw-r--r--WebCore/accessibility/mac/AccessibilityObjectWrapper.h9
-rw-r--r--WebCore/accessibility/mac/AccessibilityObjectWrapper.mm429
-rw-r--r--WebCore/accessibility/win/AXObjectCacheWin.cpp1
32 files changed, 2037 insertions, 685 deletions
diff --git a/WebCore/accessibility/AXObjectCache.cpp b/WebCore/accessibility/AXObjectCache.cpp
index 55199a3..6ec325a 100644
--- a/WebCore/accessibility/AXObjectCache.cpp
+++ b/WebCore/accessibility/AXObjectCache.cpp
@@ -30,12 +30,12 @@
#include "AXObjectCache.h"
#include "AccessibilityARIAGrid.h"
-#include "AccessibilityARIAGridRow.h"
#include "AccessibilityARIAGridCell.h"
+#include "AccessibilityARIAGridRow.h"
+#include "AccessibilityImageMapLink.h"
#include "AccessibilityList.h"
#include "AccessibilityListBox.h"
#include "AccessibilityListBoxOption.h"
-#include "AccessibilityImageMapLink.h"
#include "AccessibilityMediaControls.h"
#include "AccessibilityRenderObject.h"
#include "AccessibilitySlider.h"
@@ -141,7 +141,10 @@ AccessibilityObject* AXObjectCache::getOrCreate(RenderObject* renderer)
RefPtr<AccessibilityObject> newObj = 0;
if (renderer->isListBox())
newObj = AccessibilityListBox::create(renderer);
- else if (node && (nodeIsAriaType(node, "list") || node->hasTagName(ulTag) || node->hasTagName(olTag) || node->hasTagName(dlTag)))
+
+ // If the node is aria role="list" or the aria role is empty and its a ul/ol/dl type (it shouldn't be a list if aria says otherwise).
+ else if (node && ((nodeIsAriaType(node, "list") || nodeIsAriaType(node, "directory"))
+ || (nodeIsAriaType(node, nullAtom) && (node->hasTagName(ulTag) || node->hasTagName(olTag) || node->hasTagName(dlTag)))))
newObj = AccessibilityList::create(renderer);
// aria tables
@@ -191,23 +194,23 @@ AccessibilityObject* AXObjectCache::getOrCreate(AccessibilityRole role)
// will be filled in...
switch (role) {
- case ListBoxOptionRole:
- obj = AccessibilityListBoxOption::create();
- break;
- case ImageMapLinkRole:
- obj = AccessibilityImageMapLink::create();
- break;
- case ColumnRole:
- obj = AccessibilityTableColumn::create();
- break;
- case TableHeaderContainerRole:
- obj = AccessibilityTableHeaderContainer::create();
- break;
- case SliderThumbRole:
- obj = AccessibilitySliderThumb::create();
- break;
- default:
- obj = 0;
+ case ListBoxOptionRole:
+ obj = AccessibilityListBoxOption::create();
+ break;
+ case ImageMapLinkRole:
+ obj = AccessibilityImageMapLink::create();
+ break;
+ case ColumnRole:
+ obj = AccessibilityTableColumn::create();
+ break;
+ case TableHeaderContainerRole:
+ obj = AccessibilityTableHeaderContainer::create();
+ break;
+ case SliderThumbRole:
+ obj = AccessibilitySliderThumb::create();
+ break;
+ default:
+ obj = 0;
}
if (obj)
@@ -235,9 +238,8 @@ void AXObjectCache::remove(AXID axID)
removeAXID(obj);
// finally remove the object
- if (!m_objects.take(axID)) {
+ if (!m_objects.take(axID))
return;
- }
ASSERT(m_objects.size() >= m_idsInUse.size());
}
@@ -261,7 +263,7 @@ AXID AXObjectCache::platformGenerateAXID() const
AXID objID = lastUsedID;
do {
++objID;
- } while (objID == 0 || HashTraits<AXID>::isDeletedValue(objID) || m_idsInUse.contains(objID));
+ } while (!objID || HashTraits<AXID>::isDeletedValue(objID) || m_idsInUse.contains(objID));
lastUsedID = objID;
@@ -292,7 +294,7 @@ void AXObjectCache::removeAXID(AccessibilityObject* obj)
return;
AXID objID = obj->axObjectID();
- if (objID == 0)
+ if (!objID)
return;
ASSERT(!HashTraits<AXID>::isDeletedValue(objID));
ASSERT(m_idsInUse.contains(objID));
diff --git a/WebCore/accessibility/AXObjectCache.h b/WebCore/accessibility/AXObjectCache.h
index 5a75f84..adfddcd 100644
--- a/WebCore/accessibility/AXObjectCache.h
+++ b/WebCore/accessibility/AXObjectCache.h
@@ -42,104 +42,105 @@ class WebCoreTextMarker;
namespace WebCore {
- class Node;
- class Page;
- class RenderObject;
- class String;
- class VisiblePosition;
-
- struct TextMarkerData {
- AXID axID;
- Node* node;
- int offset;
- EAffinity affinity;
- };
-
- class AXObjectCache {
- public:
- AXObjectCache();
- ~AXObjectCache();
-
- static AccessibilityObject* focusedUIElementForPage(const Page*);
-
- // to be used with render objects
- AccessibilityObject* getOrCreate(RenderObject*);
-
- // used for objects without backing elements
- AccessibilityObject* getOrCreate(AccessibilityRole);
-
- // will only return the AccessibilityObject if it already exists
- AccessibilityObject* get(RenderObject*);
-
- void remove(RenderObject*);
- void remove(AXID);
-
- void detachWrapper(AccessibilityObject*);
- void attachWrapper(AccessibilityObject*);
- void childrenChanged(RenderObject*);
- void selectedChildrenChanged(RenderObject*);
- void handleActiveDescendantChanged(RenderObject*);
- void handleAriaRoleChanged(RenderObject*);
- void handleFocusedUIElementChanged(RenderObject* oldFocusedRenderer, RenderObject* newFocusedRenderer);
- void handleScrolledToAnchor(const Node* anchorNode);
-
- static void enableAccessibility() { gAccessibilityEnabled = true; }
- static void enableEnhancedUserInterfaceAccessibility() { gAccessibilityEnhancedUserInterfaceEnabled = true; }
-
- static bool accessibilityEnabled() { return gAccessibilityEnabled; }
- static bool accessibilityEnhancedUserInterfaceEnabled() { return gAccessibilityEnhancedUserInterfaceEnabled; }
-
- void removeAXID(AccessibilityObject*);
- bool isIDinUse(AXID id) const { return m_idsInUse.contains(id); }
- AXID platformGenerateAXID() const;
- AccessibilityObject* objectFromAXID(AXID id) const { return m_objects.get(id).get(); }
-
- // Text marker utilities.
- static void textMarkerDataForVisiblePosition(TextMarkerData&, const VisiblePosition&);
- static VisiblePosition visiblePositionForTextMarkerData(TextMarkerData&);
-
- enum AXNotification {
- AXCheckedStateChanged,
- AXFocusedUIElementChanged,
- AXLayoutComplete,
- AXLoadComplete,
- AXSelectedChildrenChanged,
- AXSelectedTextChanged,
- AXValueChanged,
- AXScrolledToAnchor,
- };
-
- void postNotification(RenderObject*, AXNotification, bool postToElement);
-
- protected:
- void postPlatformNotification(AccessibilityObject*, AXNotification);
-
- private:
- HashMap<AXID, RefPtr<AccessibilityObject> > m_objects;
- HashMap<RenderObject*, AXID> m_renderObjectMapping;
- static bool gAccessibilityEnabled;
- static bool gAccessibilityEnhancedUserInterfaceEnabled;
-
- HashSet<AXID> m_idsInUse;
-
- Timer<AXObjectCache> m_notificationPostTimer;
- Vector<pair<RefPtr<AccessibilityObject>, AXNotification> > m_notificationsToPost;
- void notificationPostTimerFired(Timer<AXObjectCache>*);
-
- AXID getAXID(AccessibilityObject*);
- bool nodeIsAriaType(Node* node, String role);
+class Node;
+class Page;
+class RenderObject;
+class String;
+class VisiblePosition;
+
+struct TextMarkerData {
+ AXID axID;
+ Node* node;
+ int offset;
+ EAffinity affinity;
+};
+
+class AXObjectCache : public Noncopyable {
+public:
+ AXObjectCache();
+ ~AXObjectCache();
+
+ static AccessibilityObject* focusedUIElementForPage(const Page*);
+
+ // to be used with render objects
+ AccessibilityObject* getOrCreate(RenderObject*);
+
+ // used for objects without backing elements
+ AccessibilityObject* getOrCreate(AccessibilityRole);
+
+ // will only return the AccessibilityObject if it already exists
+ AccessibilityObject* get(RenderObject*);
+
+ void remove(RenderObject*);
+ void remove(AXID);
+
+ void detachWrapper(AccessibilityObject*);
+ void attachWrapper(AccessibilityObject*);
+ void childrenChanged(RenderObject*);
+ void selectedChildrenChanged(RenderObject*);
+ void handleActiveDescendantChanged(RenderObject*);
+ void handleAriaRoleChanged(RenderObject*);
+ void handleFocusedUIElementChanged(RenderObject* oldFocusedRenderer, RenderObject* newFocusedRenderer);
+ void handleScrolledToAnchor(const Node* anchorNode);
+
+ static void enableAccessibility() { gAccessibilityEnabled = true; }
+ static void enableEnhancedUserInterfaceAccessibility() { gAccessibilityEnhancedUserInterfaceEnabled = true; }
+
+ static bool accessibilityEnabled() { return gAccessibilityEnabled; }
+ static bool accessibilityEnhancedUserInterfaceEnabled() { return gAccessibilityEnhancedUserInterfaceEnabled; }
+
+ void removeAXID(AccessibilityObject*);
+ bool isIDinUse(AXID id) const { return m_idsInUse.contains(id); }
+ AXID platformGenerateAXID() const;
+ AccessibilityObject* objectFromAXID(AXID id) const { return m_objects.get(id).get(); }
+
+ // Text marker utilities.
+ static void textMarkerDataForVisiblePosition(TextMarkerData&, const VisiblePosition&);
+ static VisiblePosition visiblePositionForTextMarkerData(TextMarkerData&);
+
+ enum AXNotification {
+ AXActiveDescendantChanged,
+ AXCheckedStateChanged,
+ AXFocusedUIElementChanged,
+ AXLayoutComplete,
+ AXLoadComplete,
+ AXSelectedChildrenChanged,
+ AXSelectedTextChanged,
+ AXValueChanged,
+ AXScrolledToAnchor,
};
+
+ void postNotification(RenderObject*, AXNotification, bool postToElement);
+
+protected:
+ void postPlatformNotification(AccessibilityObject*, AXNotification);
+
+private:
+ HashMap<AXID, RefPtr<AccessibilityObject> > m_objects;
+ HashMap<RenderObject*, AXID> m_renderObjectMapping;
+ static bool gAccessibilityEnabled;
+ static bool gAccessibilityEnhancedUserInterfaceEnabled;
+
+ HashSet<AXID> m_idsInUse;
+
+ Timer<AXObjectCache> m_notificationPostTimer;
+ Vector<pair<RefPtr<AccessibilityObject>, AXNotification> > m_notificationsToPost;
+ void notificationPostTimerFired(Timer<AXObjectCache>*);
+
+ AXID getAXID(AccessibilityObject*);
+ bool nodeIsAriaType(Node*, String role);
+};
#if !HAVE(ACCESSIBILITY)
- inline void AXObjectCache::handleActiveDescendantChanged(RenderObject*) { }
- inline void AXObjectCache::handleAriaRoleChanged(RenderObject*) { }
- inline void AXObjectCache::detachWrapper(AccessibilityObject*) { }
- inline void AXObjectCache::attachWrapper(AccessibilityObject*) { }
- inline void AXObjectCache::selectedChildrenChanged(RenderObject*) { }
- inline void AXObjectCache::postNotification(RenderObject*, AXNotification, bool postToElement) { }
- inline void AXObjectCache::postPlatformNotification(AccessibilityObject*, AXNotification) { }
- inline void AXObjectCache::handleFocusedUIElementChanged(RenderObject*, RenderObject*) { }
- inline void AXObjectCache::handleScrolledToAnchor(const Node*) { }
+inline void AXObjectCache::handleActiveDescendantChanged(RenderObject*) { }
+inline void AXObjectCache::handleAriaRoleChanged(RenderObject*) { }
+inline void AXObjectCache::detachWrapper(AccessibilityObject*) { }
+inline void AXObjectCache::attachWrapper(AccessibilityObject*) { }
+inline void AXObjectCache::selectedChildrenChanged(RenderObject*) { }
+inline void AXObjectCache::postNotification(RenderObject*, AXNotification, bool postToElement) { }
+inline void AXObjectCache::postPlatformNotification(AccessibilityObject*, AXNotification) { }
+inline void AXObjectCache::handleFocusedUIElementChanged(RenderObject*, RenderObject*) { }
+inline void AXObjectCache::handleScrolledToAnchor(const Node*) { }
#endif
}
diff --git a/WebCore/accessibility/AccessibilityARIAGrid.cpp b/WebCore/accessibility/AccessibilityARIAGrid.cpp
index 69c4512..a0cf77a 100644
--- a/WebCore/accessibility/AccessibilityARIAGrid.cpp
+++ b/WebCore/accessibility/AccessibilityARIAGrid.cpp
@@ -29,11 +29,11 @@
#include "config.h"
#include "AccessibilityARIAGrid.h"
+#include "AXObjectCache.h"
#include "AccessibilityTableCell.h"
#include "AccessibilityTableColumn.h"
#include "AccessibilityTableHeaderContainer.h"
#include "AccessibilityTableRow.h"
-#include "AXObjectCache.h"
#include "RenderObject.h"
using namespace std;
@@ -137,7 +137,7 @@ AccessibilityTableCell* AccessibilityARIAGrid::cellForColumnAndRow(unsigned colu
if (column >= columnCount() || row >= rowCount())
return 0;
- AccessibilityObject *tableRow = m_rows[row].get();
+ AccessibilityObject* tableRow = m_rows[row].get();
if (!tableRow)
return 0;
diff --git a/WebCore/accessibility/AccessibilityAllInOne.cpp b/WebCore/accessibility/AccessibilityAllInOne.cpp
index 04124bd..ada50cd 100755
--- a/WebCore/accessibility/AccessibilityAllInOne.cpp
+++ b/WebCore/accessibility/AccessibilityAllInOne.cpp
@@ -25,6 +25,7 @@
// This all-in-one cpp file cuts down on template bloat to allow us to build our Windows release build.
+#include <AXObjectCache.cpp>
#include <AccessibilityARIAGrid.cpp>
#include <AccessibilityARIAGridCell.cpp>
#include <AccessibilityARIAGridRow.cpp>
@@ -41,4 +42,3 @@
#include <AccessibilityTableColumn.cpp>
#include <AccessibilityTableHeaderContainer.cpp>
#include <AccessibilityTableRow.cpp>
-#include <AXObjectCache.cpp>
diff --git a/WebCore/accessibility/AccessibilityImageMapLink.cpp b/WebCore/accessibility/AccessibilityImageMapLink.cpp
index 943122e..06150b9 100644
--- a/WebCore/accessibility/AccessibilityImageMapLink.cpp
+++ b/WebCore/accessibility/AccessibilityImageMapLink.cpp
@@ -29,8 +29,8 @@
#include "config.h"
#include "AccessibilityImageMapLink.h"
-#include "AccessibilityRenderObject.h"
#include "AXObjectCache.h"
+#include "AccessibilityRenderObject.h"
#include "Document.h"
#include "HTMLNames.h"
#include "IntRect.h"
@@ -68,6 +68,18 @@ AccessibilityObject* AccessibilityImageMapLink::parentObject() const
return m_mapElement->document()->axObjectCache()->getOrCreate(m_mapElement->renderer());
}
+AccessibilityRole AccessibilityImageMapLink::roleValue() const
+{
+ if (!m_areaElement)
+ return WebCoreLinkRole;
+
+ const AtomicString& ariaRole = m_areaElement->getAttribute(roleAttr);
+ if (!ariaRole.isEmpty())
+ return AccessibilityObject::ariaRoleToWebCoreRole(ariaRole);
+
+ return WebCoreLinkRole;
+}
+
Element* AccessibilityImageMapLink::actionElement() const
{
return anchorElement();
@@ -134,5 +146,15 @@ IntSize AccessibilityImageMapLink::size() const
{
return elementRect().size();
}
-
+
+String AccessibilityImageMapLink::stringValueForMSAA() const
+{
+ return url();
+}
+
+String AccessibilityImageMapLink::nameForMSAA() const
+{
+ return accessibilityDescription();
+}
+
} // namespace WebCore
diff --git a/WebCore/accessibility/AccessibilityImageMapLink.h b/WebCore/accessibility/AccessibilityImageMapLink.h
index 2c27e46..3024f37 100644
--- a/WebCore/accessibility/AccessibilityImageMapLink.h
+++ b/WebCore/accessibility/AccessibilityImageMapLink.h
@@ -47,7 +47,7 @@ public:
void setHTMLMapElement(HTMLMapElement* element) { m_mapElement = element; }
void setParent(AccessibilityObject* parent) { m_parent = parent; }
- virtual AccessibilityRole roleValue() const { return WebCoreLinkRole; }
+ virtual AccessibilityRole roleValue() const;
virtual bool accessibilityIsIgnored() const { return false; }
virtual bool isEnabled() const { return true; }
@@ -56,9 +56,13 @@ public:
virtual Element* actionElement() const;
virtual KURL url() const;
virtual bool isLink() const { return true; }
+ virtual bool isLinked() const { return true; }
virtual String title() const;
virtual String accessibilityDescription() const;
-
+
+ virtual String stringValueForMSAA() const;
+ virtual String nameForMSAA() const;
+
virtual IntSize size() const;
virtual IntRect elementRect() const;
diff --git a/WebCore/accessibility/AccessibilityList.cpp b/WebCore/accessibility/AccessibilityList.cpp
index 95239b0..feceee5 100644
--- a/WebCore/accessibility/AccessibilityList.cpp
+++ b/WebCore/accessibility/AccessibilityList.cpp
@@ -55,6 +55,10 @@ PassRefPtr<AccessibilityList> AccessibilityList::create(RenderObject* renderer)
bool AccessibilityList::accessibilityIsIgnored() const
{
+ // Is the platform interested in the object?
+ if (accessibilityPlatformIncludesObject() == IgnoreObject)
+ return true;
+
// lists don't appear on tiger/leopard on the mac
#if ACCESSIBILITY_LISTS
return false;
@@ -83,7 +87,11 @@ bool AccessibilityList::isOrderedList() const
{
if (!m_renderer)
return false;
-
+
+ // ARIA says a directory is like a static table of contents, which sounds like an ordered list.
+ if (ariaRoleAttribute() == DirectoryRole)
+ return true;
+
Node* node = m_renderer->node();
return node && node->hasTagName(olTag);
}
diff --git a/WebCore/accessibility/AccessibilityList.h b/WebCore/accessibility/AccessibilityList.h
index 89befb2..b7265b2 100644
--- a/WebCore/accessibility/AccessibilityList.h
+++ b/WebCore/accessibility/AccessibilityList.h
@@ -47,7 +47,7 @@ public:
static PassRefPtr<AccessibilityList> create(RenderObject*);
virtual ~AccessibilityList();
- virtual bool isList() const { return true; };
+ virtual bool isList() const { return true; }
bool isUnorderedList() const;
bool isOrderedList() const;
bool isDefinitionList() const;
diff --git a/WebCore/accessibility/AccessibilityListBox.cpp b/WebCore/accessibility/AccessibilityListBox.cpp
index 1f37481..2a60294 100644
--- a/WebCore/accessibility/AccessibilityListBox.cpp
+++ b/WebCore/accessibility/AccessibilityListBox.cpp
@@ -31,9 +31,9 @@
#include "AXObjectCache.h"
#include "AccessibilityListBoxOption.h"
-#include "HitTestResult.h"
#include "HTMLNames.h"
#include "HTMLSelectElement.h"
+#include "HitTestResult.h"
#include "RenderListBox.h"
#include "RenderObject.h"
diff --git a/WebCore/accessibility/AccessibilityListBox.h b/WebCore/accessibility/AccessibilityListBox.h
index 3f3352d..ce1abe0 100644
--- a/WebCore/accessibility/AccessibilityListBox.h
+++ b/WebCore/accessibility/AccessibilityListBox.h
@@ -43,7 +43,7 @@ public:
virtual ~AccessibilityListBox();
virtual AccessibilityObject* doAccessibilityHitTest(const IntPoint&) const;
- virtual bool isListBox() const { return true; };
+ virtual bool isListBox() const { return true; }
virtual bool canSetFocusAttribute() const { return true; }
virtual bool canSetSelectedChildrenAttribute() const;
diff --git a/WebCore/accessibility/AccessibilityListBoxOption.cpp b/WebCore/accessibility/AccessibilityListBoxOption.cpp
index 6e3bf98..6a77dac 100644
--- a/WebCore/accessibility/AccessibilityListBoxOption.cpp
+++ b/WebCore/accessibility/AccessibilityListBoxOption.cpp
@@ -34,12 +34,12 @@
#include "Element.h"
#include "HTMLElement.h"
#include "HTMLNames.h"
-#include "HTMLOptionElement.h"
#include "HTMLOptGroupElement.h"
+#include "HTMLOptionElement.h"
#include "HTMLSelectElement.h"
#include "IntRect.h"
-#include "RenderObject.h"
#include "RenderListBox.h"
+#include "RenderObject.h"
using namespace std;
diff --git a/WebCore/accessibility/AccessibilityListBoxOption.h b/WebCore/accessibility/AccessibilityListBoxOption.h
index 933cdeb..f8fd5f0 100644
--- a/WebCore/accessibility/AccessibilityListBoxOption.h
+++ b/WebCore/accessibility/AccessibilityListBoxOption.h
@@ -63,7 +63,7 @@ public:
virtual IntRect elementRect() const;
virtual IntSize size() const;
virtual AccessibilityObject* parentObject() const;
- bool isListBoxOption() const { return true; };
+ bool isListBoxOption() const { return true; }
private:
HTMLElement* m_optionElement;
diff --git a/WebCore/accessibility/AccessibilityMediaControls.cpp b/WebCore/accessibility/AccessibilityMediaControls.cpp
index 7200de9..6151840 100644
--- a/WebCore/accessibility/AccessibilityMediaControls.cpp
+++ b/WebCore/accessibility/AccessibilityMediaControls.cpp
@@ -113,6 +113,8 @@ String AccessibilityMediaControl::controlTypeName() const
DEFINE_STATIC_LOCAL(const String, mediaStatusDisplayName, ("StatusDisplay"));
DEFINE_STATIC_LOCAL(const String, mediaCurrentTimeDisplay, ("CurrentTimeDisplay"));
DEFINE_STATIC_LOCAL(const String, mediaTimeRemainingDisplay, ("TimeRemainingDisplay"));
+ DEFINE_STATIC_LOCAL(const String, mediaShowClosedCaptionsButtonName, ("ShowClosedCaptionsButton"));
+ DEFINE_STATIC_LOCAL(const String, mediaHideClosedCaptionsButtonName, ("HideClosedCaptionsButton"));
switch (controlType()) {
case MediaFullscreenButton:
@@ -139,6 +141,10 @@ String AccessibilityMediaControl::controlTypeName() const
return mediaCurrentTimeDisplay;
case MediaTimeRemainingDisplay:
return mediaTimeRemainingDisplay;
+ case MediaShowClosedCaptionsButton:
+ return mediaShowClosedCaptionsButtonName;
+ case MediaHideClosedCaptionsButton:
+ return mediaHideClosedCaptionsButtonName;
default:
break;
@@ -187,6 +193,8 @@ AccessibilityRole AccessibilityMediaControl::roleValue() const
case MediaReturnToRealtimeButton:
case MediaUnMuteButton:
case MediaPauseButton:
+ case MediaShowClosedCaptionsButton:
+ case MediaHideClosedCaptionsButton:
return ButtonRole;
case MediaStatusDisplay:
diff --git a/WebCore/accessibility/AccessibilityMediaControls.h b/WebCore/accessibility/AccessibilityMediaControls.h
index 9b306fd..6f51b2c 100644
--- a/WebCore/accessibility/AccessibilityMediaControls.h
+++ b/WebCore/accessibility/AccessibilityMediaControls.h
@@ -37,77 +37,77 @@
namespace WebCore {
- class AccessibilityMediaControl : public AccessibilityRenderObject {
+class AccessibilityMediaControl : public AccessibilityRenderObject {
- public:
- static PassRefPtr<AccessibilityObject> create(RenderObject*);
- virtual ~AccessibilityMediaControl() { }
+public:
+ static PassRefPtr<AccessibilityObject> create(RenderObject*);
+ virtual ~AccessibilityMediaControl() { }
- virtual AccessibilityRole roleValue() const;
- virtual bool accessibilityIsIgnored() const;
+ virtual AccessibilityRole roleValue() const;
+ virtual bool accessibilityIsIgnored() const;
- virtual String title() const;
- virtual String accessibilityDescription() const;
- virtual String helpText() const;
+ virtual String title() const;
+ virtual String accessibilityDescription() const;
+ virtual String helpText() const;
- protected:
- AccessibilityMediaControl(RenderObject*);
- MediaControlElementType controlType() const;
- String controlTypeName() const;
- };
+protected:
+ AccessibilityMediaControl(RenderObject*);
+ MediaControlElementType controlType() const;
+ String controlTypeName() const;
+};
- class AccessibilityMediaTimeline : public AccessibilitySlider {
+class AccessibilityMediaTimeline : public AccessibilitySlider {
- public:
- static PassRefPtr<AccessibilityObject> create(RenderObject*);
- virtual ~AccessibilityMediaTimeline() { }
+public:
+ static PassRefPtr<AccessibilityObject> create(RenderObject*);
+ virtual ~AccessibilityMediaTimeline() { }
- virtual bool isMediaTimeline() const { return true; }
+ virtual bool isMediaTimeline() const { return true; }
- virtual String helpText() const;
- virtual String valueDescription() const;
- const AtomicString& getAttribute(const QualifiedName& attribute) const;
+ virtual String helpText() const;
+ virtual String valueDescription() const;
+ const AtomicString& getAttribute(const QualifiedName& attribute) const;
- private:
- AccessibilityMediaTimeline(RenderObject*);
- };
+private:
+ AccessibilityMediaTimeline(RenderObject*);
+};
- class AccessibilityMediaControlsContainer : public AccessibilityMediaControl {
+class AccessibilityMediaControlsContainer : public AccessibilityMediaControl {
- public:
- static PassRefPtr<AccessibilityObject> create(RenderObject*);
- virtual ~AccessibilityMediaControlsContainer() { }
+public:
+ static PassRefPtr<AccessibilityObject> create(RenderObject*);
+ virtual ~AccessibilityMediaControlsContainer() { }
- virtual AccessibilityRole roleValue() const { return ToolbarRole; }
- virtual bool accessibilityIsIgnored() const { return false; }
+ virtual AccessibilityRole roleValue() const { return ToolbarRole; }
+ virtual bool accessibilityIsIgnored() const { return false; }
- virtual String helpText() const;
- virtual String accessibilityDescription() const;
+ virtual String helpText() const;
+ virtual String accessibilityDescription() const;
- private:
- AccessibilityMediaControlsContainer(RenderObject*);
- bool controllingVideoElement() const;
- const String elementTypeName() const;
- };
+private:
+ AccessibilityMediaControlsContainer(RenderObject*);
+ bool controllingVideoElement() const;
+ const String elementTypeName() const;
+};
- class AccessibilityMediaTimeDisplay : public AccessibilityMediaControl {
+class AccessibilityMediaTimeDisplay : public AccessibilityMediaControl {
- public:
- static PassRefPtr<AccessibilityObject> create(RenderObject*);
- virtual ~AccessibilityMediaTimeDisplay() { }
+public:
+ static PassRefPtr<AccessibilityObject> create(RenderObject*);
+ virtual ~AccessibilityMediaTimeDisplay() { }
- virtual AccessibilityRole roleValue() const { return StaticTextRole; }
- virtual bool accessibilityIsIgnored() const;
+ virtual AccessibilityRole roleValue() const { return StaticTextRole; }
+ virtual bool accessibilityIsIgnored() const;
- virtual String stringValue() const;
- virtual String accessibilityDescription() const;
+ virtual String stringValue() const;
+ virtual String accessibilityDescription() const;
- private:
- AccessibilityMediaTimeDisplay(RenderObject*);
- };
+private:
+ AccessibilityMediaTimeDisplay(RenderObject*);
+};
} // namespace WebCore
diff --git a/WebCore/accessibility/AccessibilityObject.cpp b/WebCore/accessibility/AccessibilityObject.cpp
index d7093e4..585e4cb 100644
--- a/WebCore/accessibility/AccessibilityObject.cpp
+++ b/WebCore/accessibility/AccessibilityObject.cpp
@@ -29,8 +29,8 @@
#include "config.h"
#include "AccessibilityObject.h"
-#include "AccessibilityRenderObject.h"
#include "AXObjectCache.h"
+#include "AccessibilityRenderObject.h"
#include "CharacterNames.h"
#include "FloatRect.h"
#include "FocusController.h"
@@ -85,8 +85,9 @@ void AccessibilityObject::detach()
AccessibilityObject* AccessibilityObject::parentObjectUnignored() const
{
AccessibilityObject* parent;
- for (parent = parentObject(); parent && parent->accessibilityIsIgnored(); parent = parent->parentObject())
- ;
+ for (parent = parentObject(); parent && parent->accessibilityIsIgnored(); parent = parent->parentObject()) {
+ }
+
return parent;
}
@@ -275,7 +276,7 @@ VisiblePositionRange AccessibilityObject::rightLineVisiblePositionRange(const Vi
VisiblePosition startPosition = startOfLine(nextVisiblePos);
// fetch for a valid line start position
- if (startPosition.isNull() ) {
+ if (startPosition.isNull()) {
startPosition = visiblePos;
nextVisiblePos = nextVisiblePos.next();
} else
@@ -381,9 +382,8 @@ static bool replacedNodeNeedsCharacter(Node* replacedNode)
{
// we should always be given a rendered node and a replaced node, but be safe
// replaced nodes are either attachments (widgets) or images
- if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode()) {
+ if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode())
return false;
- }
// create an AX object, but skip it if it is not supposed to be seen
AccessibilityObject* object = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer());
@@ -445,7 +445,7 @@ String AccessibilityObject::stringForVisiblePositionRange(const VisiblePositionR
RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end);
for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
// non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
- if (it.length() != 0) {
+ if (it.length()) {
// Add a textual representation for list marker text
String listMarkerText = listMarkerTextForNodeAndPosition(it.node(), visiblePositionRange.start);
if (!listMarkerText.isEmpty())
@@ -459,9 +459,8 @@ String AccessibilityObject::stringForVisiblePositionRange(const VisiblePositionR
ASSERT(node == it.range()->endContainer(exception));
int offset = it.range()->startOffset(exception);
- if (replacedNodeNeedsCharacter(node->childNode(offset))) {
+ if (replacedNodeNeedsCharacter(node->childNode(offset)))
resultVector.append(objectReplacementCharacter);
- }
}
}
@@ -478,9 +477,9 @@ int AccessibilityObject::lengthForVisiblePositionRange(const VisiblePositionRang
RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end);
for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
// non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
- if (it.length() != 0) {
+ if (it.length())
length += it.length();
- } else {
+ else {
// locate the node and starting offset for this replaced range
int exception = 0;
Node* node = it.range()->startContainer(exception);
@@ -754,6 +753,53 @@ AccessibilityObject* AccessibilityObject::anchorElementForNode(Node* node)
return anchorRenderer->document()->axObjectCache()->getOrCreate(anchorRenderer);
}
+void AccessibilityObject::ariaTreeRows(AccessibilityChildrenVector& result)
+{
+ AccessibilityChildrenVector axChildren = children();
+ unsigned count = axChildren.size();
+ for (unsigned k = 0; k < count; ++k) {
+ AccessibilityObject* obj = axChildren[k].get();
+
+ // Add tree items as the rows.
+ if (obj->roleValue() == TreeItemRole)
+ result.append(obj);
+
+ // Now see if this item also has rows hiding inside of it.
+ obj->ariaTreeRows(result);
+ }
+}
+
+void AccessibilityObject::ariaTreeItemContent(AccessibilityChildrenVector& result)
+{
+ // The ARIA tree item content are the item that are not other tree items or their containing groups.
+ AccessibilityChildrenVector axChildren = children();
+ unsigned count = axChildren.size();
+ for (unsigned k = 0; k < count; ++k) {
+ AccessibilityObject* obj = axChildren[k].get();
+ AccessibilityRole role = obj->roleValue();
+ if (role == TreeItemRole || role == GroupRole)
+ continue;
+
+ result.append(obj);
+ }
+}
+
+void AccessibilityObject::ariaTreeItemDisclosedRows(AccessibilityChildrenVector& result)
+{
+ AccessibilityChildrenVector axChildren = children();
+ unsigned count = axChildren.size();
+ for (unsigned k = 0; k < count; ++k) {
+ AccessibilityObject* obj = axChildren[k].get();
+
+ // Add tree items as the rows.
+ if (obj->roleValue() == TreeItemRole)
+ result.append(obj);
+ // If it's not a tree item, then descend into the group to find more tree items.
+ else
+ obj->ariaTreeRows(result);
+ }
+}
+
const String& AccessibilityObject::actionVerb() const
{
// FIXME: Need to add verbs for select elements.
@@ -766,20 +812,20 @@ const String& AccessibilityObject::actionVerb() const
DEFINE_STATIC_LOCAL(const String, noAction, ());
switch (roleValue()) {
- case ButtonRole:
- return buttonAction;
- case TextFieldRole:
- case TextAreaRole:
- return textFieldAction;
- case RadioButtonRole:
- return radioButtonAction;
- case CheckBoxRole:
- return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction;
- case LinkRole:
- case WebCoreLinkRole:
- return linkAction;
- default:
- return noAction;
+ case ButtonRole:
+ return buttonAction;
+ case TextFieldRole:
+ case TextAreaRole:
+ return textFieldAction;
+ case RadioButtonRole:
+ return radioButtonAction;
+ case CheckBoxRole:
+ return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction;
+ case LinkRole:
+ case WebCoreLinkRole:
+ return linkAction;
+ default:
+ return noAction;
}
}
@@ -794,6 +840,93 @@ AccessibilityOrientation AccessibilityObject::orientation() const
// A tie goes to horizontal.
return AccessibilityOrientationHorizontal;
+}
+
+typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap;
+
+struct RoleEntry {
+ String ariaRole;
+ AccessibilityRole webcoreRole;
+};
+
+static ARIARoleMap* createARIARoleMap()
+{
+ const RoleEntry roles[] = {
+ { "alert", ApplicationAlertRole },
+ { "alertdialog", ApplicationAlertDialogRole },
+ { "application", LandmarkApplicationRole },
+ { "article", DocumentArticleRole },
+ { "banner", LandmarkBannerRole },
+ { "button", ButtonRole },
+ { "checkbox", CheckBoxRole },
+ { "complementary", LandmarkComplementaryRole },
+ { "contentinfo", LandmarkContentInfoRole },
+ { "dialog", ApplicationDialogRole },
+ { "directory", DirectoryRole },
+ { "grid", TableRole },
+ { "gridcell", CellRole },
+ { "columnheader", ColumnHeaderRole },
+ { "combobox", ComboBoxRole },
+ { "definition", DefinitionListDefinitionRole },
+ { "document", DocumentRole },
+ { "rowheader", RowHeaderRole },
+ { "group", GroupRole },
+ { "heading", HeadingRole },
+ { "img", ImageRole },
+ { "link", WebCoreLinkRole },
+ { "list", ListRole },
+ { "listitem", GroupRole },
+ { "listbox", ListBoxRole },
+ { "log", ApplicationLogRole },
+ // "option" isn't here because it may map to different roles depending on the parent element's role
+ { "main", LandmarkMainRole },
+ { "marquee", ApplicationMarqueeRole },
+ { "math", DocumentMathRole },
+ { "menu", MenuRole },
+ { "menubar", GroupRole },
+ // "menuitem" isn't here because it may map to different roles depending on the parent element's role
+ { "menuitemcheckbox", MenuItemRole },
+ { "menuitemradio", MenuItemRole },
+ { "note", DocumentNoteRole },
+ { "navigation", LandmarkNavigationRole },
+ { "option", ListBoxOptionRole },
+ { "presentation", IgnoredRole },
+ { "progressbar", ProgressIndicatorRole },
+ { "radio", RadioButtonRole },
+ { "radiogroup", RadioGroupRole },
+ { "region", DocumentRegionRole },
+ { "row", RowRole },
+ { "range", SliderRole },
+ { "scrollbar", ScrollBarRole },
+ { "search", LandmarkSearchRole },
+ { "separator", SplitterRole },
+ { "slider", SliderRole },
+ { "spinbutton", ProgressIndicatorRole },
+ { "status", ApplicationStatusRole },
+ { "tab", TabRole },
+ { "tablist", TabListRole },
+ { "tabpanel", TabPanelRole },
+ { "text", StaticTextRole },
+ { "textbox", TextAreaRole },
+ { "timer", ApplicationTimerRole },
+ { "toolbar", ToolbarRole },
+ { "tooltip", UserInterfaceTooltipRole },
+ { "tree", TreeRole },
+ { "treeitem", TreeItemRole }
+ };
+ ARIARoleMap* roleMap = new ARIARoleMap;
+
+ const unsigned numRoles = sizeof(roles) / sizeof(roles[0]);
+ for (unsigned i = 0; i < numRoles; ++i)
+ roleMap->set(roles[i].ariaRole, roles[i].webcoreRole);
+ return roleMap;
+}
+
+AccessibilityRole AccessibilityObject::ariaRoleToWebCoreRole(const String& value)
+{
+ ASSERT(!value.isEmpty());
+ static const ARIARoleMap* roleMap = createARIARoleMap();
+ return roleMap->get(value);
}
} // namespace WebCore
diff --git a/WebCore/accessibility/AccessibilityObject.h b/WebCore/accessibility/AccessibilityObject.h
index 8fc40e8..8e46311 100644
--- a/WebCore/accessibility/AccessibilityObject.h
+++ b/WebCore/accessibility/AccessibilityObject.h
@@ -161,6 +161,12 @@ enum AccessibilityRole {
AnnotationRole,
SliderThumbRole,
IgnoredRole,
+ TabRole,
+ TabListRole,
+ TabPanelRole,
+ TreeRole,
+ TreeItemRole,
+ DirectoryRole,
// ARIA Grouping roles
LandmarkApplicationRole,
@@ -171,6 +177,9 @@ enum AccessibilityRole {
LandmarkNavigationRole,
LandmarkSearchRole,
+ ApplicationAlertRole,
+ ApplicationAlertDialogRole,
+ ApplicationDialogRole,
ApplicationLogRole,
ApplicationMarqueeRole,
ApplicationStatusRole,
@@ -178,6 +187,7 @@ enum AccessibilityRole {
DocumentRole,
DocumentArticleRole,
+ DocumentMathRole,
DocumentNoteRole,
DocumentRegionRole,
@@ -225,7 +235,7 @@ struct PlainTextRange {
, length(l)
{ }
- bool isNull() const { return start == 0 && length == 0; }
+ bool isNull() const { return !start && !length; }
};
class AccessibilityObject : public RefCounted<AccessibilityObject> {
@@ -237,64 +247,75 @@ public:
typedef Vector<RefPtr<AccessibilityObject> > AccessibilityChildrenVector;
- virtual bool isAccessibilityRenderObject() const { return false; };
- virtual bool isAnchor() const { return false; };
- virtual bool isAttachment() const { return false; };
- virtual bool isHeading() const { return false; };
- virtual bool isLink() const { return false; };
- virtual bool isImage() const { return false; };
- virtual bool isNativeImage() const { return false; };
- virtual bool isImageButton() const { return false; };
- virtual bool isPasswordField() const { return false; };
- virtual bool isTextControl() const { return false; };
- virtual bool isNativeTextControl() const { return false; };
- virtual bool isWebArea() const { return false; };
- virtual bool isCheckboxOrRadio() const { return false; };
- virtual bool isListBox() const { return roleValue() == ListBoxRole; };
+ virtual bool isAccessibilityRenderObject() const { return false; }
+ virtual bool isAnchor() const { return false; }
+ virtual bool isAttachment() const { return false; }
+ virtual bool isHeading() const { return false; }
+ virtual bool isLink() const { return false; }
+ virtual bool isImage() const { return false; }
+ virtual bool isNativeImage() const { return false; }
+ virtual bool isImageButton() const { return false; }
+ virtual bool isPasswordField() const { return false; }
+ virtual bool isTextControl() const { return false; }
+ virtual bool isNativeTextControl() const { return false; }
+ virtual bool isWebArea() const { return false; }
+ virtual bool isCheckboxOrRadio() const { return false; }
+ virtual bool isListBox() const { return roleValue() == ListBoxRole; }
virtual bool isMediaTimeline() const { return false; }
virtual bool isMenuRelated() const { return false; }
virtual bool isMenu() const { return false; }
virtual bool isMenuBar() const { return false; }
virtual bool isMenuButton() const { return false; }
virtual bool isMenuItem() const { return false; }
- virtual bool isFileUploadButton() const { return false; };
+ virtual bool isFileUploadButton() const { return false; }
virtual bool isInputImage() const { return false; }
- virtual bool isProgressIndicator() const { return false; };
- virtual bool isSlider() const { return false; };
- virtual bool isControl() const { return false; };
- virtual bool isList() const { return false; };
- virtual bool isDataTable() const { return false; };
- virtual bool isTableRow() const { return false; };
- virtual bool isTableColumn() const { return false; };
- virtual bool isTableCell() const { return false; };
- virtual bool isFieldset() const { return false; };
- virtual bool isGroup() const { return false; };
+ virtual bool isProgressIndicator() const { return false; }
+ virtual bool isSlider() const { return false; }
+ virtual bool isControl() const { return false; }
+ virtual bool isList() const { return false; }
+ virtual bool isDataTable() const { return false; }
+ virtual bool isTableRow() const { return false; }
+ virtual bool isTableColumn() const { return false; }
+ virtual bool isTableCell() const { return false; }
+ virtual bool isFieldset() const { return false; }
+ virtual bool isGroup() const { return false; }
+ bool isTabList() const { return roleValue() == TabListRole; }
+ bool isTabItem() const { return roleValue() == TabRole; }
bool isRadioGroup() const { return roleValue() == RadioGroupRole; }
+ bool isComboBox() const { return roleValue() == ComboBoxRole; }
+ bool isTree() const { return roleValue() == TreeRole; }
+ bool isTreeItem() const { return roleValue() == TreeItemRole; }
+ bool isScrollbar() const { return roleValue() == ScrollBarRole; }
+ bool isButton() const { return roleValue() == ButtonRole; }
- virtual bool isChecked() const { return false; };
- virtual bool isEnabled() const { return false; };
- virtual bool isSelected() const { return false; };
- virtual bool isFocused() const { return false; };
- virtual bool isHovered() const { return false; };
- virtual bool isIndeterminate() const { return false; };
- virtual bool isLoaded() const { return false; };
- virtual bool isMultiSelect() const { return false; };
- virtual bool isOffScreen() const { return false; };
- virtual bool isPressed() const { return false; };
- virtual bool isReadOnly() const { return false; };
- virtual bool isVisited() const { return false; };
- virtual bool isRequired() const { return false; };
-
- virtual bool canSetFocusAttribute() const { return false; };
- virtual bool canSetTextRangeAttributes() const { return false; };
- virtual bool canSetValueAttribute() const { return false; };
+ virtual bool isChecked() const { return false; }
+ virtual bool isEnabled() const { return false; }
+ virtual bool isSelected() const { return false; }
+ virtual bool isFocused() const { return false; }
+ virtual bool isHovered() const { return false; }
+ virtual bool isIndeterminate() const { return false; }
+ virtual bool isLoaded() const { return false; }
+ virtual bool isMultiSelect() const { return false; }
+ virtual bool isOffScreen() const { return false; }
+ virtual bool isPressed() const { return false; }
+ virtual bool isReadOnly() const { return false; }
+ virtual bool isVisited() const { return false; }
+ virtual bool isRequired() const { return false; }
+ virtual bool isLinked() const { return false; }
+ virtual bool isExpanded() const { return false; }
+ virtual void setIsExpanded(bool) { }
+
+ virtual bool canSetFocusAttribute() const { return false; }
+ virtual bool canSetTextRangeAttributes() const { return false; }
+ virtual bool canSetValueAttribute() const { return false; }
virtual bool canSetSelectedAttribute() const { return false; }
virtual bool canSetSelectedChildrenAttribute() const { return false; }
+ virtual bool canSetExpandedAttribute() const { return false; }
- virtual bool hasIntValue() const { return false; };
+ virtual bool hasIntValue() const { return false; }
- bool accessibilityShouldUseUniqueId() const { return true; };
- virtual bool accessibilityIsIgnored() const { return true; };
+ bool accessibilityShouldUseUniqueId() const { return true; }
+ virtual bool accessibilityIsIgnored() const { return true; }
virtual int headingLevel() const { return 0; }
virtual int intValue() const { return 0; }
@@ -303,9 +324,21 @@ public:
virtual float maxValueForRange() const { return 0.0f; }
virtual float minValueForRange() const { return 0.0f; }
virtual AccessibilityObject* selectedRadioButton() { return 0; }
+ virtual AccessibilityObject* selectedTabItem() { return 0; }
virtual int layoutCount() const { return 0; }
static bool isARIAControl(AccessibilityRole);
static bool isARIAInput(AccessibilityRole);
+ virtual bool supportsARIAOwns() const { return false; }
+ virtual void ariaOwnsElements(AccessibilityChildrenVector&) const { }
+ virtual bool supportsARIAFlowTo() const { return false; }
+ virtual void ariaFlowToElements(AccessibilityChildrenVector&) const { }
+
+ // ARIA drag and drop
+ virtual bool supportsARIADropping() { return false; }
+ virtual bool supportsARIADragging() { return false; }
+ virtual bool isARIAGrabbed() { return false; }
+ virtual void setARIAGrabbed(bool) { }
+ virtual void determineARIADropEffects(Vector<String>&) { }
virtual AccessibilityObject* doAccessibilityHitTest(const IntPoint&) const { return 0; }
virtual AccessibilityObject* focusedUIElement() const { return 0; }
@@ -331,7 +364,6 @@ public:
void setRoleValue(AccessibilityRole role) { m_role = role; }
virtual AccessibilityRole roleValue() const { return m_role; }
- virtual String ariaAccessibilityName(const String&) const { return String(); }
virtual String ariaLabeledByAttribute() const { return String(); }
virtual String ariaDescribedByAttribute() const { return String(); }
virtual String accessibilityDescription() const { return String(); }
@@ -370,20 +402,22 @@ public:
virtual FrameView* topDocumentFrameView() const { return 0; }
virtual FrameView* documentFrameView() const;
virtual String language() const;
-
+ virtual unsigned hierarchicalLevel() const { return 0; }
+
virtual void setFocused(bool) { }
virtual void setSelectedText(const String&) { }
virtual void setSelectedTextRange(const PlainTextRange&) { }
virtual void setValue(const String&) { }
virtual void setSelected(bool) { }
-
+ virtual void setSelectedRows(AccessibilityChildrenVector&) { }
+
virtual void makeRangeVisible(const PlainTextRange&) { }
virtual bool press() const;
bool performDefaultAction() const { return press(); }
-
+
virtual AccessibilityOrientation orientation() const;
- virtual void increment() { };
- virtual void decrement() { };
+ virtual void increment() { }
+ virtual void decrement() { }
virtual void childrenChanged() { }
virtual const AccessibilityChildrenVector& children() { return m_children; }
@@ -392,10 +426,13 @@ public:
virtual bool hasChildren() const { return m_haveChildren; }
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() { }
+ static AccessibilityRole ariaRoleToWebCoreRole(const String&);
+
virtual VisiblePositionRange visiblePositionRange() const { return VisiblePositionRange(); }
virtual VisiblePositionRange visiblePositionRangeForLine(unsigned) const { return VisiblePositionRange(); }
@@ -446,6 +483,18 @@ public:
unsigned doAXLineForIndex(unsigned);
+ virtual String stringValueForMSAA() const { return String(); }
+ virtual String stringRoleForMSAA() const { return String(); }
+ virtual String nameForMSAA() const { return String(); }
+ virtual String descriptionForMSAA() const { return String(); }
+
+ // Used by an ARIA tree to get all its rows.
+ void ariaTreeRows(AccessibilityChildrenVector&);
+ // Used by an ARIA tree item to get all of its direct rows that it can disclose.
+ void ariaTreeItemDisclosedRows(AccessibilityChildrenVector&);
+ // Used by an ARIA tree item to get only its content, and not its child tree items and groups.
+ void ariaTreeItemContent(AccessibilityChildrenVector&);
+
#if HAVE(ACCESSIBILITY)
#if PLATFORM(GTK)
AccessibilityObjectWrapper* wrapper() const;
diff --git a/WebCore/accessibility/AccessibilityRenderObject.cpp b/WebCore/accessibility/AccessibilityRenderObject.cpp
index 4c50b9a..c57dd92 100644
--- a/WebCore/accessibility/AccessibilityRenderObject.cpp
+++ b/WebCore/accessibility/AccessibilityRenderObject.cpp
@@ -30,8 +30,8 @@
#include "AccessibilityRenderObject.h"
#include "AXObjectCache.h"
-#include "AccessibilityListBox.h"
#include "AccessibilityImageMapLink.h"
+#include "AccessibilityListBox.h"
#include "CharacterNames.h"
#include "EventNames.h"
#include "FloatRect.h"
@@ -84,6 +84,7 @@ AccessibilityRenderObject::AccessibilityRenderObject(RenderObject* renderer)
: AccessibilityObject()
, m_renderer(renderer)
, m_ariaRole(UnknownRole)
+ , m_childrenDirty(false)
{
updateAccessibilityRole();
#ifndef NDEBUG
@@ -166,7 +167,7 @@ AccessibilityObject* AccessibilityRenderObject::parentObjectIfExists() const
if (!m_renderer)
return 0;
- RenderObject *parent = m_renderer->parent();
+ RenderObject* parent = m_renderer->parent();
if (!parent)
return 0;
@@ -178,7 +179,7 @@ AccessibilityObject* AccessibilityRenderObject::parentObject() const
if (!m_renderer)
return 0;
- RenderObject *parent = m_renderer->parent();
+ RenderObject* parent = m_renderer->parent();
if (!parent)
return 0;
@@ -296,10 +297,10 @@ bool AccessibilityRenderObject::isSlider() const
bool AccessibilityRenderObject::isMenuRelated() const
{
AccessibilityRole role = roleValue();
- return role == MenuRole ||
- role == MenuBarRole ||
- role == MenuButtonRole ||
- role == MenuItemRole;
+ return role == MenuRole
+ || role == MenuBarRole
+ || role == MenuButtonRole
+ || role == MenuItemRole;
}
bool AccessibilityRenderObject::isMenu() const
@@ -505,6 +506,24 @@ AccessibilityObject* AccessibilityRenderObject::selectedRadioButton()
}
return 0;
}
+
+AccessibilityObject* AccessibilityRenderObject::selectedTabItem()
+{
+ if (!isTabList())
+ return 0;
+
+ // Find the child tab item that is selected (ie. the intValue == 1).
+ AccessibilityObject::AccessibilityChildrenVector tabs;
+ tabChildren(tabs);
+
+ int count = tabs.size();
+ for (int i = 0; i < count; ++i) {
+ AccessibilityObject* object = m_children[i].get();
+ if (object->isTabItem() && object->intValue() == 1)
+ return object;
+ }
+ return 0;
+}
const AtomicString& AccessibilityRenderObject::getAttribute(const QualifiedName& attribute) const
{
@@ -693,6 +712,40 @@ String AccessibilityRenderObject::helpText() const
return String();
}
+unsigned AccessibilityRenderObject::hierarchicalLevel() const
+{
+ if (!m_renderer)
+ return 0;
+
+ Node* node = m_renderer->node();
+ if (!node || !node->isElementNode())
+ return 0;
+ Element* element = static_cast<Element*>(node);
+ String ariaLevel = element->getAttribute(aria_levelAttr);
+ if (!ariaLevel.isEmpty())
+ return ariaLevel.toInt();
+
+ // Only tree item will calculate its level through the DOM currently.
+ if (roleValue() != TreeItemRole)
+ return 0;
+
+ // Hierarchy leveling starts at 0.
+ // We measure tree hierarchy by the number of groups that the item is within.
+ unsigned level = 0;
+ AccessibilityObject* parent = parentObject();
+ while (parent) {
+ AccessibilityRole parentRole = parent->roleValue();
+ if (parentRole == GroupRole)
+ level++;
+ else if (parentRole == TreeRole)
+ break;
+
+ parent = parent->parentObject();
+ }
+
+ return level;
+}
+
String AccessibilityRenderObject::language() const
{
if (!m_renderer)
@@ -780,7 +833,7 @@ String AccessibilityRenderObject::valueDescription() const
float AccessibilityRenderObject::valueForRange() const
{
- if (!isProgressIndicator() && !isSlider())
+ if (!isProgressIndicator() && !isSlider() && !isScrollbar())
return 0.0f;
return getAttribute(aria_valuenowAttr).toFloat();
@@ -807,6 +860,9 @@ String AccessibilityRenderObject::stringValue() const
if (!m_renderer || isPasswordField())
return String();
+ if (ariaRoleAttribute() == StaticTextRole)
+ return text();
+
if (m_renderer->isText())
return textUnderElement();
@@ -864,56 +920,67 @@ static String accessibleNameForNode(Node* node)
return String();
}
-String AccessibilityRenderObject::ariaAccessibilityName(const String& s) const
+String AccessibilityRenderObject::accessibilityDescriptionForElements(Vector<Element*> &elements) const
{
+ Vector<UChar> ariaLabel;
+ unsigned size = elements.size();
+ for (unsigned i = 0; i < size; ++i) {
+ Element* idElement = elements[i];
+
+ String nameFragment = accessibleNameForNode(idElement);
+ ariaLabel.append(nameFragment.characters(), nameFragment.length());
+ for (Node* n = idElement->firstChild(); n; n = n->traverseNextNode(idElement)) {
+ nameFragment = accessibleNameForNode(n);
+ ariaLabel.append(nameFragment.characters(), nameFragment.length());
+ }
+
+ if (i != size - 1)
+ ariaLabel.append(' ');
+ }
+ return String::adopt(ariaLabel);
+}
+
+
+void AccessibilityRenderObject::elementsFromAttribute(Vector<Element*>& elements, const QualifiedName& attribute) const
+{
+ Node* node = m_renderer->node();
+ if (!node || !node->isElementNode())
+ return;
+
Document* document = m_renderer->document();
if (!document)
- return String();
-
- String idList = s;
+ return;
+
+ String idList = getAttribute(attribute).string();
+ if (idList.isEmpty())
+ return;
+
idList.replace('\n', ' ');
Vector<String> idVector;
idList.split(' ', idVector);
-
- Vector<UChar> ariaLabel;
+
unsigned size = idVector.size();
for (unsigned i = 0; i < size; ++i) {
String idName = idVector[i];
Element* idElement = document->getElementById(idName);
- if (idElement) {
- String nameFragment = accessibleNameForNode(idElement);
- ariaLabel.append(nameFragment.characters(), nameFragment.length());
- for (Node* n = idElement->firstChild(); n; n = n->traverseNextNode(idElement)) {
- nameFragment = accessibleNameForNode(n);
- ariaLabel.append(nameFragment.characters(), nameFragment.length());
- }
-
- if (i != size - 1)
- ariaLabel.append(' ');
- }
+ if (idElement)
+ elements.append(idElement);
}
- return String::adopt(ariaLabel);
}
-
+
+void AccessibilityRenderObject::ariaLabeledByElements(Vector<Element*>& elements) const
+{
+ elementsFromAttribute(elements, aria_labeledbyAttr);
+ if (!elements.size())
+ elementsFromAttribute(elements, aria_labelledbyAttr);
+}
+
String AccessibilityRenderObject::ariaLabeledByAttribute() const
{
- Node* node = m_renderer->node();
- if (!node)
- return String();
-
- if (!node->isElementNode())
- return String();
-
- // The ARIA spec uses the British spelling: "labelled." It seems prudent to support the American
- // spelling ("labeled") as well.
- String idList = getAttribute(aria_labeledbyAttr).string();
- if (idList.isEmpty()) {
- idList = getAttribute(aria_labelledbyAttr).string();
- if (idList.isEmpty())
- return String();
- }
-
- return ariaAccessibilityName(idList);
+ Vector<Element*> elements;
+ ariaLabeledByElements(elements);
+
+ return accessibilityDescriptionForElements(elements);
}
static HTMLLabelElement* labelForElement(Element* element)
@@ -990,6 +1057,8 @@ String AccessibilityRenderObject::title() const
|| ariaRole == MenuItemRole
|| ariaRole == MenuButtonRole
|| ariaRole == RadioButtonRole
+ || ariaRole == CheckBoxRole
+ || ariaRole == TabRole
|| isHeading())
return textUnderElement();
@@ -1001,11 +1070,10 @@ String AccessibilityRenderObject::title() const
String AccessibilityRenderObject::ariaDescribedByAttribute() const
{
- String idList = getAttribute(aria_describedbyAttr).string();
- if (idList.isEmpty())
- return String();
+ Vector<Element*> elements;
+ elementsFromAttribute(elements, aria_describedbyAttr);
- return ariaAccessibilityName(idList);
+ return accessibilityDescriptionForElements(elements);
}
String AccessibilityRenderObject::accessibilityDescription() const
@@ -1032,7 +1100,7 @@ String AccessibilityRenderObject::accessibilityDescription() const
}
if (isWebArea()) {
- Document *document = m_renderer->document();
+ Document* document = m_renderer->document();
Node* owner = document->ownerElement();
if (owner) {
if (owner->hasTagName(frameTag) || owner->hasTagName(iframeTag)) {
@@ -1048,12 +1116,7 @@ String AccessibilityRenderObject::accessibilityDescription() const
if (owner && owner->isHTMLElement())
return static_cast<HTMLElement*>(owner)->getAttribute(nameAttr);
}
-
- if (roleValue() == DefinitionListTermRole)
- return AXDefinitionListTermText();
- if (roleValue() == DefinitionListDefinitionRole)
- return AXDefinitionListDefinitionText();
-
+
return String();
}
@@ -1198,6 +1261,8 @@ void AccessibilityRenderObject::addRadioButtonGroupMembers(AccessibilityChildren
// or an internal anchor connection
void AccessibilityRenderObject::linkedUIElements(AccessibilityChildrenVector& linkedUIElements) const
{
+ ariaFlowToElements(linkedUIElements);
+
if (isAnchor()) {
AccessibilityObject* linkedAXElement = internalLinkElement();
if (linkedAXElement)
@@ -1208,6 +1273,71 @@ void AccessibilityRenderObject::linkedUIElements(AccessibilityChildrenVector& li
addRadioButtonGroupMembers(linkedUIElements);
}
+bool AccessibilityRenderObject::hasTextAlternative() const
+{
+ // ARIA: section 2A, bullet #3 says if aria-labeledby or aria-label appears, it should
+ // override the "label" element association.
+ if (!ariaLabeledByAttribute().isEmpty() || !getAttribute(aria_labelAttr).string().isEmpty())
+ return true;
+
+ return false;
+}
+
+bool AccessibilityRenderObject::supportsARIAFlowTo() const
+{
+ return !getAttribute(aria_flowtoAttr).string().isEmpty();
+}
+
+void AccessibilityRenderObject::ariaFlowToElements(AccessibilityChildrenVector& flowTo) const
+{
+ Vector<Element*> elements;
+ elementsFromAttribute(elements, aria_flowtoAttr);
+
+ AXObjectCache* cache = axObjectCache();
+ unsigned count = elements.size();
+ for (unsigned k = 0; k < count; ++k) {
+ Element* element = elements[k];
+ AccessibilityObject* flowToElement = cache->getOrCreate(element->renderer());
+ if (flowToElement)
+ flowTo.append(flowToElement);
+ }
+
+}
+
+bool AccessibilityRenderObject::supportsARIADropping()
+{
+ const AtomicString& dropEffect = getAttribute(aria_dropeffectAttr).string();
+ return !dropEffect.isEmpty();
+}
+
+bool AccessibilityRenderObject::supportsARIADragging()
+{
+ const AtomicString& grabbed = getAttribute(aria_grabbedAttr).string();
+ return equalIgnoringCase(grabbed, "true") || equalIgnoringCase(grabbed, "false");
+}
+
+bool AccessibilityRenderObject::isARIAGrabbed()
+{
+ return elementAttributeValue(aria_grabbedAttr);
+}
+
+void AccessibilityRenderObject::setARIAGrabbed(bool grabbed)
+{
+ setElementAttributeValue(aria_grabbedAttr, grabbed);
+}
+
+void AccessibilityRenderObject::determineARIADropEffects(Vector<String>& effects)
+{
+ String dropEffects = getAttribute(aria_dropeffectAttr).string();
+ if (dropEffects.isEmpty()) {
+ effects.clear();
+ return;
+ }
+
+ dropEffects.replace('\n', ' ');
+ dropEffects.split(' ', effects);
+}
+
bool AccessibilityRenderObject::exposesTitleUIElement() const
{
if (!isControl())
@@ -1217,6 +1347,9 @@ bool AccessibilityRenderObject::exposesTitleUIElement() const
if (isCheckboxOrRadio() && getAttribute(titleAttr).isEmpty())
return false;
+ if (hasTextAlternative())
+ return false;
+
return true;
}
@@ -1256,9 +1389,19 @@ bool AccessibilityRenderObject::ariaIsHidden() const
return false;
}
+bool AccessibilityRenderObject::isDescendantOfBarrenParent() const
+{
+ for (AccessibilityObject* object = parentObject(); object; object = object->parentObject()) {
+ if (!object->canHaveChildren())
+ return true;
+ }
+
+ return false;
+}
+
bool AccessibilityRenderObject::accessibilityIsIgnored() const
{
- // is the platform is interested in this object?
+ // Is the platform interested in this object?
AccessibilityObjectPlatformInclusion decision = accessibilityPlatformIncludesObject();
if (decision == IncludeObject)
return false;
@@ -1276,6 +1419,10 @@ bool AccessibilityRenderObject::accessibilityIsIgnored() const
if (isPresentationalChildOfAriaRole())
return true;
+ // If this element is within a parent that cannot have children, it should not be exposed.
+ if (isDescendantOfBarrenParent())
+ return true;
+
if (roleValue() == IgnoredRole)
return true;
@@ -1288,7 +1435,7 @@ bool AccessibilityRenderObject::accessibilityIsIgnored() const
// find out if this element is inside of a label element.
// if so, it may be ignored because it's the label for a checkbox or radio button
AccessibilityObject* controlObject = correspondingControlForLabelElement();
- if (controlObject && !controlObject->exposesTitleUIElement())
+ if (controlObject && !controlObject->exposesTitleUIElement() && controlObject->isCheckboxOrRadio())
return true;
AccessibilityRole ariaRole = ariaRoleAttribute();
@@ -1300,8 +1447,8 @@ bool AccessibilityRenderObject::accessibilityIsIgnored() const
// NOTE: BRs always have text boxes now, so the text box check here can be removed
if (m_renderer->isText()) {
// static text beneath MenuItems and MenuButtons are just reported along with the menu item, so it's ignored on an individual level
- if (parentObjectUnignored()->ariaRoleAttribute() == MenuItemRole ||
- parentObjectUnignored()->ariaRoleAttribute() == MenuButtonRole)
+ if (parentObjectUnignored()->ariaRoleAttribute() == MenuItemRole
+ || parentObjectUnignored()->ariaRoleAttribute() == MenuButtonRole)
return true;
RenderText* renderText = toRenderText(m_renderer);
if (m_renderer->isBR() || !renderText->firstTextBox())
@@ -1388,6 +1535,10 @@ int AccessibilityRenderObject::layoutCount() const
String AccessibilityRenderObject::text() const
{
+ // If this is a user defined static text, use the accessible name computation.
+ if (ariaRoleAttribute() == StaticTextRole)
+ return accessibilityDescription();
+
if (!isTextControl() || isPasswordField())
return String();
@@ -1545,6 +1696,46 @@ bool AccessibilityRenderObject::isVisited() const
return m_renderer->style()->pseudoState() == PseudoVisited;
}
+bool AccessibilityRenderObject::isExpanded() const
+{
+ if (equalIgnoringCase(getAttribute(aria_expandedAttr).string(), "true"))
+ return true;
+
+ return false;
+}
+
+void AccessibilityRenderObject::setElementAttributeValue(const QualifiedName& attributeName, bool value)
+{
+ if (!m_renderer)
+ return;
+
+ Node* node = m_renderer->node();
+ if (!node || !node->isElementNode())
+ return;
+
+ Element* element = static_cast<Element*>(node);
+ element->setAttribute(attributeName, (value) ? "true" : "false");
+}
+
+bool AccessibilityRenderObject::elementAttributeValue(const QualifiedName& attributeName)
+{
+ if (!m_renderer)
+ return false;
+
+ return equalIgnoringCase(getAttribute(attributeName).string(), "true");
+}
+
+void AccessibilityRenderObject::setIsExpanded(bool isExpanded)
+{
+ // Combo boxes and tree items can be expanded (in different ways on different platforms).
+ // That action translates into setting the aria-expanded attribute to true.
+ AccessibilityRole role = roleValue();
+ if (role != ComboBoxRole && role != TreeItemRole)
+ return;
+
+ setElementAttributeValue(aria_expandedAttr, isExpanded);
+}
+
bool AccessibilityRenderObject::isRequired() const
{
if (equalIgnoringCase(getAttribute(aria_requiredAttr).string(), "true"))
@@ -1562,9 +1753,56 @@ bool AccessibilityRenderObject::isSelected() const
if (!node)
return false;
+ String ariaSelected = getAttribute(aria_selectedAttr).string();
+ if (equalIgnoringCase(ariaSelected, "true"))
+ return true;
+
+ if (isTabItem() && isTabItemSelected())
+ return true;
+
return false;
}
+bool AccessibilityRenderObject::isTabItemSelected() const
+{
+ if (!isTabItem() || !m_renderer)
+ return false;
+
+ Node* node = m_renderer->node();
+ if (!node || !node->isElementNode())
+ return false;
+
+ // The ARIA spec says a tab item can also be selected if it is aria-labeled by a tabpanel
+ // that has keyboard focus inside of it, or if a tabpanel in its aria-controls list has KB
+ // focus inside of it.
+ AccessibilityObject* focusedElement = focusedUIElement();
+ if (!focusedElement)
+ return false;
+
+ Vector<Element*> elements;
+ elementsFromAttribute(elements, aria_controlsAttr);
+
+ unsigned count = elements.size();
+ for (unsigned k = 0; k < count; ++k) {
+ Element* element = elements[k];
+ AccessibilityObject* tabPanel = axObjectCache()->getOrCreate(element->renderer());
+
+ // A tab item should only control tab panels.
+ if (!tabPanel || tabPanel->roleValue() != TabPanelRole)
+ continue;
+
+ AccessibilityObject* checkFocusElement = focusedElement;
+ // Check if the focused element is a descendant of the element controlled by the tab item.
+ while (checkFocusElement) {
+ if (tabPanel == checkFocusElement)
+ return true;
+ checkFocusElement = checkFocusElement->parentObject();
+ }
+ }
+
+ return false;
+}
+
bool AccessibilityRenderObject::isFocused() const
{
if (!m_renderer)
@@ -1580,8 +1818,8 @@ bool AccessibilityRenderObject::isFocused() const
// A web area is represented by the Document node in the DOM tree, which isn't focusable.
// Check instead if the frame's selection controller is focused
- if (focusedNode == m_renderer->node() ||
- (roleValue() == WebAreaRole && document->frame()->selection()->isFocusedAndActive()))
+ if (focusedNode == m_renderer->node()
+ || (roleValue() == WebAreaRole && document->frame()->selection()->isFocusedAndActive()))
return true;
return false;
@@ -1613,6 +1851,26 @@ void AccessibilityRenderObject::changeValueByPercent(float percentChange)
axObjectCache()->postNotification(m_renderer, AXObjectCache::AXValueChanged, true);
}
+void AccessibilityRenderObject::setSelected(bool enabled)
+{
+ setElementAttributeValue(aria_selectedAttr, enabled);
+}
+
+void AccessibilityRenderObject::setSelectedRows(AccessibilityChildrenVector& selectedRows)
+{
+ // Setting selected rows only works on trees for now.
+ if (roleValue() != TreeRole)
+ return;
+
+ bool isMultiselectable = elementAttributeValue(aria_multiselectableAttr);
+ unsigned count = selectedRows.size();
+ if (count > 1 && !isMultiselectable)
+ count = 1;
+
+ for (unsigned k = 0; k < count; ++k)
+ selectedRows[k]->setSelected(true);
+}
+
void AccessibilityRenderObject::setValue(const String& string)
{
if (!m_renderer)
@@ -1632,6 +1890,29 @@ void AccessibilityRenderObject::setValue(const String& string)
}
}
+void AccessibilityRenderObject::ariaOwnsElements(AccessibilityChildrenVector& axObjects) const
+{
+ Vector<Element*> elements;
+ elementsFromAttribute(elements, aria_ownsAttr);
+
+ unsigned count = elements.size();
+ for (unsigned k = 0; k < count; ++k) {
+ RenderObject* render = elements[k]->renderer();
+ AccessibilityObject* obj = axObjectCache()->getOrCreate(render);
+ if (obj)
+ axObjects.append(obj);
+ }
+}
+
+bool AccessibilityRenderObject::supportsARIAOwns() const
+{
+ if (!m_renderer)
+ return false;
+ const AtomicString& ariaOwns = getAttribute(aria_ownsAttr).string();
+
+ return !ariaOwns.isEmpty();
+}
+
bool AccessibilityRenderObject::isEnabled() const
{
ASSERT(m_renderer);
@@ -1777,7 +2058,7 @@ VisiblePositionRange AccessibilityRenderObject::visiblePositionRange() const
VisiblePositionRange AccessibilityRenderObject::visiblePositionRangeForLine(unsigned lineCount) const
{
- if (lineCount == 0 || !m_renderer)
+ if (!lineCount || !m_renderer)
return VisiblePositionRange();
// iterate over the lines
@@ -1785,7 +2066,7 @@ VisiblePositionRange AccessibilityRenderObject::visiblePositionRangeForLine(unsi
// last offset of the last line
VisiblePosition visiblePos = m_renderer->document()->renderer()->positionForCoordinates(0, 0);
VisiblePosition savedVisiblePos;
- while (--lineCount != 0) {
+ while (--lineCount) {
savedVisiblePos = visiblePos;
visiblePos = nextLinePosition(visiblePos, 0);
if (visiblePos.isNull() || visiblePos == savedVisiblePos)
@@ -1900,9 +2181,8 @@ void AccessibilityRenderObject::setSelectedVisiblePositionRange(const VisiblePos
return;
// make selection and tell the document to use it. if it's zero length, then move to that position
- if (range.start == range.end) {
+ if (range.start == range.end)
m_renderer->document()->frame()->selection()->moveTo(range.start, true);
- }
else {
VisibleSelection newSelection = VisibleSelection(range.start, range.end);
m_renderer->document()->frame()->selection()->setSelection(newSelection);
@@ -1998,7 +2278,7 @@ PlainTextRange AccessibilityRenderObject::doAXRangeForLine(unsigned lineNumber)
// iterate to the specified line
VisiblePosition visiblePos = visiblePositionForIndex(0);
VisiblePosition savedVisiblePos;
- for (unsigned lineCount = lineNumber; lineCount != 0; lineCount -= 1) {
+ for (unsigned lineCount = lineNumber; lineCount; lineCount -= 1) {
savedVisiblePos = visiblePos;
visiblePos = nextLinePosition(visiblePos, 0);
if (visiblePos.isNull() || visiblePos == savedVisiblePos)
@@ -2053,8 +2333,8 @@ String AccessibilityRenderObject::doAXStringForRange(const PlainTextRange& range
if (isPasswordField())
return String();
- if (range.length == 0)
- return "";
+ if (!range.length)
+ return String();
if (!isTextControl())
return String();
@@ -2081,7 +2361,7 @@ AccessibilityObject* AccessibilityRenderObject::accessibilityImageMapHitTest(HTM
if (!area)
return 0;
- HTMLMapElement *map = static_cast<HTMLMapElement*>(area->parent());
+ HTMLMapElement* map = static_cast<HTMLMapElement*>(area->parent());
AccessibilityObject* parent = accessibilityParentForImageMap(map);
if (!parent)
return 0;
@@ -2159,14 +2439,14 @@ bool AccessibilityRenderObject::shouldFocusActiveDescendant() const
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:
@@ -2176,19 +2456,22 @@ bool AccessibilityRenderObject::shouldFocusActiveDescendant() const
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;
@@ -2207,7 +2490,7 @@ void AccessibilityRenderObject::handleActiveDescendantChanged()
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
@@ -2247,80 +2530,6 @@ AccessibilityObject* AccessibilityRenderObject::observableObject() const
return 0;
}
-
-typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap;
-
-struct RoleEntry {
- String ariaRole;
- AccessibilityRole webcoreRole;
-};
-
-static const ARIARoleMap& createARIARoleMap()
-{
- const RoleEntry roles[] = {
- { "application", LandmarkApplicationRole },
- { "article", DocumentArticleRole },
- { "banner", LandmarkBannerRole },
- { "button", ButtonRole },
- { "checkbox", CheckBoxRole },
- { "complementary", LandmarkComplementaryRole },
- { "contentinfo", LandmarkContentInfoRole },
- { "grid", TableRole },
- { "gridcell", CellRole },
- { "columnheader", ColumnHeaderRole },
- { "definition", DefinitionListDefinitionRole },
- { "document", DocumentRole },
- { "rowheader", RowHeaderRole },
- { "group", GroupRole },
- { "heading", HeadingRole },
- { "img", ImageRole },
- { "link", WebCoreLinkRole },
- { "list", ListRole },
- { "listitem", GroupRole },
- { "listbox", ListBoxRole },
- { "log", ApplicationLogRole },
- // "option" isn't here because it may map to different roles depending on the parent element's role
- { "main", LandmarkMainRole },
- { "marquee", ApplicationMarqueeRole },
- { "menu", MenuRole },
- { "menubar", GroupRole },
- // "menuitem" isn't here because it may map to different roles depending on the parent element's role
- { "menuitemcheckbox", MenuItemRole },
- { "menuitemradio", MenuItemRole },
- { "note", DocumentNoteRole },
- { "navigation", LandmarkNavigationRole },
- { "option", ListBoxOptionRole },
- { "presentation", IgnoredRole },
- { "progressbar", ProgressIndicatorRole },
- { "radio", RadioButtonRole },
- { "radiogroup", RadioGroupRole },
- { "region", DocumentRegionRole },
- { "row", RowRole },
- { "range", SliderRole },
- { "search", LandmarkSearchRole },
- { "separator", SplitterRole },
- { "slider", SliderRole },
- { "spinbutton", ProgressIndicatorRole },
- { "status", ApplicationStatusRole },
- { "textbox", TextAreaRole },
- { "timer", ApplicationTimerRole },
- { "toolbar", ToolbarRole },
- { "tooltip", UserInterfaceTooltipRole }
- };
- ARIARoleMap& roleMap = *new ARIARoleMap;
-
- const unsigned numRoles = sizeof(roles) / sizeof(roles[0]);
- for (unsigned i = 0; i < numRoles; ++i)
- roleMap.set(roles[i].ariaRole, roles[i].webcoreRole);
- return roleMap;
-}
-
-static AccessibilityRole ariaRoleToWebCoreRole(String value)
-{
- ASSERT(!value.isEmpty() && !value.isNull());
- static const ARIARoleMap& roleMap = createARIARoleMap();
- return roleMap.get(value);
-}
AccessibilityRole AccessibilityRenderObject::determineAriaRoleAttribute() const
{
@@ -2332,14 +2541,14 @@ AccessibilityRole AccessibilityRenderObject::determineAriaRoleAttribute() const
if (role)
return role;
// selects and listboxes both have options as child roles, but they map to different roles within WebCore
- if (equalIgnoringCase(ariaRole,"option")) {
+ if (equalIgnoringCase(ariaRole, "option")) {
if (parentObjectUnignored()->ariaRoleAttribute() == MenuRole)
return MenuItemRole;
if (parentObjectUnignored()->ariaRoleAttribute() == ListBoxRole)
return ListBoxOptionRole;
}
// an aria "menuitem" may map to MenuButton or MenuItem depending on its parent
- if (equalIgnoringCase(ariaRole,"menuitem")) {
+ if (equalIgnoringCase(ariaRole, "menuitem")) {
if (parentObjectUnignored()->ariaRoleAttribute() == GroupRole)
return MenuButtonRole;
if (parentObjectUnignored()->ariaRoleAttribute() == MenuRole)
@@ -2418,7 +2627,7 @@ AccessibilityRole AccessibilityRenderObject::determineAccessibilityRole()
if (m_renderer->isMenuList())
return PopUpButtonRole;
- if (headingLevel() != 0)
+ if (headingLevel())
return HeadingRole;
if (node && node->hasTagName(ddTag))
@@ -2436,12 +2645,24 @@ AccessibilityRole AccessibilityRenderObject::determineAccessibilityRole()
return UnknownRole;
}
+AccessibilityOrientation AccessibilityRenderObject::orientation() const
+{
+ const AtomicString& ariaOrientation = getAttribute(aria_orientationAttr).string();
+ if (equalIgnoringCase(ariaOrientation, "horizontal"))
+ return AccessibilityOrientationHorizontal;
+ if (equalIgnoringCase(ariaOrientation, "vertical"))
+ return AccessibilityOrientationVertical;
+
+ return AccessibilityObject::orientation();
+}
+
bool AccessibilityRenderObject::isPresentationalChildOfAriaRole() const
{
// Walk the parent chain looking for a parent that has presentational children
AccessibilityObject* parent;
for (parent = parentObject(); parent && !parent->ariaRoleHasPresentationalChildren(); parent = parent->parentObject())
- ;
+ { }
+
return parent;
}
@@ -2474,20 +2695,27 @@ bool AccessibilityRenderObject::canSetFocusAttribute() const
return false;
switch (roleValue()) {
- case WebCoreLinkRole:
- case ImageMapLinkRole:
- case TextFieldRole:
- case TextAreaRole:
- case ButtonRole:
- case PopUpButtonRole:
- case CheckBoxRole:
- case RadioButtonRole:
- case SliderRole:
- return true;
- default:
- return false;
+ case WebCoreLinkRole:
+ case ImageMapLinkRole:
+ case TextFieldRole:
+ case TextAreaRole:
+ case ButtonRole:
+ case PopUpButtonRole:
+ case CheckBoxRole:
+ case RadioButtonRole:
+ case SliderRole:
+ return true;
+ default:
+ return false;
}
}
+
+bool AccessibilityRenderObject::canSetExpandedAttribute() const
+{
+ // An object can be expanded if it aria-expanded is true or false.
+ String ariaExpanded = getAttribute(aria_expandedAttr).string();
+ return equalIgnoringCase(ariaExpanded, "true") || equalIgnoringCase(ariaExpanded, "false");
+}
bool AccessibilityRenderObject::canSetValueAttribute() const
{
@@ -2531,16 +2759,18 @@ bool AccessibilityRenderObject::canHaveChildren() const
// Elements that should not have children
switch (roleValue()) {
- case ImageRole:
- case ButtonRole:
- case PopUpButtonRole:
- case CheckBoxRole:
- case RadioButtonRole:
- case StaticTextRole:
- case ListBoxOptionRole:
- return false;
- default:
- return true;
+ case ImageRole:
+ case ButtonRole:
+ case PopUpButtonRole:
+ case CheckBoxRole:
+ case RadioButtonRole:
+ case TabRole:
+ case StaticTextRole:
+ case ListBoxOptionRole:
+ case ScrollBarRole:
+ return false;
+ default:
+ return true;
}
}
@@ -2604,17 +2834,42 @@ void AccessibilityRenderObject::addChildren()
}
}
+void AccessibilityRenderObject::ariaTreeSelectedRows(AccessibilityChildrenVector& result)
+{
+ // Get all the rows.
+ AccessibilityChildrenVector allRows;
+ ariaTreeRows(allRows);
+
+ // 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()) {
+ result.append(allRows[k]);
+ if (!isMultiselectable)
+ break;
+ }
+ }
+}
+
void AccessibilityRenderObject::ariaListboxSelectedChildren(AccessibilityChildrenVector& result)
{
AccessibilityObject* child = firstChild();
- bool isMultiselectable = false;
Element* element = static_cast<Element*>(renderer()->node());
if (!element || !element->isElementNode()) // do this check to ensure safety of static_cast above
return;
- String multiselectablePropertyStr = element->getAttribute("aria-multiselectable").string();
- isMultiselectable = equalIgnoringCase(multiselectablePropertyStr, "true");
+ bool isMultiselectable = elementAttributeValue(aria_multiselectableAttr);
while (child) {
// every child should have aria-role option, and if so, check for selected attribute/state
@@ -2625,7 +2880,7 @@ void AccessibilityRenderObject::ariaListboxSelectedChildren(AccessibilityChildre
if (childRenderer && ariaRole == ListBoxOptionRole) {
Element* childElement = static_cast<Element*>(childRenderer->node());
if (childElement && childElement->isElementNode()) { // do this check to ensure safety of static_cast above
- String selectedAttrString = childElement->getAttribute("aria-selected").string();
+ String selectedAttrString = childElement->getAttribute(aria_selectedAttr).string();
if (equalIgnoringCase(selectedAttrString, "true")) {
result.append(child);
if (isMultiselectable)
@@ -2642,11 +2897,11 @@ void AccessibilityRenderObject::selectedChildren(AccessibilityChildrenVector& re
ASSERT(result.isEmpty());
// only listboxes should be asked for their selected children.
- if (ariaRoleAttribute() != ListBoxRole) { // native list boxes would be AccessibilityListBoxes, so only check for aria list boxes
- ASSERT_NOT_REACHED();
- return;
- }
- return ariaListboxSelectedChildren(result);
+ AccessibilityRole role = roleValue();
+ if (role == ListBoxRole) // native list boxes would be AccessibilityListBoxes, so only check for aria list boxes
+ ariaListboxSelectedChildren(result);
+ else if (role == TreeRole)
+ ariaTreeSelectedRows(result);
}
void AccessibilityRenderObject::ariaListboxVisibleChildren(AccessibilityChildrenVector& result)
@@ -2673,6 +2928,17 @@ void AccessibilityRenderObject::visibleChildren(AccessibilityChildrenVector& res
return ariaListboxVisibleChildren(result);
}
+void AccessibilityRenderObject::tabChildren(AccessibilityChildrenVector& result)
+{
+ ASSERT(roleValue() == TabListRole);
+
+ unsigned length = m_children.size();
+ for (unsigned i = 0; i < length; ++i) {
+ if (m_children[i]->isTabItem())
+ result.append(m_children[i]);
+ }
+}
+
const String& AccessibilityRenderObject::actionVerb() const
{
// FIXME: Need to add verbs for select elements.
@@ -2685,20 +2951,20 @@ const String& AccessibilityRenderObject::actionVerb() const
DEFINE_STATIC_LOCAL(const String, noAction, ());
switch (roleValue()) {
- case ButtonRole:
- return buttonAction;
- case TextFieldRole:
- case TextAreaRole:
- return textFieldAction;
- case RadioButtonRole:
- return radioButtonAction;
- case CheckBoxRole:
- return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction;
- case LinkRole:
- case WebCoreLinkRole:
- return linkAction;
- default:
- return noAction;
+ case ButtonRole:
+ return buttonAction;
+ case TextFieldRole:
+ case TextAreaRole:
+ return textFieldAction;
+ case RadioButtonRole:
+ return radioButtonAction;
+ case CheckBoxRole:
+ return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction;
+ case LinkRole:
+ case WebCoreLinkRole:
+ return linkAction;
+ default:
+ return noAction;
}
}
@@ -2711,4 +2977,101 @@ void AccessibilityRenderObject::updateBackingStore()
m_renderer->document()->updateLayoutIgnorePendingStylesheets();
}
+static bool isLinkable(const AccessibilityRenderObject& object)
+{
+ if (!object.renderer())
+ return false;
+
+ // See https://wiki.mozilla.org/Accessibility/AT-Windows-API for the elements
+ // Mozilla considers linkable.
+ return object.isLink() || object.isImage() || object.renderer()->isText();
+}
+
+String AccessibilityRenderObject::stringValueForMSAA() const
+{
+ if (isLinkable(*this)) {
+ Element* anchor = anchorElement();
+ if (anchor && anchor->hasTagName(aTag))
+ return static_cast<HTMLAnchorElement*>(anchor)->href();
+ }
+
+ return stringValue();
+}
+
+bool AccessibilityRenderObject::isLinked() const
+{
+ if (!isLinkable(*this))
+ return false;
+
+ Element* anchor = anchorElement();
+ if (!anchor || !anchor->hasTagName(aTag))
+ return false;
+
+ return !static_cast<HTMLAnchorElement*>(anchor)->href().isEmpty();
+}
+
+String AccessibilityRenderObject::nameForMSAA() const
+{
+ if (m_renderer && m_renderer->isText())
+ return textUnderElement();
+
+ return title();
+}
+
+static bool shouldReturnTagNameAsRoleForMSAA(const Element& element)
+{
+ // See "document structure",
+ // https://wiki.mozilla.org/Accessibility/AT-Windows-API
+ // FIXME: Add the other tag names that should be returned as the role.
+ return element.hasTagName(h1Tag) || element.hasTagName(h2Tag)
+ || element.hasTagName(h3Tag) || element.hasTagName(h4Tag)
+ || element.hasTagName(h5Tag) || element.hasTagName(h6Tag);
+}
+
+String AccessibilityRenderObject::stringRoleForMSAA() const
+{
+ if (!m_renderer)
+ return String();
+
+ Node* node = m_renderer->node();
+ if (!node || !node->isElementNode())
+ return String();
+
+ Element* element = static_cast<Element*>(node);
+ if (!shouldReturnTagNameAsRoleForMSAA(*element))
+ return String();
+
+ return element->tagName();
+}
+
+String AccessibilityRenderObject::positionalDescriptionForMSAA() const
+{
+ // See "positional descriptions",
+ // https://wiki.mozilla.org/Accessibility/AT-Windows-API
+ if (isHeading())
+ return "L" + String::number(headingLevel());
+
+ // FIXME: Add positional descriptions for other elements.
+ return String();
+}
+
+String AccessibilityRenderObject::descriptionForMSAA() const
+{
+ String description = positionalDescriptionForMSAA();
+ if (!description.isEmpty())
+ return description;
+
+ description = accessibilityDescription();
+ if (!description.isEmpty()) {
+ // From the Mozilla MSAA implementation:
+ // "Signal to screen readers that this description is speakable and is not
+ // a formatted positional information description. Don't localize the
+ // 'Description: ' part of this string, it will be parsed out by assistive
+ // technologies."
+ return "Description: " + description;
+ }
+
+ return String();
+}
+
} // namespace WebCore
diff --git a/WebCore/accessibility/AccessibilityRenderObject.h b/WebCore/accessibility/AccessibilityRenderObject.h
index c6fd748..d537881 100644
--- a/WebCore/accessibility/AccessibilityRenderObject.h
+++ b/WebCore/accessibility/AccessibilityRenderObject.h
@@ -62,7 +62,7 @@ public:
static PassRefPtr<AccessibilityRenderObject> create(RenderObject*);
virtual ~AccessibilityRenderObject();
- bool isAccessibilityRenderObject() const { return true; };
+ bool isAccessibilityRenderObject() const { return true; }
virtual bool isAnchor() const;
virtual bool isAttachment() const;
@@ -102,12 +102,16 @@ public:
virtual bool isReadOnly() const;
virtual bool isVisited() const;
virtual bool isRequired() const;
+ virtual bool isLinked() const;
+ virtual bool isExpanded() const;
+ virtual void setIsExpanded(bool);
const AtomicString& getAttribute(const QualifiedName&) const;
virtual bool canSetFocusAttribute() const;
virtual bool canSetTextRangeAttributes() const;
virtual bool canSetValueAttribute() const;
-
+ virtual bool canSetExpandedAttribute() const;
+
virtual bool hasIntValue() const;
virtual bool accessibilityIsIgnored() const;
@@ -119,6 +123,7 @@ public:
virtual float maxValueForRange() const;
virtual float minValueForRange() const;
virtual AccessibilityObject* selectedRadioButton();
+ virtual AccessibilityObject* selectedTabItem();
virtual int layoutCount() const;
virtual AccessibilityObject* doAccessibilityHitTest(const IntPoint&) const;
@@ -136,6 +141,8 @@ public:
virtual AccessibilityObject* correspondingControlForLabelElement() const;
virtual AccessibilityObject* correspondingLabelForControlElement() const;
+ virtual void ariaOwnsElements(AccessibilityChildrenVector&) const;
+ virtual bool supportsARIAOwns() const;
virtual AccessibilityRole ariaRoleAttribute() const;
virtual bool isPresentationalChildOfAriaRole() const;
virtual bool ariaRoleHasPresentationalChildren() const;
@@ -167,7 +174,6 @@ public:
virtual PlainTextRange selectedTextRange() const;
virtual VisibleSelection selection() const;
virtual String stringValue() const;
- virtual String ariaAccessibilityName(const String&) const;
virtual String ariaLabeledByAttribute() const;
virtual String title() const;
virtual String ariaDescribedByAttribute() const;
@@ -185,13 +191,17 @@ public:
virtual void getDocumentLinks(AccessibilityChildrenVector&);
virtual FrameView* documentFrameView() const;
virtual String language() const;
-
+ virtual unsigned hierarchicalLevel() const;
+
virtual const AccessibilityChildrenVector& children();
virtual void setFocused(bool);
virtual void setSelectedTextRange(const PlainTextRange&);
virtual void setValue(const String&);
+ virtual void setSelected(bool);
+ virtual void setSelectedRows(AccessibilityChildrenVector&);
virtual void changeValueByPercent(float percentChange);
+ virtual AccessibilityOrientation orientation() const;
virtual void increment();
virtual void decrement();
@@ -201,6 +211,7 @@ public:
virtual bool canHaveChildren() const;
virtual void selectedChildren(AccessibilityChildrenVector&);
virtual void visibleChildren(AccessibilityChildrenVector&);
+ virtual void tabChildren(AccessibilityChildrenVector&);
virtual bool shouldFocusActiveDescendant() const;
virtual AccessibilityObject* activeDescendant() const;
virtual void handleActiveDescendantChanged();
@@ -209,6 +220,14 @@ public:
virtual VisiblePositionRange visiblePositionRangeForLine(unsigned) const;
virtual IntRect boundsForVisiblePositionRange(const VisiblePositionRange&) const;
virtual void setSelectedVisiblePositionRange(const VisiblePositionRange&) const;
+ virtual bool supportsARIAFlowTo() const;
+ virtual void ariaFlowToElements(AccessibilityChildrenVector&) const;
+
+ virtual bool supportsARIADropping();
+ virtual bool supportsARIADragging();
+ virtual bool isARIAGrabbed();
+ virtual void setARIAGrabbed(bool);
+ virtual void determineARIADropEffects(Vector<String>&);
virtual VisiblePosition visiblePositionForPoint(const IntPoint&) const;
virtual VisiblePosition visiblePositionForIndex(unsigned indexValue, bool lastIndexOK) const;
@@ -224,13 +243,19 @@ public:
virtual IntRect doAXBoundsForRange(const PlainTextRange&) const;
virtual void updateBackingStore();
-
+
+ virtual String stringValueForMSAA() const;
+ virtual String stringRoleForMSAA() const;
+ virtual String nameForMSAA() const;
+ virtual String descriptionForMSAA() const;
+
protected:
RenderObject* m_renderer;
AccessibilityRole m_ariaRole;
mutable bool m_childrenDirty;
void setRenderObject(RenderObject* renderer) { m_renderer = renderer; }
+ void ariaLabeledByElements(Vector<Element*>& elements) const;
virtual bool isDetached() const { return !m_renderer; }
@@ -238,18 +263,30 @@ private:
void ariaListboxSelectedChildren(AccessibilityChildrenVector&);
void ariaListboxVisibleChildren(AccessibilityChildrenVector&);
bool ariaIsHidden() const;
+ bool isDescendantOfBarrenParent() const;
+ bool hasTextAlternative() const;
+ String positionalDescriptionForMSAA() const;
Element* menuElementForMenuButton() const;
Element* menuItemElementForMenu() const;
AccessibilityRole determineAccessibilityRole();
AccessibilityRole determineAriaRoleAttribute() const;
+ bool isTabItemSelected() const;
IntRect checkboxOrRadioRect() const;
void addRadioButtonGroupMembers(AccessibilityChildrenVector& linkedUIElements) const;
AccessibilityObject* internalLinkElement() const;
AccessibilityObject* accessibilityImageMapHitTest(HTMLAreaElement*, const IntPoint&) const;
AccessibilityObject* accessibilityParentForImageMap(HTMLMapElement* map) const;
+ void ariaTreeSelectedRows(AccessibilityChildrenVector&);
+
+ bool elementAttributeValue(const QualifiedName&);
+ void setElementAttributeValue(const QualifiedName&, bool);
+
+ String accessibilityDescriptionForElements(Vector<Element*> &elements) const;
+ void elementsFromAttribute(Vector<Element*>& elements, const QualifiedName& name) const;
+
void markChildrenDirty() const { m_childrenDirty = true; }
};
diff --git a/WebCore/accessibility/AccessibilitySlider.cpp b/WebCore/accessibility/AccessibilitySlider.cpp
index 5aca672..77f4dcc 100644
--- a/WebCore/accessibility/AccessibilitySlider.cpp
+++ b/WebCore/accessibility/AccessibilitySlider.cpp
@@ -68,18 +68,18 @@ AccessibilityOrientation AccessibilitySlider::orientation() const
ControlPart styleAppearance = style->appearance();
switch (styleAppearance) {
- case SliderThumbHorizontalPart:
- case SliderHorizontalPart:
- case MediaSliderPart:
- return AccessibilityOrientationHorizontal;
+ case SliderThumbHorizontalPart:
+ case SliderHorizontalPart:
+ case MediaSliderPart:
+ return AccessibilityOrientationHorizontal;
+
+ case SliderThumbVerticalPart:
+ case SliderVerticalPart:
+ case MediaVolumeSliderPart:
+ return AccessibilityOrientationVertical;
- case SliderThumbVerticalPart:
- case SliderVerticalPart:
- case MediaVolumeSliderPart:
- return AccessibilityOrientationVertical;
-
- default:
- return AccessibilityOrientationHorizontal;
+ default:
+ return AccessibilityOrientationHorizontal;
}
}
diff --git a/WebCore/accessibility/AccessibilitySlider.h b/WebCore/accessibility/AccessibilitySlider.h
index 254ebdd..e1e3812 100644
--- a/WebCore/accessibility/AccessibilitySlider.h
+++ b/WebCore/accessibility/AccessibilitySlider.h
@@ -33,58 +33,58 @@
namespace WebCore {
- class HTMLInputElement;
+class HTMLInputElement;
- class AccessibilitySlider : public AccessibilityRenderObject {
-
- public:
- static PassRefPtr<AccessibilitySlider> create(RenderObject*);
- virtual ~AccessibilitySlider() { }
+class AccessibilitySlider : public AccessibilityRenderObject {
+
+public:
+ static PassRefPtr<AccessibilitySlider> create(RenderObject*);
+ virtual ~AccessibilitySlider() { }
- virtual AccessibilityRole roleValue() const { return SliderRole; }
- virtual bool accessibilityIsIgnored() const { return false; }
+ virtual AccessibilityRole roleValue() const { return SliderRole; }
+ virtual bool accessibilityIsIgnored() const { return false; }
- virtual bool isSlider() const { return true; }
+ virtual bool isSlider() const { return true; }
- virtual const AccessibilityChildrenVector& children();
- virtual void addChildren();
+ virtual const AccessibilityChildrenVector& children();
+ virtual void addChildren();
- virtual bool canSetValueAttribute() const { return true; };
- const AtomicString& getAttribute(const QualifiedName& attribute) const;
+ virtual bool canSetValueAttribute() const { return true; }
+ const AtomicString& getAttribute(const QualifiedName& attribute) const;
- virtual void setValue(const String&);
- virtual float valueForRange() const;
- virtual float maxValueForRange() const;
- virtual float minValueForRange() const;
- virtual AccessibilityOrientation orientation() const;
+ virtual void setValue(const String&);
+ virtual float valueForRange() const;
+ virtual float maxValueForRange() const;
+ virtual float minValueForRange() const;
+ virtual AccessibilityOrientation orientation() const;
- protected:
- AccessibilitySlider(RenderObject*);
+protected:
+ AccessibilitySlider(RenderObject*);
- private:
- HTMLInputElement* element() const;
- };
+private:
+ HTMLInputElement* element() const;
+};
- class AccessibilitySliderThumb : public AccessibilityObject {
-
- public:
- static PassRefPtr<AccessibilitySliderThumb> create();
- virtual ~AccessibilitySliderThumb() { }
+class AccessibilitySliderThumb : public AccessibilityObject {
+
+public:
+ static PassRefPtr<AccessibilitySliderThumb> create();
+ virtual ~AccessibilitySliderThumb() { }
- virtual AccessibilityRole roleValue() const { return SliderThumbRole; }
- virtual bool accessibilityIsIgnored() const { return false; }
+ virtual AccessibilityRole roleValue() const { return SliderThumbRole; }
+ virtual bool accessibilityIsIgnored() const { return false; }
- void setParentObject(AccessibilitySlider* slider) { m_parentSlider = slider; }
- virtual AccessibilityObject* parentObject() const { return m_parentSlider; }
+ void setParentObject(AccessibilitySlider* slider) { m_parentSlider = slider; }
+ virtual AccessibilityObject* parentObject() const { return m_parentSlider; }
- virtual IntSize size() const;
- virtual IntRect elementRect() const;
+ virtual IntSize size() const;
+ virtual IntRect elementRect() const;
- private:
- AccessibilitySliderThumb();
+private:
+ AccessibilitySliderThumb();
- AccessibilitySlider* m_parentSlider;
- };
+ AccessibilitySlider* m_parentSlider;
+};
} // namespace WebCore
diff --git a/WebCore/accessibility/AccessibilityTable.cpp b/WebCore/accessibility/AccessibilityTable.cpp
index 928ef2c..9ac1046 100644
--- a/WebCore/accessibility/AccessibilityTable.cpp
+++ b/WebCore/accessibility/AccessibilityTable.cpp
@@ -29,15 +29,15 @@
#include "config.h"
#include "AccessibilityTable.h"
+#include "AXObjectCache.h"
#include "AccessibilityTableCell.h"
#include "AccessibilityTableColumn.h"
#include "AccessibilityTableHeaderContainer.h"
#include "AccessibilityTableRow.h"
-#include "AXObjectCache.h"
#include "HTMLNames.h"
-#include "HTMLTableElement.h"
#include "HTMLTableCaptionElement.h"
#include "HTMLTableCellElement.h"
+#include "HTMLTableElement.h"
#include "RenderObject.h"
#include "RenderTable.h"
#include "RenderTableCell.h"
@@ -149,8 +149,8 @@ bool AccessibilityTable::isTableExposableThroughAccessibility()
HTMLTableCellElement* cellElement = static_cast<HTMLTableCellElement*>(cellNode);
// in this case, the developer explicitly assigned a "data" table attribute
- if (!cellElement->headers().isEmpty() || !cellElement->abbr().isEmpty() ||
- !cellElement->axis().isEmpty() || !cellElement->scope().isEmpty())
+ if (!cellElement->headers().isEmpty() || !cellElement->abbr().isEmpty()
+ || !cellElement->axis().isEmpty() || !cellElement->scope().isEmpty())
return true;
RenderStyle* renderStyle = cell->style();
@@ -158,15 +158,15 @@ bool AccessibilityTable::isTableExposableThroughAccessibility()
continue;
// a cell needs to have matching bordered sides, before it can be considered a bordered cell.
- if ((cell->borderTop() > 0 && cell->borderBottom() > 0) ||
- (cell->borderLeft() > 0 && cell->borderRight() > 0))
+ if ((cell->borderTop() > 0 && cell->borderBottom() > 0)
+ || (cell->borderLeft() > 0 && cell->borderRight() > 0))
borderedCellCount++;
// if the cell has a different color from the table and there is cell spacing,
// then it is probably a data table cell (spacing and colors take the place of borders)
Color cellColor = renderStyle->backgroundColor();
- if (table->hBorderSpacing() > 0 && table->vBorderSpacing() > 0 &&
- tableBGColor != cellColor && cellColor.alpha() != 1)
+ if (table->hBorderSpacing() > 0 && table->vBorderSpacing() > 0
+ && tableBGColor != cellColor && cellColor.alpha() != 1)
backgroundDifferenceCellCount++;
// if we've found 10 "good" cells, we don't need to keep searching
diff --git a/WebCore/accessibility/AccessibilityTableColumn.cpp b/WebCore/accessibility/AccessibilityTableColumn.cpp
index e09d65e..ee8531e 100644
--- a/WebCore/accessibility/AccessibilityTableColumn.cpp
+++ b/WebCore/accessibility/AccessibilityTableColumn.cpp
@@ -29,12 +29,12 @@
#include "config.h"
#include "AccessibilityTableColumn.h"
-#include "AccessibilityTableCell.h"
#include "AXObjectCache.h"
+#include "AccessibilityTableCell.h"
#include "HTMLNames.h"
#include "RenderTable.h"
-#include "RenderTableSection.h"
#include "RenderTableCell.h"
+#include "RenderTableSection.h"
using namespace std;
diff --git a/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp b/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp
index af9de39..3a2a241 100644
--- a/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp
+++ b/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp
@@ -29,8 +29,8 @@
#include "config.h"
#include "AccessibilityTableHeaderContainer.h"
-#include "AccessibilityTable.h"
#include "AXObjectCache.h"
+#include "AccessibilityTable.h"
using namespace std;
@@ -79,9 +79,8 @@ void AccessibilityTableHeaderContainer::addChildren()
static_cast<AccessibilityTable*>(m_parentTable)->columnHeaders(m_children);
unsigned length = m_children.size();
- for (unsigned k = 0; k < length; ++k) {
+ for (unsigned k = 0; k < length; ++k)
m_headerRect.unite(m_children[k]->elementRect());
- }
}
} // namespace WebCore
diff --git a/WebCore/accessibility/AccessibilityTableRow.cpp b/WebCore/accessibility/AccessibilityTableRow.cpp
index 53b479e..71f8b2b 100644
--- a/WebCore/accessibility/AccessibilityTableRow.cpp
+++ b/WebCore/accessibility/AccessibilityTableRow.cpp
@@ -29,8 +29,8 @@
#include "config.h"
#include "AccessibilityTableRow.h"
-#include "AccessibilityTableCell.h"
#include "AXObjectCache.h"
+#include "AccessibilityTableCell.h"
#include "HTMLNames.h"
#include "HTMLTableRowElement.h"
#include "RenderObject.h"
diff --git a/WebCore/accessibility/chromium/AccessibilityObjectWrapper.h b/WebCore/accessibility/chromium/AccessibilityObjectWrapper.h
index d7238e1..85a65ed 100644
--- a/WebCore/accessibility/chromium/AccessibilityObjectWrapper.h
+++ b/WebCore/accessibility/chromium/AccessibilityObjectWrapper.h
@@ -27,6 +27,8 @@
#ifndef AccessibilityObjectWrapper_h
#define AccessibilityObjectWrapper_h
+#include <wtf/RefCounted.h>
+
namespace WebCore {
class AccessibilityObject;
@@ -41,8 +43,6 @@ namespace WebCore {
AccessibilityObjectWrapper(AccessibilityObject* obj)
: m_object(obj)
{
- // FIXME: Remove this once our immediate subclass no longer uses COM.
- *addressOfCount() = 0;
}
AccessibilityObjectWrapper() : m_object(0) { }
diff --git a/WebCore/accessibility/gtk/AXObjectCacheAtk.cpp b/WebCore/accessibility/gtk/AXObjectCacheAtk.cpp
index cc515ad..c30b006 100644
--- a/WebCore/accessibility/gtk/AXObjectCacheAtk.cpp
+++ b/WebCore/accessibility/gtk/AXObjectCacheAtk.cpp
@@ -43,6 +43,10 @@ void AXObjectCache::postPlatformNotification(AccessibilityObject* coreObject, AX
if (!coreObject->isCheckboxOrRadio())
return;
g_signal_emit_by_name(coreObject->wrapper(), "state-change", "checked", coreObject->isChecked());
+ } else if (notification == AXSelectedChildrenChanged) {
+ if (!coreObject->isListBox())
+ return;
+ g_signal_emit_by_name(coreObject->wrapper(), "selection-changed");
}
}
diff --git a/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp b/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp
index c5f09ae..16ea948 100644
--- a/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp
+++ b/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp
@@ -35,6 +35,7 @@
#include "AXObjectCache.h"
#include "AccessibilityListBox.h"
+#include "AccessibilityListBoxOption.h"
#include "AccessibilityRenderObject.h"
#include "AccessibilityTable.h"
#include "AccessibilityTableCell.h"
@@ -43,6 +44,7 @@
#include "AtomicString.h"
#include "CString.h"
#include "Document.h"
+#include "DocumentType.h"
#include "Editor.h"
#include "Frame.h"
#include "FrameView.h"
@@ -106,6 +108,11 @@ static AccessibilityObject* core(AtkAction* action)
return core(ATK_OBJECT(action));
}
+static AccessibilityObject* core(AtkSelection* selection)
+{
+ return core(ATK_OBJECT(selection));
+}
+
static AccessibilityObject* core(AtkText* text)
{
return core(ATK_OBJECT(text));
@@ -131,39 +138,72 @@ static AccessibilityObject* core(AtkTable* table)
return core(ATK_OBJECT(table));
}
+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 const gchar* webkit_accessible_get_name(AtkObject* object)
{
AccessibilityObject* coreObject = core(object);
+ if (!coreObject->isAccessibilityRenderObject())
+ return returnString(coreObject->stringValue());
+
+ AccessibilityRenderObject* renderObject = static_cast<AccessibilityRenderObject*>(coreObject);
if (coreObject->isControl()) {
- AccessibilityRenderObject* renderObject = static_cast<AccessibilityRenderObject*>(coreObject);
AccessibilityObject* label = renderObject->correspondingLabelForControlElement();
- if (label) {
- AccessibilityRenderObject::AccessibilityChildrenVector children = label->children();
- // Currently, label->stringValue() should be an empty String. This
- // might not be the case down the road.
- String name = label->stringValue();
- for (unsigned i = 0; i < children.size(); ++i)
- name += children.at(i).get()->stringValue();
- return returnString(name);
+ if (label)
+ return returnString(nameFromChildren(label));
+ }
+
+ if (renderObject->isImage() || renderObject->isInputImage()) {
+ Node* node = renderObject->renderer()->node();
+ if (node && node->isHTMLElement()) {
+ // Get the attribute rather than altText String so as not to fall back on title.
+ String alt = static_cast<HTMLElement*>(node)->getAttribute(HTMLNames::altAttr);
+ if (!alt.isEmpty())
+ return returnString(alt);
}
}
+
return returnString(coreObject->stringValue());
}
static const gchar* webkit_accessible_get_description(AtkObject* object)
{
AccessibilityObject* coreObject = core(object);
+ Node* node = 0;
+ if (coreObject->isAccessibilityRenderObject())
+ node = static_cast<AccessibilityRenderObject*>(coreObject)->renderer()->node();
+ if (!node || !node->isHTMLElement() || coreObject->ariaRoleAttribute() != UnknownRole)
+ return returnString(coreObject->accessibilityDescription());
// atk_table_get_summary returns an AtkObject. We have no summary object, so expose summary here.
- if (coreObject->roleValue() == TableRole && coreObject->ariaRoleAttribute() == UnknownRole) {
- Node* node = static_cast<AccessibilityRenderObject*>(coreObject)->renderer()->node();
- if (node && node->isHTMLElement()) {
- String summary = static_cast<HTMLTableElement*>(node)->summary();
- if (!summary.isEmpty())
- return returnString(summary);
- }
+ if (coreObject->roleValue() == TableRole) {
+ String summary = static_cast<HTMLTableElement*>(node)->summary();
+ if (!summary.isEmpty())
+ return returnString(summary);
}
+ // The title attribute should be reliably available as the object's descripton.
+ // We do not want to fall back on other attributes in its absence. See bug 25524.
+ String title = static_cast<HTMLElement*>(node)->title();
+ if (!title.isEmpty())
+ return returnString(title);
+
return returnString(coreObject->accessibilityDescription());
}
@@ -181,9 +221,9 @@ static void setAtkRelationSetFromCoreObject(AccessibilityObject* coreObject, Atk
}
}
-static gpointer webkit_accessible_parent_class = NULL;
+static gpointer webkit_accessible_parent_class = 0;
-static AtkObject* webkit_accessible_get_parent(AtkObject* object)
+static AtkObject* atkParentOfWebView(AtkObject* object)
{
AccessibilityObject* coreParent = core(object)->parentObjectUnignored();
@@ -203,7 +243,19 @@ static AtkObject* webkit_accessible_get_parent(AtkObject* object)
}
if (!coreParent)
- return NULL;
+ return 0;
+
+ return coreParent->wrapper();
+}
+
+static AtkObject* webkit_accessible_get_parent(AtkObject* object)
+{
+ AccessibilityObject* coreParent = core(object)->parentObjectUnignored();
+ if (!coreParent && core(object)->isWebArea())
+ return atkParentOfWebView(object);
+
+ if (!coreParent)
+ return 0;
return coreParent->wrapper();
}
@@ -216,14 +268,14 @@ static gint webkit_accessible_get_n_children(AtkObject* object)
static AtkObject* webkit_accessible_ref_child(AtkObject* object, gint index)
{
AccessibilityObject* coreObject = core(object);
+ AccessibilityObject::AccessibilityChildrenVector children = coreObject->children();
+ if (index < 0 || static_cast<unsigned>(index) >= children.size())
+ return 0;
- g_return_val_if_fail(index >= 0, NULL);
- g_return_val_if_fail(static_cast<size_t>(index) < coreObject->children().size(), NULL);
-
- AccessibilityObject* coreChild = coreObject->children().at(index).get();
+ AccessibilityObject* coreChild = children.at(index).get();
if (!coreChild)
- return NULL;
+ return 0;
AtkObject* child = coreChild->wrapper();
atk_object_set_parent(child, object);
@@ -237,7 +289,20 @@ static gint webkit_accessible_get_index_in_parent(AtkObject* object)
AccessibilityObject* coreObject = core(object);
AccessibilityObject* parent = coreObject->parentObjectUnignored();
- g_return_val_if_fail(parent, 0);
+ if (!parent && core(object)->isWebArea()) {
+ AtkObject* atkParent = atkParentOfWebView(object);
+ if (!atkParent)
+ return -1;
+
+ unsigned count = atk_object_get_n_accessible_children(atkParent);
+ for (unsigned i = 0; i < count; ++i) {
+ AtkObject* child = atk_object_ref_accessible_child(atkParent, i);
+ bool childIsObject = child == object;
+ g_object_unref(child);
+ if (childIsObject)
+ return i;
+ }
+ }
AccessibilityObject::AccessibilityChildrenVector children = parent->children();
unsigned count = children.size();
@@ -246,7 +311,7 @@ static gint webkit_accessible_get_index_in_parent(AtkObject* object)
return i;
}
- return 0;
+ return -1;
}
static AtkAttributeSet* addAttributeToSet(AtkAttributeSet* attributeSet, const char* name, const char* value)
@@ -261,7 +326,7 @@ static AtkAttributeSet* addAttributeToSet(AtkAttributeSet* attributeSet, const c
static AtkAttributeSet* webkit_accessible_get_attributes(AtkObject* object)
{
- AtkAttributeSet* attributeSet = NULL;
+ AtkAttributeSet* attributeSet = 0;
int headingLevel = core(object)->headingLevel();
if (headingLevel) {
@@ -361,21 +426,21 @@ static AtkRole atkRole(AccessibilityRole role)
static AtkRole webkit_accessible_get_role(AtkObject* object)
{
- AccessibilityObject* AXObject = core(object);
+ AccessibilityObject* axObject = core(object);
- if (!AXObject)
+ 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 (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();
+ if (axObject->isAccessibilityRenderObject()) {
+ Node* node = static_cast<AccessibilityRenderObject*>(axObject)->renderer()->node();
if (node) {
if (node->hasTagName(HTMLNames::pTag))
return ATK_ROLE_PARAGRAPH;
@@ -387,10 +452,10 @@ static AtkRole webkit_accessible_get_role(AtkObject* object)
}
// Note: Why doesn't WebCore have a password field for this
- if (AXObject->isPasswordField())
+ if (axObject->isPasswordField())
return ATK_ROLE_PASSWORD_TEXT;
- return atkRole(AXObject->roleValue());
+ return atkRole(axObject->roleValue());
}
static void setAtkStateSetFromCoreObject(AccessibilityObject* coreObject, AtkStateSet* stateSet)
@@ -549,15 +614,15 @@ webkit_accessible_get_type(void)
if (g_once_init_enter(&type_volatile)) {
static const GTypeInfo tinfo = {
sizeof(WebKitAccessibleClass),
- (GBaseInitFunc)NULL,
- (GBaseFinalizeFunc)NULL,
- (GClassInitFunc)webkit_accessible_class_init,
- (GClassFinalizeFunc)NULL,
- NULL, /* class data */
+ (GBaseInitFunc) 0,
+ (GBaseFinalizeFunc) 0,
+ (GClassInitFunc) webkit_accessible_class_init,
+ (GClassFinalizeFunc) 0,
+ 0, /* class data */
sizeof(WebKitAccessible), /* instance size */
0, /* nb preallocs */
- (GInstanceInitFunc)NULL,
- NULL /* value table */
+ (GInstanceInitFunc) 0,
+ 0 /* value table */
};
GType type = g_type_register_static(ATK_TYPE_OBJECT,
@@ -581,7 +646,7 @@ static gint webkit_accessible_action_get_n_actions(AtkAction* action)
static const gchar* webkit_accessible_action_get_description(AtkAction* action, gint i)
{
- g_return_val_if_fail(i == 0, NULL);
+ g_return_val_if_fail(i == 0, 0);
// TODO: Need a way to provide/localize action descriptions.
notImplemented();
return "";
@@ -589,14 +654,14 @@ static const gchar* webkit_accessible_action_get_description(AtkAction* action,
static const gchar* webkit_accessible_action_get_keybinding(AtkAction* action, gint i)
{
- g_return_val_if_fail(i == 0, NULL);
+ g_return_val_if_fail(i == 0, 0);
// FIXME: Construct a proper keybinding string.
return returnString(core(action)->accessKey().string());
}
static const gchar* webkit_accessible_action_get_name(AtkAction* action, gint i)
{
- g_return_val_if_fail(i == 0, NULL);
+ g_return_val_if_fail(i == 0, 0);
return returnString(core(action)->actionVerb());
}
@@ -609,6 +674,145 @@ static void atk_action_interface_init(AtkActionIface* iface)
iface->get_name = webkit_accessible_action_get_name;
}
+// Selection (for controls)
+
+static AccessibilityObject* optionFromList(AtkSelection* selection, gint i)
+{
+ AccessibilityObject* coreSelection = core(selection);
+ if (!coreSelection || i < 0)
+ return 0;
+
+ AccessibilityRenderObject::AccessibilityChildrenVector options = core(selection)->children();
+ if (i < static_cast<gint>(options.size()))
+ return options.at(i).get();
+
+ return 0;
+}
+
+static AccessibilityObject* optionFromSelection(AtkSelection* selection, gint i)
+{
+ // i is the ith selection as opposed to the ith child.
+
+ AccessibilityObject* coreSelection = core(selection);
+ if (!coreSelection || i < 0)
+ return 0;
+
+ AccessibilityRenderObject::AccessibilityChildrenVector selectedItems;
+ if (coreSelection->isListBox())
+ static_cast<AccessibilityListBox*>(coreSelection)->selectedChildren(selectedItems);
+
+ // TODO: Combo boxes
+
+ if (i < static_cast<gint>(selectedItems.size()))
+ return selectedItems.at(i).get();
+
+ return 0;
+}
+
+static gboolean webkit_accessible_selection_add_selection(AtkSelection* selection, gint i)
+{
+ AccessibilityObject* option = optionFromList(selection, i);
+ if (option && core(selection)->isListBox()) {
+ AccessibilityListBoxOption* listBoxOption = static_cast<AccessibilityListBoxOption*>(option);
+ listBoxOption->setSelected(true);
+ return listBoxOption->isSelected();
+ }
+
+ return false;
+}
+
+static gboolean webkit_accessible_selection_clear_selection(AtkSelection* selection)
+{
+ AccessibilityObject* coreSelection = core(selection);
+ if (!coreSelection)
+ return false;
+
+ AccessibilityRenderObject::AccessibilityChildrenVector selectedItems;
+ if (coreSelection->isListBox()) {
+ // Set the list of selected items to an empty list; then verify that it worked.
+ AccessibilityListBox* listBox = static_cast<AccessibilityListBox*>(coreSelection);
+ listBox->setSelectedChildren(selectedItems);
+ listBox->selectedChildren(selectedItems);
+ return selectedItems.size() == 0;
+ }
+ return false;
+}
+
+static AtkObject* webkit_accessible_selection_ref_selection(AtkSelection* selection, gint i)
+{
+ AccessibilityObject* option = optionFromSelection(selection, i);
+ if (option) {
+ AtkObject* child = option->wrapper();
+ g_object_ref(child);
+ return child;
+ }
+
+ return 0;
+}
+
+static gint webkit_accessible_selection_get_selection_count(AtkSelection* selection)
+{
+ AccessibilityObject* coreSelection = core(selection);
+ if (coreSelection && coreSelection->isListBox()) {
+ AccessibilityRenderObject::AccessibilityChildrenVector selectedItems;
+ static_cast<AccessibilityListBox*>(coreSelection)->selectedChildren(selectedItems);
+ return static_cast<gint>(selectedItems.size());
+ }
+
+ return 0;
+}
+
+static gboolean webkit_accessible_selection_is_child_selected(AtkSelection* selection, gint i)
+{
+ AccessibilityObject* option = optionFromList(selection, i);
+ if (option && core(selection)->isListBox())
+ return static_cast<AccessibilityListBoxOption*>(option)->isSelected();
+
+ return false;
+}
+
+static gboolean webkit_accessible_selection_remove_selection(AtkSelection* selection, gint i)
+{
+ // TODO: This is only getting called if i == 0. What is preventing the rest?
+ AccessibilityObject* option = optionFromSelection(selection, i);
+ if (option && core(selection)->isListBox()) {
+ AccessibilityListBoxOption* listBoxOption = static_cast<AccessibilityListBoxOption*>(option);
+ listBoxOption->setSelected(false);
+ return !listBoxOption->isSelected();
+ }
+
+ return false;
+}
+
+static gboolean webkit_accessible_selection_select_all_selection(AtkSelection* selection)
+{
+ AccessibilityObject* coreSelection = core(selection);
+ if (!coreSelection || !coreSelection->isMultiSelect())
+ return false;
+
+ AccessibilityRenderObject::AccessibilityChildrenVector children = coreSelection->children();
+ if (coreSelection->isListBox()) {
+ AccessibilityListBox* listBox = static_cast<AccessibilityListBox*>(coreSelection);
+ listBox->setSelectedChildren(children);
+ AccessibilityRenderObject::AccessibilityChildrenVector selectedItems;
+ listBox->selectedChildren(selectedItems);
+ return selectedItems.size() == children.size();
+ }
+
+ return false;
+}
+
+static void atk_selection_interface_init(AtkSelectionIface* iface)
+{
+ iface->add_selection = webkit_accessible_selection_add_selection;
+ iface->clear_selection = webkit_accessible_selection_clear_selection;
+ iface->ref_selection = webkit_accessible_selection_ref_selection;
+ iface->get_selection_count = webkit_accessible_selection_get_selection_count;
+ iface->is_child_selected = webkit_accessible_selection_is_child_selected;
+ iface->remove_selection = webkit_accessible_selection_remove_selection;
+ iface->select_all_selection = webkit_accessible_selection_select_all_selection;
+}
+
// Text
static gchar* webkit_accessible_text_get_text(AtkText* text, gint startOffset, gint endOffset)
@@ -616,6 +820,8 @@ static gchar* webkit_accessible_text_get_text(AtkText* text, gint startOffset, g
AccessibilityObject* coreObject = core(text);
String ret;
unsigned start = startOffset;
+ if (endOffset == -1)
+ endOffset = coreObject->stringValue().length();
int length = endOffset - startOffset;
if (coreObject->isTextControl())
@@ -656,23 +862,24 @@ static gchar* convertUniCharToUTF8(const UChar* characters, gint length, int fro
{
CString stringUTF8 = UTF8Encoding().encode(characters, length, QuestionMarksForUnencodables);
gchar* utf8String = utf8Substr(stringUTF8.data(), from, to);
- if (!g_utf8_validate(utf8String, -1, NULL)) {
+ if (!g_utf8_validate(utf8String, -1, 0)) {
g_free(utf8String);
return 0;
}
gsize len = strlen(utf8String);
- GString* ret = g_string_new_len(NULL, len);
+ GString* ret = g_string_new_len(0, len);
+ gchar* ptr = utf8String;
// WebCore introduces line breaks in the text that do not reflect
// the layout you see on the screen, replace them with spaces
while (len > 0) {
gint index, start;
- pango_find_paragraph_boundary(utf8String, len, &index, &start);
- g_string_append_len(ret, utf8String, index);
+ pango_find_paragraph_boundary(ptr, len, &index, &start);
+ g_string_append_len(ret, ptr, index);
if (index == start)
break;
g_string_append_c(ret, ' ');
- utf8String += start;
+ ptr += start;
len -= start;
}
@@ -691,7 +898,7 @@ static PangoLayout* getPangoLayoutForAtk(AtkText* textObject)
if (!webView)
return 0;
- GString* str = g_string_new(NULL);
+ GString* str = g_string_new(0);
AccessibilityRenderObject* accObject = static_cast<AccessibilityRenderObject*>(coreObject);
if (!accObject)
@@ -701,12 +908,30 @@ static PangoLayout* getPangoLayoutForAtk(AtkText* textObject)
return 0;
// Create a string with the layout as it appears on the screen
- InlineTextBox* box = renderText->firstTextBox();
- while (box) {
- gchar *text = convertUniCharToUTF8(renderText->characters(), renderText->textLength(), box->start(), box->end());
- g_string_append(str, text);
- g_string_append(str, "\n");
- box = box->nextTextBox();
+ if (accObject->isTextControl()) {
+ unsigned textLength = accObject->textLength();
+ int lineNumber = 0;
+ PlainTextRange range = accObject->doAXRangeForLine(lineNumber);
+ while (range.length) {
+ // When a line of text wraps in a text area, the final space is removed.
+ if (range.start + range.length < textLength)
+ range.length -= 1;
+ String lineText = accObject->doAXStringForRange(range);
+ g_string_append(str, lineText.utf8().data());
+ g_string_append(str, "\n");
+ range = accObject->doAXRangeForLine(++lineNumber);
+ }
+ } else {
+ InlineTextBox* box = renderText->firstTextBox();
+ while (box) {
+ gchar* text = convertUniCharToUTF8(renderText->characters(), renderText->textLength(), box->start(), box->end());
+ g_string_append(str, text);
+ // Newline chars in the source result in separate text boxes, so check
+ // before adding a newline in the layout. See bug 25415 comment #78.
+ if (!box->nextOnLineExists())
+ g_string_append(str, "\n");
+ box = box->nextTextBox();
+ }
}
PangoLayout* layout = gtk_widget_create_pango_layout(static_cast<GtkWidget*>(webView), g_string_free(str, FALSE));
@@ -732,7 +957,7 @@ static gchar* webkit_accessible_text_get_text_before_offset(AtkText* text, gint
static gunichar webkit_accessible_text_get_character_at_offset(AtkText* text, gint offset)
{
notImplemented();
- return NULL;
+ return 0;
}
static gint webkit_accessible_text_get_caret_offset(AtkText* text)
@@ -744,13 +969,13 @@ static gint webkit_accessible_text_get_caret_offset(AtkText* text)
static AtkAttributeSet* webkit_accessible_text_get_run_attributes(AtkText* text, gint offset, gint* start_offset, gint* end_offset)
{
notImplemented();
- return NULL;
+ return 0;
}
static AtkAttributeSet* webkit_accessible_text_get_default_attributes(AtkText* text)
{
notImplemented();
- return NULL;
+ return 0;
}
static void webkit_accessible_text_get_character_extents(AtkText* text, gint offset, gint* x, gint* y, gint* width, gint* height, AtkCoordType coords)
@@ -795,7 +1020,7 @@ static gint webkit_accessible_text_get_offset_at_point(AtkText* text, gint x, gi
return range.start;
}
-static bool selectionBelongsToObject(AccessibilityObject *coreObject, VisibleSelection& selection)
+static bool selectionBelongsToObject(AccessibilityObject* coreObject, VisibleSelection& selection)
{
if (!coreObject->isAccessibilityRenderObject())
return false;
@@ -830,7 +1055,7 @@ static gchar* webkit_accessible_text_get_selection(AtkText* text, gint selection
// the global one (the API is a bit confusing)
if (selection_num != 0 || !selectionBelongsToObject(coreObject, selection)) {
*start_offset = *end_offset = 0;
- return NULL;
+ return 0;
}
*start_offset = selection.start().offsetInContainerNode();
@@ -1016,7 +1241,7 @@ static AtkObject* webkit_accessible_component_ref_accessible_at_point(AtkCompone
IntPoint pos = atkToContents(core(component), coordType, x, y);
AccessibilityObject* target = core(component)->doAccessibilityHitTest(pos);
if (!target)
- return NULL;
+ return 0;
g_object_ref(target->wrapper());
return target->wrapper();
}
@@ -1033,7 +1258,7 @@ static gboolean webkit_accessible_component_grab_focus(AtkComponent* component)
return core(component)->isFocused();
}
-static void atk_component_interface_init(AtkComponentIface *iface)
+static void atk_component_interface_init(AtkComponentIface* iface)
{
iface->ref_accessible_at_point = webkit_accessible_component_ref_accessible_at_point;
iface->get_extents = webkit_accessible_component_get_extents;
@@ -1080,32 +1305,68 @@ static AccessibilityTableCell* cell(AtkTable* table, guint row, guint column)
return 0;
}
-static gint cellIndex(AccessibilityTableCell* AXCell, AccessibilityTable* AXTable)
+static gint cellIndex(AccessibilityTableCell* axCell, AccessibilityTable* axTable)
{
// Calculate the cell's index as if we had a traditional Gtk+ table in
// which cells are all direct children of the table, arranged row-first.
AccessibilityObject::AccessibilityChildrenVector allCells;
- AXTable->cells(allCells);
+ axTable->cells(allCells);
AccessibilityObject::AccessibilityChildrenVector::iterator position;
- position = std::find(allCells.begin(), allCells.end(), AXCell);
+ position = std::find(allCells.begin(), allCells.end(), axCell);
if (position == allCells.end())
return -1;
return position - allCells.begin();
}
+static AccessibilityTableCell* cellAtIndex(AtkTable* table, gint index)
+{
+ AccessibilityObject* accTable = core(table);
+ if (accTable->isAccessibilityRenderObject()) {
+ AccessibilityObject::AccessibilityChildrenVector allCells;
+ static_cast<AccessibilityTable*>(accTable)->cells(allCells);
+ if (0 <= index && static_cast<unsigned>(index) < allCells.size()) {
+ AccessibilityObject* accCell = allCells.at(index).get();
+ return static_cast<AccessibilityTableCell*>(accCell);
+ }
+ }
+ return 0;
+}
+
static AtkObject* webkit_accessible_table_ref_at(AtkTable* table, gint row, gint column)
{
- AccessibilityTableCell* AXCell = cell(table, row, column);
- if (!AXCell)
+ AccessibilityTableCell* axCell = cell(table, row, column);
+ if (!axCell)
return 0;
- return AXCell->wrapper();
+ return axCell->wrapper();
}
static gint webkit_accessible_table_get_index_at(AtkTable* table, gint row, gint column)
{
- AccessibilityTableCell* AXCell = cell(table, row, column);
- AccessibilityTable* AXTable = static_cast<AccessibilityTable*>(core(table));
- return cellIndex(AXCell, AXTable);
+ AccessibilityTableCell* axCell = cell(table, row, column);
+ AccessibilityTable* axTable = static_cast<AccessibilityTable*>(core(table));
+ return cellIndex(axCell, axTable);
+}
+
+static gint webkit_accessible_table_get_column_at_index(AtkTable* table, gint index)
+{
+ AccessibilityTableCell* axCell = cellAtIndex(table, index);
+ if (axCell){
+ pair<int, int> columnRange;
+ axCell->columnIndexRange(columnRange);
+ return columnRange.first;
+ }
+ return -1;
+}
+
+static gint webkit_accessible_table_get_row_at_index(AtkTable* table, gint index)
+{
+ AccessibilityTableCell* axCell = cellAtIndex(table, index);
+ if (axCell){
+ pair<int, int> rowRange;
+ axCell->rowIndexRange(rowRange);
+ return rowRange.first;
+ }
+ return -1;
}
static gint webkit_accessible_table_get_n_columns(AtkTable* table)
@@ -1126,10 +1387,10 @@ static gint webkit_accessible_table_get_n_rows(AtkTable* table)
static gint webkit_accessible_table_get_column_extent_at(AtkTable* table, gint row, gint column)
{
- AccessibilityTableCell* AXCell = cell(table, row, column);
- if (AXCell) {
+ AccessibilityTableCell* axCell = cell(table, row, column);
+ if (axCell) {
pair<int, int> columnRange;
- AXCell->columnIndexRange(columnRange);
+ axCell->columnIndexRange(columnRange);
return columnRange.second;
}
return 0;
@@ -1137,15 +1398,22 @@ static gint webkit_accessible_table_get_column_extent_at(AtkTable* table, gint r
static gint webkit_accessible_table_get_row_extent_at(AtkTable* table, gint row, gint column)
{
- AccessibilityTableCell* AXCell = cell(table, row, column);
- if (AXCell) {
+ AccessibilityTableCell* axCell = cell(table, row, column);
+ if (axCell) {
pair<int, int> rowRange;
- AXCell->rowIndexRange(rowRange);
+ axCell->rowIndexRange(rowRange);
return rowRange.second;
}
return 0;
}
+static AtkObject* webkit_accessible_table_get_column_header(AtkTable* table, gint column)
+{
+ // FIXME: This needs to be implemented.
+ notImplemented();
+ return 0;
+}
+
static AtkObject* webkit_accessible_table_get_row_header(AtkTable* table, gint row)
{
AccessibilityObject* accTable = core(table);
@@ -1163,39 +1431,139 @@ static AtkObject* webkit_accessible_table_get_row_header(AtkTable* table, gint r
return 0;
}
+static AtkObject* webkit_accessible_table_get_caption(AtkTable* table)
+{
+ AccessibilityObject* accTable = core(table);
+ if (accTable->isAccessibilityRenderObject()) {
+ Node* node = static_cast<AccessibilityRenderObject*>(accTable)->renderer()->node();
+ if (node && node->hasTagName(HTMLNames::tableTag)) {
+ HTMLTableCaptionElement* caption = static_cast<HTMLTableElement*>(node)->caption();
+ if (caption)
+ return AccessibilityObject::firstAccessibleObjectFromNode(caption->renderer()->node())->wrapper();
+ }
+ }
+ return 0;
+}
+
+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)));
+
+ return 0;
+}
+
+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)));
+
+ return 0;
+}
+
static void atk_table_interface_init(AtkTableIface* iface)
{
iface->ref_at = webkit_accessible_table_ref_at;
iface->get_index_at = webkit_accessible_table_get_index_at;
+ iface->get_column_at_index = webkit_accessible_table_get_column_at_index;
+ iface->get_row_at_index = webkit_accessible_table_get_row_at_index;
iface->get_n_columns = webkit_accessible_table_get_n_columns;
iface->get_n_rows = webkit_accessible_table_get_n_rows;
iface->get_column_extent_at = webkit_accessible_table_get_column_extent_at;
iface->get_row_extent_at = webkit_accessible_table_get_row_extent_at;
+ iface->get_column_header = webkit_accessible_table_get_column_header;
iface->get_row_header = webkit_accessible_table_get_row_header;
+ iface->get_caption = webkit_accessible_table_get_caption;
+ iface->get_column_description = webkit_accessible_table_get_column_description;
+ iface->get_row_description = webkit_accessible_table_get_row_description;
+}
+
+static const gchar* documentAttributeValue(AtkDocument* document, const gchar* attribute)
+{
+ Document* coreDocument = core(document)->document();
+ if (!coreDocument)
+ return 0;
+
+ String value = String();
+ if (!g_ascii_strcasecmp(attribute, "DocType") && coreDocument->doctype())
+ value = coreDocument->doctype()->name();
+ else if (!g_ascii_strcasecmp(attribute, "Encoding"))
+ value = coreDocument->charset();
+ else if (!g_ascii_strcasecmp(attribute, "URI"))
+ value = coreDocument->documentURI();
+ if (!value.isEmpty())
+ return returnString(value);
+
+ return 0;
+}
+
+static const gchar* webkit_accessible_document_get_attribute_value(AtkDocument* document, const gchar* attribute)
+{
+ return documentAttributeValue(document, attribute);
+}
+
+static AtkAttributeSet* webkit_accessible_document_get_attributes(AtkDocument* document)
+{
+ AtkAttributeSet* attributeSet = 0;
+ const gchar* attributes [] = {"DocType", "Encoding", "URI"};
+
+ for (unsigned i = 0; i < G_N_ELEMENTS(attributes); i++) {
+ const gchar* value = documentAttributeValue(document, attributes[i]);
+ if (value)
+ attributeSet = addAttributeToSet(attributeSet, attributes[i], value);
+ }
+
+ return attributeSet;
+}
+
+static const gchar* webkit_accessible_document_get_locale(AtkDocument* document)
+{
+
+ // TODO: Should we fall back on lang xml:lang when the following comes up empty?
+ String language = static_cast<AccessibilityRenderObject*>(core(document))->language();
+ if (!language.isEmpty())
+ return returnString(language);
+
+ return 0;
+}
+
+static void atk_document_interface_init(AtkDocumentIface* iface)
+{
+ iface->get_document_attribute_value = webkit_accessible_document_get_attribute_value;
+ iface->get_document_attributes = webkit_accessible_document_get_attributes;
+ iface->get_document_locale = webkit_accessible_document_get_locale;
}
static const GInterfaceInfo AtkInterfacesInitFunctions[] = {
{(GInterfaceInitFunc)atk_action_interface_init,
- (GInterfaceFinalizeFunc) NULL, NULL},
+ (GInterfaceFinalizeFunc) 0, 0},
+ {(GInterfaceInitFunc)atk_selection_interface_init,
+ (GInterfaceFinalizeFunc) 0, 0},
{(GInterfaceInitFunc)atk_editable_text_interface_init,
- (GInterfaceFinalizeFunc) NULL, NULL},
+ (GInterfaceFinalizeFunc) 0, 0},
{(GInterfaceInitFunc)atk_text_interface_init,
- (GInterfaceFinalizeFunc) NULL, NULL},
+ (GInterfaceFinalizeFunc) 0, 0},
{(GInterfaceInitFunc)atk_component_interface_init,
- (GInterfaceFinalizeFunc) NULL, NULL},
+ (GInterfaceFinalizeFunc) 0, 0},
{(GInterfaceInitFunc)atk_image_interface_init,
- (GInterfaceFinalizeFunc) NULL, NULL},
+ (GInterfaceFinalizeFunc) 0, 0},
{(GInterfaceInitFunc)atk_table_interface_init,
- (GInterfaceFinalizeFunc) NULL, NULL}
+ (GInterfaceFinalizeFunc) 0, 0},
+ {(GInterfaceInitFunc)atk_document_interface_init,
+ (GInterfaceFinalizeFunc) 0, 0}
};
enum WAIType {
WAI_ACTION,
+ WAI_SELECTION,
WAI_EDITABLE_TEXT,
WAI_TEXT,
WAI_COMPONENT,
WAI_IMAGE,
- WAI_TABLE
+ WAI_TABLE,
+ WAI_DOCUMENT
};
static GType GetAtkInterfaceTypeFromWAIType(WAIType type)
@@ -1203,6 +1571,8 @@ static GType GetAtkInterfaceTypeFromWAIType(WAIType type)
switch (type) {
case WAI_ACTION:
return ATK_TYPE_ACTION;
+ case WAI_SELECTION:
+ return ATK_TYPE_SELECTION;
case WAI_EDITABLE_TEXT:
return ATK_TYPE_EDITABLE_TEXT;
case WAI_TEXT:
@@ -1213,6 +1583,8 @@ static GType GetAtkInterfaceTypeFromWAIType(WAIType type)
return ATK_TYPE_IMAGE;
case WAI_TABLE:
return ATK_TYPE_TABLE;
+ case WAI_DOCUMENT:
+ return ATK_TYPE_DOCUMENT;
}
return G_TYPE_INVALID;
@@ -1229,6 +1601,10 @@ static guint16 getInterfaceMaskFromObject(AccessibilityObject* coreObject)
if (!coreObject->actionVerb().isEmpty())
interfaceMask |= 1 << WAI_ACTION;
+ // Selection
+ if (coreObject->isListBox())
+ interfaceMask |= 1 << WAI_SELECTION;
+
// Text & Editable Text
AccessibilityRole role = coreObject->roleValue();
@@ -1248,6 +1624,10 @@ static guint16 getInterfaceMaskFromObject(AccessibilityObject* coreObject)
if (role == TableRole)
interfaceMask |= 1 << WAI_TABLE;
+ // Document
+ if (role == WebAreaRole)
+ interfaceMask |= 1 << WAI_DOCUMENT;
+
return interfaceMask;
}
@@ -1255,10 +1635,10 @@ static const char* getUniqueAccessibilityTypeName(guint16 interfaceMask)
{
#define WAI_TYPE_NAME_LEN (30) /* Enough for prefix + 5 hex characters (max) */
static char name[WAI_TYPE_NAME_LEN + 1];
-
+
g_sprintf(name, "WAIType%x", interfaceMask);
name[WAI_TYPE_NAME_LEN] = '\0';
-
+
return name;
}
@@ -1266,15 +1646,15 @@ static GType getAccessibilityTypeFromObject(AccessibilityObject* coreObject)
{
static const GTypeInfo typeInfo = {
sizeof(WebKitAccessibleClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) NULL,
- (GClassFinalizeFunc) NULL,
- NULL, /* class data */
+ (GBaseInitFunc) 0,
+ (GBaseFinalizeFunc) 0,
+ (GClassInitFunc) 0,
+ (GClassFinalizeFunc) 0,
+ 0, /* class data */
sizeof(WebKitAccessible), /* instance size */
0, /* nb preallocs */
- (GInstanceInitFunc) NULL,
- NULL /* value table */
+ (GInstanceInitFunc) 0,
+ 0 /* value table */
};
guint16 interfaceMask = getInterfaceMaskFromObject(coreObject);
@@ -1299,7 +1679,7 @@ static GType getAccessibilityTypeFromObject(AccessibilityObject* coreObject)
WebKitAccessible* webkit_accessible_new(AccessibilityObject* coreObject)
{
GType type = getAccessibilityTypeFromObject(coreObject);
- AtkObject* object = static_cast<AtkObject*>(g_object_new(type, NULL));
+ AtkObject* object = static_cast<AtkObject*>(g_object_new(type, 0));
atk_object_initialize(object, coreObject);
diff --git a/WebCore/accessibility/mac/AXObjectCacheMac.mm b/WebCore/accessibility/mac/AXObjectCacheMac.mm
index 2f18cf3..bf1b22c 100644
--- a/WebCore/accessibility/mac/AXObjectCacheMac.mm
+++ b/WebCore/accessibility/mac/AXObjectCacheMac.mm
@@ -59,6 +59,13 @@ void AXObjectCache::postPlatformNotification(AccessibilityObject* obj, AXNotific
// 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;
diff --git a/WebCore/accessibility/mac/AccessibilityObjectMac.mm b/WebCore/accessibility/mac/AccessibilityObjectMac.mm
index 217af54..722b03e 100644
--- a/WebCore/accessibility/mac/AccessibilityObjectMac.mm
+++ b/WebCore/accessibility/mac/AccessibilityObjectMac.mm
@@ -43,6 +43,24 @@ bool AccessibilityObject::accessibilityIgnoreAttachment() const
AccessibilityObjectPlatformInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const
{
+ // Determine if this is in a tree. If so, we apply special behavior to make it work like an AXOutline.
+ AccessibilityObject* axObj = parentObject();
+ bool isInTree = false;
+ while (axObj) {
+ if (axObj->isTree()) {
+ isInTree = true;
+ break;
+ }
+ axObj = axObj->parentObjectUnignored();
+ }
+
+ // If the object is in a tree, only tree items should be exposed (and the children of tree items).
+ if (isInTree) {
+ AccessibilityRole role = roleValue();
+ if (role != TreeItemRole && role != StaticTextRole)
+ return IgnoreObject;
+ }
+
return DefaultBehavior;
}
diff --git a/WebCore/accessibility/mac/AccessibilityObjectWrapper.h b/WebCore/accessibility/mac/AccessibilityObjectWrapper.h
index 3b584a9..910305b 100644
--- a/WebCore/accessibility/mac/AccessibilityObjectWrapper.h
+++ b/WebCore/accessibility/mac/AccessibilityObjectWrapper.h
@@ -29,7 +29,7 @@
#ifndef AccessibilityObjectWrapper_h
#define AccessibilityObjectWrapper_h
-#import <wtf/RefPtr.h>
+#include <wtf/RefPtr.h>
#ifdef __OBJC__
@class WebCoreTextMarker;
@@ -40,12 +40,11 @@ class WebCoreTextMarkerRange;
#endif
namespace WebCore {
- class AccessibilityObject;
- class VisiblePosition;
+class AccessibilityObject;
+class VisiblePosition;
}
-@interface AccessibilityObjectWrapper : NSObject
-{
+@interface AccessibilityObjectWrapper : NSObject {
WebCore::AccessibilityObject* m_object;
}
diff --git a/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm b/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm
index 58e5018..6099b3d 100644
--- a/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm
+++ b/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm
@@ -119,6 +119,18 @@ using namespace std;
#define NSAccessibilityRequiredAttribute @"AXRequired"
#endif
+#ifndef NSAccessibilityOwnsAttribute
+#define NSAccessibilityOwnsAttribute @"AXOwns"
+#endif
+
+#ifndef NSAccessibilityGrabbedAttribute
+#define NSAccessibilityGrabbedAttribute @"AXGrabbed"
+#endif
+
+#ifndef NSAccessibilityDropEffectsAttribute
+#define NSAccessibilityDropEffectsAttribute @"AXDropEffects"
+#endif
+
#ifdef BUILDING_ON_TIGER
typedef unsigned NSUInteger;
#define NSAccessibilityValueDescriptionAttribute @"AXValueDescription"
@@ -569,6 +581,27 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi
return actions;
}
+- (NSArray*)additionalAccessibilityAttributeNames
+{
+ if (!m_object)
+ return nil;
+
+ NSMutableArray *additional = [NSMutableArray array];
+ if (m_object->supportsARIAOwns())
+ [additional addObject:NSAccessibilityOwnsAttribute];
+
+ if (m_object->isScrollbar())
+ [additional addObject:NSAccessibilityOrientationAttribute];
+
+ if (m_object->supportsARIADragging())
+ [additional addObject:NSAccessibilityGrabbedAttribute];
+
+ if (m_object->supportsARIADropping())
+ [additional addObject:NSAccessibilityDropEffectsAttribute];
+
+ return additional;
+}
+
- (NSArray*)accessibilityAttributeNames
{
if (!m_object)
@@ -600,6 +633,11 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi
static NSArray* groupAttrs = nil;
static NSArray* inputImageAttrs = nil;
static NSArray* passwordFieldAttrs = nil;
+ static NSArray* tabListAttrs = nil;
+ static NSArray* comboBoxAttrs = nil;
+ static NSArray* outlineAttrs = nil;
+ static NSArray* outlineRowAttrs = nil;
+ static NSArray* buttonAttrs = nil;
NSMutableArray* tempArray;
if (attributes == nil) {
attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
@@ -739,6 +777,21 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi
controlAttrs = [[NSArray alloc] initWithArray:tempArray];
[tempArray release];
}
+ if (buttonAttrs == nil) {
+ tempArray = [[NSMutableArray alloc] initWithArray:attributes];
+ // Buttons should not expose AXValue.
+ [tempArray removeObject:NSAccessibilityValueAttribute];
+ [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
+ [tempArray addObject:NSAccessibilityAccessKeyAttribute];
+ buttonAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
+ if (comboBoxAttrs == nil) {
+ tempArray = [[NSMutableArray alloc] initWithArray:controlAttrs];
+ [tempArray addObject:NSAccessibilityExpandedAttribute];
+ comboBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
if (tableAttrs == nil) {
tempArray = [[NSMutableArray alloc] initWithArray:attributes];
[tempArray addObject:NSAccessibilityRowsAttribute];
@@ -781,9 +834,8 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi
[tempArray release];
}
if (inputImageAttrs == nil) {
- tempArray = [[NSMutableArray alloc] initWithArray:controlAttrs];
+ tempArray = [[NSMutableArray alloc] initWithArray:buttonAttrs];
[tempArray addObject:NSAccessibilityURLAttribute];
- [tempArray addObject:NSAccessibilityAccessKeyAttribute];
inputImageAttrs = [[NSArray alloc] initWithArray:tempArray];
[tempArray release];
}
@@ -794,53 +846,96 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi
passwordFieldAttrs = [[NSArray alloc] initWithArray:tempArray];
[tempArray release];
}
+ if (tabListAttrs == nil) {
+ tempArray = [[NSMutableArray alloc] initWithArray:attributes];
+ [tempArray addObject:NSAccessibilityTabsAttribute];
+ [tempArray addObject:NSAccessibilityContentsAttribute];
+ tabListAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
+ if (outlineAttrs == nil) {
+ tempArray = [[NSMutableArray alloc] initWithArray:attributes];
+ [tempArray addObject:NSAccessibilitySelectedRowsAttribute];
+ [tempArray addObject:NSAccessibilityRowsAttribute];
+ [tempArray addObject:NSAccessibilityColumnsAttribute];
+ outlineAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
+ if (outlineRowAttrs == nil) {
+ tempArray = [[NSMutableArray alloc] initWithArray:tableRowAttrs];
+ [tempArray addObject:NSAccessibilityIndexAttribute];
+ [tempArray addObject:NSAccessibilityDisclosingAttribute];
+ [tempArray addObject:NSAccessibilityDisclosedByRowAttribute];
+ [tempArray addObject:NSAccessibilityDisclosureLevelAttribute];
+ [tempArray addObject:NSAccessibilityDisclosedRowsAttribute];
+ outlineRowAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
- if (m_object->isPasswordField())
- return passwordFieldAttrs;
-
- if (m_object->isWebArea())
- return webAreaAttrs;
+ NSArray *objectAttributes = attributes;
- if (m_object->isTextControl())
- return textAttrs;
-
- if (m_object->isAnchor() || m_object->isImage() || m_object->isLink())
- return anchorAttrs;
-
- if (m_object->isDataTable())
- return tableAttrs;
- if (m_object->isTableRow())
- return tableRowAttrs;
- if (m_object->isTableColumn())
- return tableColAttrs;
- if (m_object->isTableCell())
- return tableCellAttrs;
-
- if (m_object->isListBox() || m_object->isList())
- return listBoxAttrs;
-
- if (m_object->isProgressIndicator() || m_object->isSlider())
- return rangeAttrs;
-
- if (m_object->isInputImage())
- return inputImageAttrs;
-
- if (m_object->isControl())
- return controlAttrs;
-
- if (m_object->isGroup())
- return groupAttrs;
-
- if (m_object->isMenu())
- return menuAttrs;
- if (m_object->isMenuBar())
- return menuBarAttrs;
- if (m_object->isMenuButton())
- return menuButtonAttrs;
- if (m_object->isMenuItem())
- return menuItemAttrs;
-
- return attributes;
+ if (m_object->isPasswordField())
+ objectAttributes = passwordFieldAttrs;
+
+ else if (m_object->isWebArea())
+ objectAttributes = webAreaAttrs;
+
+ else if (m_object->isTextControl())
+ objectAttributes = textAttrs;
+
+ else if (m_object->isAnchor() || m_object->isImage() || m_object->isLink())
+ objectAttributes = anchorAttrs;
+
+ else if (m_object->isDataTable())
+ objectAttributes = tableAttrs;
+ else if (m_object->isTableRow())
+ objectAttributes = tableRowAttrs;
+ else if (m_object->isTableColumn())
+ objectAttributes = tableColAttrs;
+ else if (m_object->isTableCell())
+ objectAttributes = tableCellAttrs;
+
+ else if (m_object->isTree())
+ objectAttributes = outlineAttrs;
+ else if (m_object->isTreeItem())
+ objectAttributes = outlineRowAttrs;
+
+ else if (m_object->isListBox() || m_object->isList())
+ objectAttributes = listBoxAttrs;
+
+ else if (m_object->isComboBox())
+ objectAttributes = comboBoxAttrs;
+
+ else if (m_object->isProgressIndicator() || m_object->isSlider())
+ objectAttributes = rangeAttrs;
+
+ // These are processed in order because an input image is a button, and a button is a control.
+ else if (m_object->isInputImage())
+ objectAttributes = inputImageAttrs;
+ else if (m_object->isButton())
+ objectAttributes = buttonAttrs;
+ else if (m_object->isControl())
+ objectAttributes = controlAttrs;
+
+ else if (m_object->isGroup())
+ objectAttributes = groupAttrs;
+ else if (m_object->isTabList())
+ objectAttributes = tabListAttrs;
+
+ else if (m_object->isMenu())
+ objectAttributes = menuAttrs;
+ else if (m_object->isMenuBar())
+ objectAttributes = menuBarAttrs;
+ else if (m_object->isMenuButton())
+ objectAttributes = menuButtonAttrs;
+ else if (m_object->isMenuItem())
+ objectAttributes = menuItemAttrs;
+
+ NSArray *additionalAttributes = [self additionalAccessibilityAttributeNames];
+ if ([additionalAttributes count])
+ objectAttributes = [objectAttributes arrayByAddingObjectsFromArray:additionalAttributes];
+
+ return objectAttributes;
}
- (VisiblePositionRange)visiblePositionRangeForTextMarkerRange:(WebCoreTextMarkerRange*) textMarkerRange
@@ -936,6 +1031,7 @@ static const AccessibilityRoleMap& createAccessibilityRoleMap()
{ GroupRole, NSAccessibilityGroupRole },
{ RadioGroupRole, NSAccessibilityRadioGroupRole },
{ ListRole, NSAccessibilityListRole },
+ { DirectoryRole, NSAccessibilityListRole },
{ ScrollBarRole, NSAccessibilityScrollBarRole },
{ ValueIndicatorRole, NSAccessibilityValueIndicatorRole },
{ ImageRole, NSAccessibilityImageRole },
@@ -992,17 +1088,24 @@ static const AccessibilityRoleMap& createAccessibilityRoleMap()
{ LandmarkMainRole, NSAccessibilityGroupRole },
{ LandmarkNavigationRole, NSAccessibilityGroupRole },
{ LandmarkSearchRole, NSAccessibilityGroupRole },
+ { ApplicationAlertRole, NSAccessibilityGroupRole },
+ { ApplicationAlertDialogRole, NSAccessibilityGroupRole },
+ { ApplicationDialogRole, NSAccessibilityGroupRole },
{ ApplicationLogRole, NSAccessibilityGroupRole },
{ ApplicationMarqueeRole, NSAccessibilityGroupRole },
{ ApplicationStatusRole, NSAccessibilityGroupRole },
{ ApplicationTimerRole, NSAccessibilityGroupRole },
{ DocumentRole, NSAccessibilityGroupRole },
{ DocumentArticleRole, NSAccessibilityGroupRole },
+ { DocumentMathRole, NSAccessibilityGroupRole },
{ DocumentNoteRole, NSAccessibilityGroupRole },
{ DocumentRegionRole, NSAccessibilityGroupRole },
{ UserInterfaceTooltipRole, NSAccessibilityGroupRole },
-
-
+ { TabRole, NSAccessibilityRadioButtonRole },
+ { TabListRole, NSAccessibilityTabGroupRole },
+ { TabPanelRole, NSAccessibilityGroupRole },
+ { TreeRole, NSAccessibilityOutlineRole },
+ { TreeItemRole, NSAccessibilityRowRole },
};
AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap;
@@ -1041,6 +1144,9 @@ static NSString* roleValueToNSString(AccessibilityRole value)
}
}
+ if (m_object->isTreeItem())
+ return NSAccessibilityOutlineRowSubrole;
+
if (m_object->isList()) {
AccessibilityList* listObject = static_cast<AccessibilityList*>(m_object);
if (listObject->isUnorderedList() || listObject->isOrderedList())
@@ -1065,6 +1171,12 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return @"AXLandmarkNavigation";
case LandmarkSearchRole:
return @"AXLandmarkSearch";
+ case ApplicationAlertRole:
+ return @"AXApplicationAlert";
+ case ApplicationAlertDialogRole:
+ return @"AXApplicationAlertDialog";
+ case ApplicationDialogRole:
+ return @"AXApplicationDialog";
case ApplicationLogRole:
return @"AXApplicationLog";
case ApplicationMarqueeRole:
@@ -1077,14 +1189,23 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return @"AXDocument";
case DocumentArticleRole:
return @"AXDocumentArticle";
+ case DocumentMathRole:
+ return @"AXDocumentMath";
case DocumentNoteRole:
return @"AXDocumentNote";
case DocumentRegionRole:
return @"AXDocumentRegion";
case UserInterfaceTooltipRole:
return @"AXUserInterfaceTooltip";
+ case TabPanelRole:
+ return @"AXTabPanel";
+ case DefinitionListTermRole:
+ return @"AXTerm";
+ case DefinitionListDefinitionRole:
+ return @"AXDefinition";
+ // Default doesn't return anything, so roles defined below can be chosen.
default:
- return nil;
+ break;
}
if (m_object->isMediaTimeline())
@@ -1122,6 +1243,12 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return AXARIAContentGroupText(@"ARIALandmarkNavigation");
case LandmarkSearchRole:
return AXARIAContentGroupText(@"ARIALandmarkSearch");
+ case ApplicationAlertRole:
+ return AXARIAContentGroupText(@"ARIAApplicationAlert");
+ case ApplicationAlertDialogRole:
+ return AXARIAContentGroupText(@"ARIAApplicationAlertDialog");
+ case ApplicationDialogRole:
+ return AXARIAContentGroupText(@"ARIAApplicationDialog");
case ApplicationLogRole:
return AXARIAContentGroupText(@"ARIAApplicationLog");
case ApplicationMarqueeRole:
@@ -1134,12 +1261,20 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return AXARIAContentGroupText(@"ARIADocument");
case DocumentArticleRole:
return AXARIAContentGroupText(@"ARIADocumentArticle");
+ case DocumentMathRole:
+ return AXARIAContentGroupText(@"ARIADocumentMath");
case DocumentNoteRole:
return AXARIAContentGroupText(@"ARIADocumentNote");
case DocumentRegionRole:
return AXARIAContentGroupText(@"ARIADocumentRegion");
case UserInterfaceTooltipRole:
return AXARIAContentGroupText(@"ARIAUserInterfaceTooltip");
+ case TabPanelRole:
+ return AXARIAContentGroupText(@"ARIATabPanel");
+ case DefinitionListTermRole:
+ return AXDefinitionListTermText();
+ case DefinitionListDefinitionRole:
+ return AXDefinitionListDefinitionText();
}
}
@@ -1158,6 +1293,10 @@ static NSString* roleValueToNSString(AccessibilityRole value)
if ([axRole isEqualToString:@"AXHeading"])
return AXHeadingText();
+ // AppKit also returns AXTab for the role description for a tab item.
+ if (m_object->isTabItem())
+ return NSAccessibilityRoleDescription(@"AXTab", nil);
+
// We should try the system default role description for all other roles.
// If we get the same string back, then as a last resort, return unknown.
NSString* defaultRoleDescription = NSAccessibilityRoleDescription(axRole, [self subrole]);
@@ -1195,6 +1334,16 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return fv->platformWidget();
}
+ // Tree item (changed to AXRows) can only report the tree (AXOutline) as its parent.
+ if (m_object->isTreeItem()) {
+ AccessibilityObject* parent = m_object->parentObjectUnignored();
+ while (parent) {
+ if (parent->isTree())
+ return parent->wrapper();
+ parent = parent->parentObjectUnignored();
+ }
+ }
+
return m_object->parentObjectUnignored()->wrapper();
}
@@ -1204,6 +1353,19 @@ static NSString* roleValueToNSString(AccessibilityRole value)
if (children != nil)
return children;
}
+
+ // The tree's (AXOutline) children are supposed to be its rows and columns.
+ // The ARIA spec doesn't have columns, so we just need rows.
+ if (m_object->isTree())
+ return [self accessibilityAttributeValue:NSAccessibilityRowsAttribute];
+
+ // A tree item should only expose its content as its children (not its rows)
+ if (m_object->isTreeItem()) {
+ AccessibilityObject::AccessibilityChildrenVector contentCopy;
+ m_object->ariaTreeItemContent(contentCopy);
+ return convertToNSArray(contentCopy);
+ }
+
return convertToNSArray(m_object->children());
}
@@ -1305,7 +1467,7 @@ static NSString* roleValueToNSString(AccessibilityRole value)
if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute])
return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityValueAttribute];
}
- if (m_object->isProgressIndicator() || m_object->isSlider())
+ if (m_object->isProgressIndicator() || m_object->isSlider() || m_object->isScrollbar())
return [NSNumber numberWithFloat:m_object->valueForRange()];
if (m_object->hasIntValue())
return [NSNumber numberWithInt:m_object->intValue()];
@@ -1318,6 +1480,16 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return radioButton->wrapper();
}
+ if (m_object->isTabList()) {
+ AccessibilityObject* tabItem = m_object->selectedTabItem();
+ if (!tabItem)
+ return nil;
+ return tabItem->wrapper();
+ }
+
+ if (m_object->isTabItem())
+ return [NSNumber numberWithInt:m_object->isSelected()];
+
return m_object->stringValue();
}
@@ -1359,6 +1531,31 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return accessKey;
}
+ if ([attributeName isEqualToString:NSAccessibilityTabsAttribute]) {
+ if (m_object->isTabList()) {
+ AccessibilityObject::AccessibilityChildrenVector tabsChildren;
+ m_object->tabChildren(tabsChildren);
+ return convertToNSArray(tabsChildren);
+ }
+ }
+
+ if ([attributeName isEqualToString:NSAccessibilityContentsAttribute]) {
+ // The contents of a tab list are all the children except the tabs.
+ if (m_object->isTabList()) {
+ AccessibilityObject::AccessibilityChildrenVector children = m_object->children();
+ AccessibilityObject::AccessibilityChildrenVector tabsChildren;
+ m_object->tabChildren(tabsChildren);
+
+ AccessibilityObject::AccessibilityChildrenVector contents;
+ unsigned childrenSize = children.size();
+ for (unsigned k = 0; k < childrenSize; ++k) {
+ if (tabsChildren.find(children[k]) == WTF::notFound)
+ contents.append(children[k]);
+ }
+ return convertToNSArray(contents);
+ }
+ }
+
if (m_object->isDataTable()) {
// TODO: distinguish between visible and non-visible rows
if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] ||
@@ -1438,6 +1635,69 @@ static NSString* roleValueToNSString(AccessibilityRole value)
}
}
+ if (m_object->isTree()) {
+ if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
+ AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
+ m_object->selectedChildren(selectedChildrenCopy);
+ return convertToNSArray(selectedChildrenCopy);
+ }
+ if ([attributeName isEqualToString:NSAccessibilityRowsAttribute]) {
+ AccessibilityObject::AccessibilityChildrenVector rowsCopy;
+ m_object->ariaTreeRows(rowsCopy);
+ return convertToNSArray(rowsCopy);
+ }
+
+ // TreeRoles do not support columns, but Mac AX expects to be able to ask about columns at the least.
+ if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute])
+ return [NSArray array];
+ }
+
+ 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.
+ 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;
+ }
+
+ // The rows that are considered inside this row.
+ if ([attributeName isEqualToString:NSAccessibilityDisclosedRowsAttribute]) {
+ AccessibilityObject::AccessibilityChildrenVector rowsCopy;
+ m_object->ariaTreeItemDisclosedRows(rowsCopy);
+ return convertToNSArray(rowsCopy);
+ }
+
+ // The row that contains this row. It should be the same as the first parent that is a treeitem.
+ if ([attributeName isEqualToString:NSAccessibilityDisclosedByRowAttribute]) {
+ AccessibilityObject* parent = m_object->parentObject();
+ while (parent) {
+ if (parent->isTreeItem())
+ return parent->wrapper();
+ // If the parent is the tree itself, then this value == nil.
+ if (parent->isTree())
+ return nil;
+ parent = parent->parentObject();
+ }
+ return nil;
+ }
+ if ([attributeName isEqualToString:NSAccessibilityDisclosureLevelAttribute])
+ return [NSNumber numberWithInt:m_object->hierarchicalLevel()];
+ if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
+ return [NSNumber numberWithBool:m_object->isExpanded()];
+ }
+
if ((m_object->isListBox() || m_object->isList()) && [attributeName isEqualToString:NSAccessibilityOrientationAttribute])
return NSAccessibilityVerticalOrientationValue;
@@ -1504,9 +1764,32 @@ static NSString* roleValueToNSString(AccessibilityRole value)
if ([attributeName isEqualToString:NSAccessibilityLanguageAttribute])
return m_object->language();
+ if ([attributeName isEqualToString:NSAccessibilityExpandedAttribute])
+ return [NSNumber numberWithBool:m_object->isExpanded()];
+
if ([attributeName isEqualToString:NSAccessibilityRequiredAttribute])
return [NSNumber numberWithBool:m_object->isRequired()];
+ if ([attributeName isEqualToString:NSAccessibilityOwnsAttribute]) {
+ AccessibilityObject::AccessibilityChildrenVector ariaOwns;
+ m_object->ariaOwnsElements(ariaOwns);
+ return convertToNSArray(ariaOwns);
+ }
+
+ if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
+ return [NSNumber numberWithBool:m_object->isARIAGrabbed()];
+
+ if ([attributeName isEqualToString:NSAccessibilityDropEffectsAttribute]) {
+ Vector<String> dropEffects;
+ m_object->determineARIADropEffects(dropEffects);
+ size_t length = dropEffects.size();
+
+ NSMutableArray* dropEffectsArray = [NSMutableArray arrayWithCapacity:length];
+ for (size_t i = 0; i < length; ++i)
+ [dropEffectsArray addObject:dropEffects[i]];
+ return dropEffectsArray;
+ }
+
// this is used only by DumpRenderTree for testing
if ([attributeName isEqualToString:@"AXClickPoint"])
return [NSValue valueWithPoint:m_object->clickPoint()];
@@ -1570,11 +1853,20 @@ static NSString* roleValueToNSString(AccessibilityRole value)
if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute])
return m_object->canSetSelectedChildrenAttribute();
+ if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
+ return m_object->canSetExpandedAttribute();
+
+ if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute])
+ return YES;
+
if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute] ||
[attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute] ||
[attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
return m_object->canSetTextRangeAttributes();
+ if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
+ return YES;
+
return NO;
}
@@ -1736,9 +2028,13 @@ static NSString* roleValueToNSString(AccessibilityRole value)
- (void)accessibilityPerformShowMenuAction
{
- // This needs to be performed in an iteration of the run loop that did not start from an AX call.
- // If it's the same run loop iteration, the menu open notification won't be sent
- [self performSelector:@selector(accessibilityShowContextMenu) withObject:nil afterDelay:0.0];
+ if (m_object->roleValue() == ComboBoxRole)
+ m_object->setIsExpanded(true);
+ else {
+ // This needs to be performed in an iteration of the run loop that did not start from an AX call.
+ // If it's the same run loop iteration, the menu open notification won't be sent
+ [self performSelector:@selector(accessibilityShowContextMenu) withObject:nil afterDelay:0.0];
+ }
}
- (void)accessibilityShowContextMenu
@@ -1852,7 +2148,15 @@ static NSString* roleValueToNSString(AccessibilityRole value)
} else if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) {
m_object->makeRangeVisible(PlainTextRange(range.location, range.length));
}
- }
+ } else if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
+ m_object->setIsExpanded([number boolValue]);
+ else if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
+ AccessibilityObject::AccessibilityChildrenVector selectedRows;
+ convertToVector(array, selectedRows);
+ if (m_object->isTree())
+ m_object->setSelectedRows(selectedRows);
+ } else if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
+ m_object->setARIAGrabbed([number boolValue]);
}
static RenderObject* rendererForView(NSView* view)
@@ -2186,7 +2490,12 @@ static RenderObject* rendererForView(NSView* view)
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())
@@ -2212,6 +2521,11 @@ static RenderObject* rendererForView(NSView* view)
return 0;
if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
+ // Tree items object returns a different set of children than those that are in children()
+ // because an AXOutline (the mac role is becomes) has some odd stipulations.
+ if (m_object->isTree() || m_object->isTreeItem())
+ return [[self accessibilityAttributeValue:NSAccessibilityChildrenAttribute] count];
+
const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
if (children.isEmpty())
return [[self renderWidgetChildren] count];
@@ -2243,6 +2557,9 @@ static RenderObject* rendererForView(NSView* view)
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();
diff --git a/WebCore/accessibility/win/AXObjectCacheWin.cpp b/WebCore/accessibility/win/AXObjectCacheWin.cpp
index a1bdcc0..863793c 100644
--- a/WebCore/accessibility/win/AXObjectCacheWin.cpp
+++ b/WebCore/accessibility/win/AXObjectCacheWin.cpp
@@ -74,6 +74,7 @@ void AXObjectCache::postPlatformNotification(AccessibilityObject* obj, AXNotific
DWORD msaaEvent;
switch (notification) {
case AXFocusedUIElementChanged:
+ case AXActiveDescendantChanged:
msaaEvent = EVENT_OBJECT_FOCUS;
break;