summaryrefslogtreecommitdiffstats
path: root/WebCore/accessibility
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/accessibility')
-rw-r--r--WebCore/accessibility/AXObjectCache.cpp79
-rw-r--r--WebCore/accessibility/AXObjectCache.h53
-rw-r--r--WebCore/accessibility/AccessibilityList.cpp7
-rw-r--r--WebCore/accessibility/AccessibilityMediaControls.cpp323
-rw-r--r--WebCore/accessibility/AccessibilityMediaControls.h117
-rw-r--r--WebCore/accessibility/AccessibilityObject.cpp80
-rw-r--r--WebCore/accessibility/AccessibilityObject.h41
-rw-r--r--WebCore/accessibility/AccessibilityRenderObject.cpp159
-rw-r--r--WebCore/accessibility/AccessibilityRenderObject.h5
-rw-r--r--WebCore/accessibility/AccessibilitySlider.cpp20
-rw-r--r--WebCore/accessibility/AccessibilitySlider.h6
-rw-r--r--WebCore/accessibility/chromium/AXObjectCacheChromium.cpp8
-rw-r--r--WebCore/accessibility/gtk/AXObjectCacheAtk.cpp14
-rw-r--r--WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp4
-rw-r--r--WebCore/accessibility/mac/AXObjectCacheMac.mm38
-rw-r--r--WebCore/accessibility/mac/AccessibilityObjectWrapper.mm163
-rw-r--r--WebCore/accessibility/win/AXObjectCacheWin.cpp83
17 files changed, 1053 insertions, 147 deletions
diff --git a/WebCore/accessibility/AXObjectCache.cpp b/WebCore/accessibility/AXObjectCache.cpp
index 0b758e6..55199a3 100644
--- a/WebCore/accessibility/AXObjectCache.cpp
+++ b/WebCore/accessibility/AXObjectCache.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -36,6 +36,7 @@
#include "AccessibilityListBox.h"
#include "AccessibilityListBoxOption.h"
#include "AccessibilityImageMapLink.h"
+#include "AccessibilityMediaControls.h"
#include "AccessibilityRenderObject.h"
#include "AccessibilitySlider.h"
#include "AccessibilityTable.h"
@@ -43,8 +44,14 @@
#include "AccessibilityTableColumn.h"
#include "AccessibilityTableHeaderContainer.h"
#include "AccessibilityTableRow.h"
-#include "InputElement.h"
+#include "FocusController.h"
+#include "Frame.h"
#include "HTMLNames.h"
+#if ENABLE(VIDEO)
+#include "MediaControlElements.h"
+#endif
+#include "InputElement.h"
+#include "Page.h"
#include "RenderObject.h"
#include "RenderView.h"
@@ -73,6 +80,32 @@ AXObjectCache::~AXObjectCache()
}
}
+AccessibilityObject* AXObjectCache::focusedUIElementForPage(const Page* page)
+{
+ // get the focused node in the page
+ Document* focusedDocument = page->focusController()->focusedOrMainFrame()->document();
+ Node* focusedNode = focusedDocument->focusedNode();
+ if (!focusedNode)
+ focusedNode = focusedDocument;
+
+ RenderObject* focusedNodeRenderer = focusedNode->renderer();
+ if (!focusedNodeRenderer)
+ return 0;
+
+ AccessibilityObject* obj = focusedNodeRenderer->document()->axObjectCache()->getOrCreate(focusedNodeRenderer);
+
+ if (obj->shouldFocusActiveDescendant()) {
+ if (AccessibilityObject* descendant = obj->activeDescendant())
+ obj = descendant;
+ }
+
+ // the HTML element, for example, is focusable but has an AX object that is ignored
+ if (obj->accessibilityIsIgnored())
+ obj = obj->parentObjectUnignored();
+
+ return obj;
+}
+
AccessibilityObject* AXObjectCache::get(RenderObject* renderer)
{
if (!renderer)
@@ -108,7 +141,7 @@ AccessibilityObject* AXObjectCache::getOrCreate(RenderObject* renderer)
RefPtr<AccessibilityObject> newObj = 0;
if (renderer->isListBox())
newObj = AccessibilityListBox::create(renderer);
- else if (node && (node->hasTagName(ulTag) || node->hasTagName(olTag) || node->hasTagName(dlTag)))
+ else if (node && (nodeIsAriaType(node, "list") || node->hasTagName(ulTag) || node->hasTagName(olTag) || node->hasTagName(dlTag)))
newObj = AccessibilityList::create(renderer);
// aria tables
@@ -127,6 +160,12 @@ AccessibilityObject* AXObjectCache::getOrCreate(RenderObject* renderer)
else if (renderer->isTableCell())
newObj = AccessibilityTableCell::create(renderer);
+#if ENABLE(VIDEO)
+ // media controls
+ else if (renderer->node() && renderer->node()->isMediaControlElement())
+ newObj = AccessibilityMediaControl::create(renderer);
+#endif
+
// input type=range
else if (renderer->isSlider())
newObj = AccessibilitySlider::create(renderer);
@@ -213,6 +252,23 @@ void AXObjectCache::remove(RenderObject* renderer)
m_renderObjectMapping.remove(renderer);
}
+#if !PLATFORM(WIN)
+AXID AXObjectCache::platformGenerateAXID() const
+{
+ static AXID lastUsedID = 0;
+
+ // Generate a new ID.
+ AXID objID = lastUsedID;
+ do {
+ ++objID;
+ } while (objID == 0 || HashTraits<AXID>::isDeletedValue(objID) || m_idsInUse.contains(objID));
+
+ lastUsedID = objID;
+
+ return objID;
+}
+#endif
+
AXID AXObjectCache::getAXID(AccessibilityObject* obj)
{
// check for already-assigned ID
@@ -221,15 +277,10 @@ AXID AXObjectCache::getAXID(AccessibilityObject* obj)
ASSERT(m_idsInUse.contains(objID));
return objID;
}
-
- // generate a new ID
- static AXID lastUsedID = 0;
- objID = lastUsedID;
- do
- ++objID;
- while (objID == 0 || HashTraits<AXID>::isDeletedValue(objID) || m_idsInUse.contains(objID));
+
+ objID = platformGenerateAXID();
+
m_idsInUse.add(objID);
- lastUsedID = objID;
obj->setAXObjectID(objID);
return objID;
@@ -288,7 +339,7 @@ void AXObjectCache::notificationPostTimerFired(Timer<AXObjectCache>*)
}
#if HAVE(ACCESSIBILITY)
-void AXObjectCache::postNotification(RenderObject* renderer, const String& message, bool postToElement)
+void AXObjectCache::postNotification(RenderObject* renderer, AXNotification notification, bool postToElement)
{
// Notifications for text input objects are sent to that object.
// All others are sent to the top WebArea.
@@ -316,14 +367,14 @@ void AXObjectCache::postNotification(RenderObject* renderer, const String& messa
if (!obj)
return;
- m_notificationsToPost.append(make_pair(obj, message));
+ m_notificationsToPost.append(make_pair(obj, notification));
if (!m_notificationPostTimer.isActive())
m_notificationPostTimer.startOneShot(0);
}
void AXObjectCache::selectedChildrenChanged(RenderObject* renderer)
{
- postNotification(renderer, "AXSelectedChildrenChanged", true);
+ postNotification(renderer, AXSelectedChildrenChanged, true);
}
#endif
diff --git a/WebCore/accessibility/AXObjectCache.h b/WebCore/accessibility/AXObjectCache.h
index 7a808dd..5a75f84 100644
--- a/WebCore/accessibility/AXObjectCache.h
+++ b/WebCore/accessibility/AXObjectCache.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -42,13 +42,11 @@ class WebCoreTextMarker;
namespace WebCore {
+ class Node;
+ class Page;
class RenderObject;
class String;
class VisiblePosition;
- class AccessibilityObject;
- class Node;
-
- typedef unsigned AXID;
struct TextMarkerData {
AXID axID;
@@ -61,7 +59,9 @@ namespace WebCore {
public:
AXObjectCache();
~AXObjectCache();
-
+
+ static AccessibilityObject* focusedUIElementForPage(const Page*);
+
// to be used with render objects
AccessibilityObject* getOrCreate(RenderObject*);
@@ -76,16 +76,13 @@ namespace WebCore {
void detachWrapper(AccessibilityObject*);
void attachWrapper(AccessibilityObject*);
- void postNotification(RenderObject*, const String&, bool postToElement);
- void postPlatformNotification(AccessibilityObject*, const String&);
void childrenChanged(RenderObject*);
void selectedChildrenChanged(RenderObject*);
void handleActiveDescendantChanged(RenderObject*);
void handleAriaRoleChanged(RenderObject*);
- void handleFocusedUIElementChanged();
-#if PLATFORM(GTK)
- void handleFocusedUIElementChangedWithRenderers(RenderObject*, RenderObject*);
-#endif
+ void handleFocusedUIElementChanged(RenderObject* oldFocusedRenderer, RenderObject* newFocusedRenderer);
+ void handleScrolledToAnchor(const Node* anchorNode);
+
static void enableAccessibility() { gAccessibilityEnabled = true; }
static void enableEnhancedUserInterfaceAccessibility() { gAccessibilityEnhancedUserInterfaceEnabled = true; }
@@ -94,11 +91,29 @@ namespace WebCore {
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;
@@ -108,7 +123,7 @@ namespace WebCore {
HashSet<AXID> m_idsInUse;
Timer<AXObjectCache> m_notificationPostTimer;
- Vector<pair<RefPtr<AccessibilityObject>, const String> > m_notificationsToPost;
+ Vector<pair<RefPtr<AccessibilityObject>, AXNotification> > m_notificationsToPost;
void notificationPostTimerFired(Timer<AXObjectCache>*);
AXID getAXID(AccessibilityObject*);
@@ -118,15 +133,13 @@ namespace WebCore {
#if !HAVE(ACCESSIBILITY)
inline void AXObjectCache::handleActiveDescendantChanged(RenderObject*) { }
inline void AXObjectCache::handleAriaRoleChanged(RenderObject*) { }
- inline void AXObjectCache::handleFocusedUIElementChanged() { }
inline void AXObjectCache::detachWrapper(AccessibilityObject*) { }
inline void AXObjectCache::attachWrapper(AccessibilityObject*) { }
inline void AXObjectCache::selectedChildrenChanged(RenderObject*) { }
- inline void AXObjectCache::postNotification(RenderObject*, const String&, bool postToElement) { }
- inline void AXObjectCache::postPlatformNotification(AccessibilityObject*, const String&) { }
-#if PLATFORM(GTK)
- inline void AXObjectCache::handleFocusedUIElementChangedWithRenderers(RenderObject*, RenderObject*) { }
-#endif
+ 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/AccessibilityList.cpp b/WebCore/accessibility/AccessibilityList.cpp
index 3b7c7a4..95239b0 100644
--- a/WebCore/accessibility/AccessibilityList.cpp
+++ b/WebCore/accessibility/AccessibilityList.cpp
@@ -69,6 +69,13 @@ bool AccessibilityList::isUnorderedList() const
return false;
Node* node = m_renderer->node();
+
+ // The ARIA spec says the "list" role is supposed to mimic a UL or OL tag.
+ // Since it can't be both, it's probably OK to say that it's an un-ordered list.
+ // On the Mac, there's no distinction to the client.
+ if (ariaRoleAttribute() == ListRole)
+ return true;
+
return node && node->hasTagName(ulTag);
}
diff --git a/WebCore/accessibility/AccessibilityMediaControls.cpp b/WebCore/accessibility/AccessibilityMediaControls.cpp
new file mode 100644
index 0000000..7200de9
--- /dev/null
+++ b/WebCore/accessibility/AccessibilityMediaControls.cpp
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "config.h"
+
+#if ENABLE(VIDEO)
+
+#include "AccessibilityMediaControls.h"
+
+#include "AXObjectCache.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "LocalizedStrings.h"
+#include "MediaControlElements.h"
+#include "RenderObject.h"
+#include "RenderSlider.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+
+AccessibilityMediaControl::AccessibilityMediaControl(RenderObject* renderer)
+ : AccessibilityRenderObject(renderer)
+{
+}
+
+PassRefPtr<AccessibilityObject> AccessibilityMediaControl::create(RenderObject* renderer)
+{
+ ASSERT(renderer->node() && renderer->node()->isMediaControlElement());
+
+ Node* node = renderer->node();
+ MediaControlElementType controlType;
+
+ if (node->hasTagName(inputTag))
+ controlType = static_cast<MediaControlInputElement*>(node)->displayType();
+ else
+ controlType = static_cast<MediaControlElement*>(node)->displayType();
+
+ PassRefPtr<AccessibilityObject> obj;
+ switch (controlType) {
+ case MediaSlider:
+ obj = AccessibilityMediaTimeline::create(renderer);
+ break;
+
+ case MediaCurrentTimeDisplay:
+ case MediaTimeRemainingDisplay:
+ obj = AccessibilityMediaTimeDisplay::create(renderer);
+ break;
+
+ case MediaControlsPanel:
+ obj = AccessibilityMediaControlsContainer::create(renderer);
+ break;
+
+ default:
+ obj = adoptRef(new AccessibilityMediaControl(renderer));
+ break;
+ }
+
+ return obj;
+}
+
+MediaControlElementType AccessibilityMediaControl::controlType() const
+{
+ if (!renderer() || !renderer()->node())
+ return MediaTimelineContainer; // Timeline container is not accessible.
+
+ Node* node = renderer()->node();
+
+ if (node->hasTagName(inputTag))
+ return static_cast<MediaControlInputElement*>(node)->displayType();
+
+ return static_cast<MediaControlElement*>(node)->displayType();
+}
+
+String AccessibilityMediaControl::controlTypeName() const
+{
+ DEFINE_STATIC_LOCAL(const String, mediaFullscreenButtonName, ("FullscreenButton"));
+ DEFINE_STATIC_LOCAL(const String, mediaMuteButtonName, ("MuteButton"));
+ DEFINE_STATIC_LOCAL(const String, mediaPlayButtonName, ("PlayButton"));
+ DEFINE_STATIC_LOCAL(const String, mediaSeekBackButtonName, ("SeekBackButton"));
+ DEFINE_STATIC_LOCAL(const String, mediaSeekForwardButtonName, ("SeekForwardButton"));
+ DEFINE_STATIC_LOCAL(const String, mediaRewindButtonName, ("RewindButton"));
+ DEFINE_STATIC_LOCAL(const String, mediaReturnToRealtimeButtonName, ("ReturnToRealtimeButton"));
+ DEFINE_STATIC_LOCAL(const String, mediaUnMuteButtonName, ("UnMuteButton"));
+ DEFINE_STATIC_LOCAL(const String, mediaPauseButtonName, ("PauseButton"));
+ DEFINE_STATIC_LOCAL(const String, mediaStatusDisplayName, ("StatusDisplay"));
+ DEFINE_STATIC_LOCAL(const String, mediaCurrentTimeDisplay, ("CurrentTimeDisplay"));
+ DEFINE_STATIC_LOCAL(const String, mediaTimeRemainingDisplay, ("TimeRemainingDisplay"));
+
+ switch (controlType()) {
+ case MediaFullscreenButton:
+ return mediaFullscreenButtonName;
+ case MediaMuteButton:
+ return mediaMuteButtonName;
+ case MediaPlayButton:
+ return mediaPlayButtonName;
+ case MediaSeekBackButton:
+ return mediaSeekBackButtonName;
+ case MediaSeekForwardButton:
+ return mediaSeekForwardButtonName;
+ case MediaRewindButton:
+ return mediaRewindButtonName;
+ case MediaReturnToRealtimeButton:
+ return mediaReturnToRealtimeButtonName;
+ case MediaUnMuteButton:
+ return mediaUnMuteButtonName;
+ case MediaPauseButton:
+ return mediaPauseButtonName;
+ case MediaStatusDisplay:
+ return mediaStatusDisplayName;
+ case MediaCurrentTimeDisplay:
+ return mediaCurrentTimeDisplay;
+ case MediaTimeRemainingDisplay:
+ return mediaTimeRemainingDisplay;
+
+ default:
+ break;
+ }
+
+ return String();
+}
+
+String AccessibilityMediaControl::title() const
+{
+ DEFINE_STATIC_LOCAL(const String, controlsPanel, ("ControlsPanel"));
+
+ if (controlType() == MediaControlsPanel)
+ return localizedMediaControlElementString(controlsPanel);
+
+ return AccessibilityRenderObject::title();
+}
+
+String AccessibilityMediaControl::accessibilityDescription() const
+{
+ return localizedMediaControlElementString(controlTypeName());
+}
+
+String AccessibilityMediaControl::helpText() const
+{
+ return localizedMediaControlElementHelpText(controlTypeName());
+}
+
+bool AccessibilityMediaControl::accessibilityIsIgnored() const
+{
+ if (!m_renderer || !m_renderer->style() || m_renderer->style()->visibility() != VISIBLE || controlType() == MediaTimelineContainer)
+ return true;
+
+ return false;
+}
+
+AccessibilityRole AccessibilityMediaControl::roleValue() const
+{
+ switch (controlType()) {
+ case MediaFullscreenButton:
+ case MediaMuteButton:
+ case MediaPlayButton:
+ case MediaSeekBackButton:
+ case MediaSeekForwardButton:
+ case MediaRewindButton:
+ case MediaReturnToRealtimeButton:
+ case MediaUnMuteButton:
+ case MediaPauseButton:
+ return ButtonRole;
+
+ case MediaStatusDisplay:
+ return StaticTextRole;
+
+ case MediaTimelineContainer:
+ return GroupRole;
+
+ default:
+ break;
+ }
+
+ return UnknownRole;
+}
+
+
+
+//
+// AccessibilityMediaControlsContainer
+
+AccessibilityMediaControlsContainer::AccessibilityMediaControlsContainer(RenderObject* renderer)
+ : AccessibilityMediaControl(renderer)
+{
+}
+
+PassRefPtr<AccessibilityObject> AccessibilityMediaControlsContainer::create(RenderObject* renderer)
+{
+ return adoptRef(new AccessibilityMediaControlsContainer(renderer));
+}
+
+String AccessibilityMediaControlsContainer::accessibilityDescription() const
+{
+ return localizedMediaControlElementString(elementTypeName());
+}
+
+String AccessibilityMediaControlsContainer::helpText() const
+{
+ return localizedMediaControlElementHelpText(elementTypeName());
+}
+
+bool AccessibilityMediaControlsContainer::controllingVideoElement() const
+{
+ if (!m_renderer->node())
+ return true;
+
+ MediaControlTimeDisplayElement* element = static_cast<MediaControlTimeDisplayElement*>(m_renderer->node());
+
+ return element->mediaElement()->isVideo();
+}
+
+const String AccessibilityMediaControlsContainer::elementTypeName() const
+{
+ DEFINE_STATIC_LOCAL(const String, videoElement, ("VideoElement"));
+ DEFINE_STATIC_LOCAL(const String, audioElement, ("AudioElement"));
+
+ if (controllingVideoElement())
+ return videoElement;
+ return audioElement;
+}
+
+
+//
+// AccessibilityMediaTimeline
+
+AccessibilityMediaTimeline::AccessibilityMediaTimeline(RenderObject* renderer)
+ : AccessibilitySlider(renderer)
+{
+}
+
+PassRefPtr<AccessibilityObject> AccessibilityMediaTimeline::create(RenderObject* renderer)
+{
+ return adoptRef(new AccessibilityMediaTimeline(renderer));
+}
+
+String AccessibilityMediaTimeline::valueDescription() const
+{
+ ASSERT(m_renderer->node()->hasTagName(inputTag));
+
+ float time = static_cast<HTMLInputElement*>(m_renderer->node())->value().toFloat();
+ return localizedMediaTimeDescription(time);
+}
+
+String AccessibilityMediaTimeline::helpText() const
+{
+ DEFINE_STATIC_LOCAL(const String, slider, ("Slider"));
+ return localizedMediaControlElementHelpText(slider);
+}
+
+
+//
+// AccessibilityMediaTimeDisplay
+
+AccessibilityMediaTimeDisplay::AccessibilityMediaTimeDisplay(RenderObject* renderer)
+ : AccessibilityMediaControl(renderer)
+{
+}
+
+PassRefPtr<AccessibilityObject> AccessibilityMediaTimeDisplay::create(RenderObject* renderer)
+{
+ return adoptRef(new AccessibilityMediaTimeDisplay(renderer));
+}
+
+bool AccessibilityMediaTimeDisplay::accessibilityIsIgnored() const
+{
+ if (!m_renderer || !m_renderer->style() || m_renderer->style()->visibility() != VISIBLE)
+ return true;
+
+ return !m_renderer->style()->width().value();
+}
+
+String AccessibilityMediaTimeDisplay::accessibilityDescription() const
+{
+ DEFINE_STATIC_LOCAL(const String, currentTimeDisplay, ("CurrentTimeDisplay"));
+ DEFINE_STATIC_LOCAL(const String, timeRemainingDisplay, ("TimeRemainingDisplay"));
+
+ if (controlType() == MediaCurrentTimeDisplay)
+ return localizedMediaControlElementString(currentTimeDisplay);
+
+ return localizedMediaControlElementString(timeRemainingDisplay);
+}
+
+String AccessibilityMediaTimeDisplay::stringValue() const
+{
+ if (!m_renderer || !m_renderer->node())
+ return String();
+
+ MediaControlTimeDisplayElement* element = static_cast<MediaControlTimeDisplayElement*>(m_renderer->node());
+ float time = element->currentValue();
+ return localizedMediaTimeDescription(fabsf(time));
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(VIDEO)
diff --git a/WebCore/accessibility/AccessibilityMediaControls.h b/WebCore/accessibility/AccessibilityMediaControls.h
new file mode 100644
index 0000000..9b306fd
--- /dev/null
+++ b/WebCore/accessibility/AccessibilityMediaControls.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef AccessibilityMediaControls_h
+#define AccessibilityMediaControls_h
+
+#if ENABLE(VIDEO)
+
+#include "AccessibilitySlider.h"
+#include "MediaControlElements.h"
+
+namespace WebCore {
+
+ class AccessibilityMediaControl : public AccessibilityRenderObject {
+
+ public:
+ static PassRefPtr<AccessibilityObject> create(RenderObject*);
+ virtual ~AccessibilityMediaControl() { }
+
+ virtual AccessibilityRole roleValue() const;
+ virtual bool accessibilityIsIgnored() const;
+
+ virtual String title() const;
+ virtual String accessibilityDescription() const;
+ virtual String helpText() const;
+
+ protected:
+ AccessibilityMediaControl(RenderObject*);
+ MediaControlElementType controlType() const;
+ String controlTypeName() const;
+ };
+
+
+ class AccessibilityMediaTimeline : public AccessibilitySlider {
+
+ public:
+ static PassRefPtr<AccessibilityObject> create(RenderObject*);
+ virtual ~AccessibilityMediaTimeline() { }
+
+ virtual bool isMediaTimeline() const { return true; }
+
+ virtual String helpText() const;
+ virtual String valueDescription() const;
+ const AtomicString& getAttribute(const QualifiedName& attribute) const;
+
+ private:
+ AccessibilityMediaTimeline(RenderObject*);
+ };
+
+
+ class AccessibilityMediaControlsContainer : public AccessibilityMediaControl {
+
+ public:
+ static PassRefPtr<AccessibilityObject> create(RenderObject*);
+ virtual ~AccessibilityMediaControlsContainer() { }
+
+ virtual AccessibilityRole roleValue() const { return ToolbarRole; }
+ virtual bool accessibilityIsIgnored() const { return false; }
+
+ virtual String helpText() const;
+ virtual String accessibilityDescription() const;
+
+ private:
+ AccessibilityMediaControlsContainer(RenderObject*);
+ bool controllingVideoElement() const;
+ const String elementTypeName() const;
+ };
+
+
+ class AccessibilityMediaTimeDisplay : public AccessibilityMediaControl {
+
+ public:
+ static PassRefPtr<AccessibilityObject> create(RenderObject*);
+ virtual ~AccessibilityMediaTimeDisplay() { }
+
+ virtual AccessibilityRole roleValue() const { return StaticTextRole; }
+ virtual bool accessibilityIsIgnored() const;
+
+ virtual String stringValue() const;
+ virtual String accessibilityDescription() const;
+
+ private:
+ AccessibilityMediaTimeDisplay(RenderObject*);
+ };
+
+
+} // namespace WebCore
+
+#endif // ENABLE(VIDEO)
+
+#endif // AccessibilityMediaControls_h
diff --git a/WebCore/accessibility/AccessibilityObject.cpp b/WebCore/accessibility/AccessibilityObject.cpp
index d6fd969..d7093e4 100644
--- a/WebCore/accessibility/AccessibilityObject.cpp
+++ b/WebCore/accessibility/AccessibilityObject.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -41,6 +41,7 @@
#include "NotImplemented.h"
#include "Page.h"
#include "RenderImage.h"
+#include "RenderListItem.h"
#include "RenderListMarker.h"
#include "RenderMenuList.h"
#include "RenderTextControl.h"
@@ -89,6 +90,35 @@ AccessibilityObject* AccessibilityObject::parentObjectUnignored() const
return parent;
}
+AccessibilityObject* AccessibilityObject::firstAccessibleObjectFromNode(const Node* node)
+{
+ ASSERT(AXObjectCache::accessibilityEnabled());
+
+ if (!node)
+ return 0;
+
+ Document* document = node->document();
+ if (!document)
+ return 0;
+
+ AXObjectCache* cache = document->axObjectCache();
+
+ AccessibilityObject* accessibleObject = cache->getOrCreate(node->renderer());
+ while (accessibleObject && accessibleObject->accessibilityIsIgnored()) {
+ node = node->traverseNextNode();
+
+ while (node && !node->renderer())
+ node = node->traverseNextSibling();
+
+ if (!node)
+ return 0;
+
+ accessibleObject = cache->getOrCreate(node->renderer());
+ }
+
+ return accessibleObject;
+}
+
bool AccessibilityObject::isARIAInput(AccessibilityRole ariaRole)
{
return ariaRole == RadioButtonRole || ariaRole == CheckBoxRole || ariaRole == TextFieldRole;
@@ -363,6 +393,49 @@ static bool replacedNodeNeedsCharacter(Node* replacedNode)
return true;
}
+// Finds a RenderListItem parent give a node.
+RenderListItem* AccessibilityObject::renderListItemContainerForNode(Node* node) const
+{
+ for (Node* stringNode = node; stringNode; stringNode = stringNode->parent()) {
+ RenderObject* renderObject = stringNode->renderer();
+ if (!renderObject || !renderObject->isListItem())
+ continue;
+
+ return toRenderListItem(renderObject);
+ }
+
+ return 0;
+}
+
+// Returns the text associated with a list marker if this node is contained within a list item.
+String AccessibilityObject::listMarkerTextForNodeAndPosition(Node* node, const VisiblePosition& visiblePositionStart) const
+{
+ // If the range does not contain the start of the line, the list marker text should not be included.
+ if (!isStartOfLine(visiblePositionStart))
+ return String();
+
+ RenderListItem* listItem = renderListItemContainerForNode(node);
+ if (!listItem)
+ return String();
+
+ // If this is in a list item, we need to manually add the text for the list marker
+ // because a RenderListMarker does not have a Node equivalent and thus does not appear
+ // when iterating text.
+ const String& markerText = listItem->markerText();
+ if (markerText.isEmpty())
+ return String();
+
+ // Append text, plus the period that follows the text.
+ // FIXME: Not all list marker styles are followed by a period, but this
+ // sounds much better when there is a synthesized pause because of a period.
+ Vector<UChar> resultVector;
+ resultVector.append(markerText.characters(), markerText.length());
+ resultVector.append('.');
+ resultVector.append(' ');
+
+ return String::adopt(resultVector);
+}
+
String AccessibilityObject::stringForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const
{
if (visiblePositionRange.isNull())
@@ -373,6 +446,11 @@ String AccessibilityObject::stringForVisiblePositionRange(const VisiblePositionR
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) {
+ // Add a textual representation for list marker text
+ String listMarkerText = listMarkerTextForNodeAndPosition(it.node(), visiblePositionRange.start);
+ if (!listMarkerText.isEmpty())
+ resultVector.append(listMarkerText.characters(), listMarkerText.length());
+
resultVector.append(it.characters(), it.length());
} else {
// locate the node and starting offset for this replaced range
diff --git a/WebCore/accessibility/AccessibilityObject.h b/WebCore/accessibility/AccessibilityObject.h
index 3f6c395..c5ba1ed 100644
--- a/WebCore/accessibility/AccessibilityObject.h
+++ b/WebCore/accessibility/AccessibilityObject.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2008 Nuanti Ltd.
*
* Redistribution and use in source and binary forms, with or without
@@ -86,10 +86,13 @@ class IntPoint;
class IntSize;
class Node;
class RenderObject;
+class RenderListItem;
class VisibleSelection;
class String;
class Widget;
+typedef unsigned AXID;
+
enum AccessibilityRole {
UnknownRole = 1,
ButtonRole,
@@ -156,7 +159,28 @@ enum AccessibilityRole {
DefinitionListTermRole,
DefinitionListDefinitionRole,
AnnotationRole,
- SliderThumbRole
+ SliderThumbRole,
+
+ // ARIA Grouping roles
+ LandmarkApplicationRole,
+ LandmarkBannerRole,
+ LandmarkComplementaryRole,
+ LandmarkContentInfoRole,
+ LandmarkMainRole,
+ LandmarkNavigationRole,
+ LandmarkSearchRole,
+
+ ApplicationLogRole,
+ ApplicationMarqueeRole,
+ ApplicationStatusRole,
+ ApplicationTimerRole,
+
+ DocumentRole,
+ DocumentArticleRole,
+ DocumentNoteRole,
+ DocumentRegionRole,
+
+ UserInterfaceTooltipRole
};
enum AccessibilityOrientation {
@@ -220,6 +244,7 @@ public:
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; }
@@ -285,11 +310,13 @@ public:
virtual AccessibilityObject* parentObject() const = 0;
virtual AccessibilityObject* parentObjectUnignored() const;
virtual AccessibilityObject* parentObjectIfExists() const { return 0; }
+ static AccessibilityObject* firstAccessibleObjectFromNode(const Node*);
virtual AccessibilityObject* observableObject() const { return 0; }
virtual void linkedUIElements(AccessibilityChildrenVector&) const { }
virtual AccessibilityObject* titleUIElement() const { return 0; }
virtual bool exposesTitleUIElement() const { return true; }
+ virtual AccessibilityObject* correspondingControlForLabelElement() const { return 0; }
virtual AccessibilityRole ariaRoleAttribute() const { return UnknownRole; }
virtual bool isPresentationalChildOfAriaRole() const { return false; }
@@ -304,8 +331,8 @@ public:
virtual PassRefPtr<Range> ariaSelectedTextDOMRange() const { return 0; }
virtual AXObjectCache* axObjectCache() const { return 0; }
- unsigned axObjectID() const { return m_id; }
- void setAXObjectID(unsigned axObjectID) { m_id = axObjectID; }
+ AXID axObjectID() const { return m_id; }
+ void setAXObjectID(AXID axObjectID) { m_id = axObjectID; }
static AccessibilityObject* anchorElementForNode(Node*);
virtual Element* anchorElement() const { return 0; }
@@ -408,6 +435,7 @@ public:
virtual String doAXStringForRange(const PlainTextRange&) const { return String(); }
virtual IntRect doAXBoundsForRange(const PlainTextRange&) const { return IntRect(); }
+ String listMarkerTextForNodeAndPosition(Node*, const VisiblePosition&) const;
unsigned doAXLineForIndex(unsigned);
@@ -436,14 +464,15 @@ public:
virtual void updateBackingStore() { }
protected:
- unsigned m_id;
+ AXID m_id;
AccessibilityChildrenVector m_children;
mutable bool m_haveChildren;
AccessibilityRole m_role;
virtual void clearChildren();
virtual bool isDetached() const { return true; }
-
+ RenderListItem* renderListItemContainerForNode(Node* node) const;
+
#if PLATFORM(MAC)
RetainPtr<AccessibilityObjectWrapper> m_wrapper;
#elif PLATFORM(WIN) && !PLATFORM(WINCE)
diff --git a/WebCore/accessibility/AccessibilityRenderObject.cpp b/WebCore/accessibility/AccessibilityRenderObject.cpp
index e0f9a91..834e931 100644
--- a/WebCore/accessibility/AccessibilityRenderObject.cpp
+++ b/WebCore/accessibility/AccessibilityRenderObject.cpp
@@ -35,7 +35,6 @@
#include "CharacterNames.h"
#include "EventNames.h"
#include "FloatRect.h"
-#include "FocusController.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "HTMLAreaElement.h"
@@ -54,7 +53,6 @@
#include "HitTestResult.h"
#include "LocalizedStrings.h"
#include "NodeList.h"
-#include "Page.h"
#include "RenderButton.h"
#include "RenderFieldset.h"
#include "RenderFileUploadControl.h"
@@ -404,6 +402,11 @@ bool AccessibilityRenderObject::isReadOnly() const
return !frame->isContentEditable();
}
+ if (m_renderer->isTextField())
+ return static_cast<HTMLInputElement*>(m_renderer->node())->readOnly();
+ if (m_renderer->isTextArea())
+ return static_cast<HTMLTextAreaElement*>(m_renderer->node())->readOnly();
+
return !m_renderer->node() || !m_renderer->node()->isContentEditable();
}
@@ -603,6 +606,22 @@ Element* AccessibilityRenderObject::mouseButtonListener() const
return 0;
}
+void AccessibilityRenderObject::increment()
+{
+ if (roleValue() != SliderRole)
+ return;
+
+ changeValueByPercent(5);
+}
+
+void AccessibilityRenderObject::decrement()
+{
+ if (roleValue() != SliderRole)
+ return;
+
+ changeValueByPercent(-5);
+}
+
static Element* siblingWithAriaRole(String role, Node* node)
{
Node* sibling = node->parent()->firstChild();
@@ -1020,7 +1039,7 @@ String AccessibilityRenderObject::accessibilityDescription() const
const AtomicString& title = static_cast<HTMLFrameElementBase*>(owner)->getAttribute(titleAttr);
if (!title.isEmpty())
return title;
- return static_cast<HTMLFrameElementBase*>(owner)->name();
+ return static_cast<HTMLFrameElementBase*>(owner)->getAttribute(nameAttr);
}
if (owner->isHTMLElement())
return static_cast<HTMLElement*>(owner)->getAttribute(nameAttr);
@@ -1135,22 +1154,10 @@ AccessibilityObject* AccessibilityRenderObject::internalLinkElement() const
if (!linkedNode)
return 0;
- // the element we find may not be accessible, keep searching until we find a good one
- AccessibilityObject* linkedAXElement = m_renderer->document()->axObjectCache()->getOrCreate(linkedNode->renderer());
- while (linkedAXElement && linkedAXElement->accessibilityIsIgnored()) {
- linkedNode = linkedNode->traverseNextNode();
-
- while (linkedNode && !linkedNode->renderer())
- linkedNode = linkedNode->traverseNextSibling();
-
- if (!linkedNode)
- return 0;
- linkedAXElement = m_renderer->document()->axObjectCache()->getOrCreate(linkedNode->renderer());
- }
-
- return linkedAXElement;
+ // The element we find may not be accessible, so find the first accessible object.
+ return firstAccessibleObjectFromNode(linkedNode);
}
-
+
void AccessibilityRenderObject::addRadioButtonGroupMembers(AccessibilityChildrenVector& linkedUIElements) const
{
if (!m_renderer || roleValue() != RadioButtonRole)
@@ -1269,15 +1276,9 @@ 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
- HTMLLabelElement* labelElement = labelElementContainer();
- if (labelElement) {
- HTMLElement* correspondingControl = labelElement->correspondingControl();
- if (correspondingControl && correspondingControl->renderer()) {
- AccessibilityObject* controlObject = axObjectCache()->getOrCreate(correspondingControl->renderer());
- if (!controlObject->exposesTitleUIElement())
- return true;
- }
- }
+ AccessibilityObject* controlObject = correspondingControlForLabelElement();
+ if (controlObject && !controlObject->exposesTitleUIElement())
+ return true;
AccessibilityRole ariaRole = ariaRoleAttribute();
if (ariaRole == TextAreaRole || ariaRole == StaticTextRole) {
@@ -1590,8 +1591,22 @@ void AccessibilityRenderObject::setFocused(bool on)
}
}
+void AccessibilityRenderObject::changeValueByPercent(float percentChange)
+{
+ float range = maxValueForRange() - minValueForRange();
+ float value = valueForRange();
+
+ value += range * (percentChange / 100);
+ setValue(String::number(value));
+
+ axObjectCache()->postNotification(m_renderer, AXObjectCache::AXValueChanged, true);
+}
+
void AccessibilityRenderObject::setValue(const String& string)
{
+ if (!m_renderer)
+ return;
+
// FIXME: Do we want to do anything here for ARIA textboxes?
if (m_renderer->isTextField()) {
HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->node());
@@ -1599,6 +1614,10 @@ void AccessibilityRenderObject::setValue(const String& string)
} else if (m_renderer->isTextArea()) {
HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(m_renderer->node());
textArea->setValue(string);
+ } else if (roleValue() == SliderRole) {
+ Node* element = m_renderer->node();
+ if (element && element->isElementNode())
+ static_cast<Element*>(element)->setAttribute(aria_valuenowAttr, string);
}
}
@@ -1658,7 +1677,7 @@ AccessibilityObject* AccessibilityRenderObject::accessibilityParentForImageMap(H
// The HTMLImageElement's useMap() value includes the '#' symbol at the beginning,
// which has to be stripped off
- String useMapName = static_cast<HTMLImageElement*>(curr)->useMap().substring(1).lower();
+ String useMapName = static_cast<HTMLImageElement*>(curr)->getAttribute(usemapAttr).string().substring(1).lower();
if (useMapName == mapName)
return axObjectCache()->getOrCreate(obj);
}
@@ -2094,40 +2113,25 @@ AccessibilityObject* AccessibilityRenderObject::doAccessibilityHitTest(const Int
if (obj->isListBox())
return static_cast<AccessibilityListBox*>(result)->doAccessibilityHitTest(point);
- if (result->accessibilityIsIgnored())
+ if (result->accessibilityIsIgnored()) {
+ // If this element is the label of a control, a hit test should return the control.
+ AccessibilityObject* controlObject = result->correspondingControlForLabelElement();
+ if (controlObject && !controlObject->exposesTitleUIElement())
+ return controlObject;
+
result = result->parentObjectUnignored();
+ }
return result;
}
AccessibilityObject* AccessibilityRenderObject::focusedUIElement() const
{
- // get the focused node in the page
Page* page = m_renderer->document()->page();
if (!page)
return 0;
-
- Document* focusedDocument = page->focusController()->focusedOrMainFrame()->document();
- Node* focusedNode = focusedDocument->focusedNode();
- if (!focusedNode)
- focusedNode = focusedDocument;
-
- RenderObject* focusedNodeRenderer = focusedNode->renderer();
- if (!focusedNodeRenderer)
- return 0;
-
- AccessibilityObject* obj = focusedNodeRenderer->document()->axObjectCache()->getOrCreate(focusedNodeRenderer);
-
- if (obj->shouldFocusActiveDescendant()) {
- if (AccessibilityObject* descendant = obj->activeDescendant())
- obj = descendant;
- }
-
- // the HTML element, for example, is focusable but has an AX object that is ignored
- if (obj->accessibilityIsIgnored())
- obj = obj->parentObjectUnignored();
-
- return obj;
+
+ return AXObjectCache::focusedUIElementForPage(page);
}
bool AccessibilityRenderObject::shouldFocusActiveDescendant() const
@@ -2174,7 +2178,7 @@ AccessibilityObject* AccessibilityRenderObject::activeDescendant() const
return 0;
AccessibilityObject* obj = renderer()->document()->axObjectCache()->getOrCreate(target->renderer());
- if (obj->isAccessibilityRenderObject())
+ 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;
return 0;
@@ -2192,9 +2196,21 @@ void AccessibilityRenderObject::handleActiveDescendantChanged()
AccessibilityRenderObject* activedescendant = static_cast<AccessibilityRenderObject*>(activeDescendant());
if (activedescendant && shouldFocusActiveDescendant())
- doc->axObjectCache()->postNotification(activedescendant->renderer(), "AXFocusedUIElementChanged", true);
+ doc->axObjectCache()->postNotification(activedescendant->renderer(), AXObjectCache::AXFocusedUIElementChanged, true);
}
+AccessibilityObject* AccessibilityRenderObject::correspondingControlForLabelElement() const
+{
+ HTMLLabelElement* labelElement = labelElementContainer();
+ if (!labelElement)
+ return 0;
+
+ HTMLElement* correspondingControl = labelElement->correspondingControl();
+ if (!correspondingControl)
+ return 0;
+
+ return axObjectCache()->getOrCreate(correspondingControl->renderer());
+}
AccessibilityObject* AccessibilityRenderObject::observableObject() const
{
@@ -2216,32 +2232,52 @@ 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 },
{ "progressbar", ProgressIndicatorRole },
{ "radio", RadioButtonRole },
{ "radiogroup", RadioGroupRole },
+ { "region", DocumentRegionRole },
{ "row", RowRole },
{ "range", SliderRole },
+ { "search", LandmarkSearchRole },
+ { "separator", SplitterRole },
{ "slider", SliderRole },
{ "spinbutton", ProgressIndicatorRole },
+ { "status", ApplicationStatusRole },
{ "textbox", TextAreaRole },
- { "toolbar", ToolbarRole }
+ { "timer", ApplicationTimerRole },
+ { "toolbar", ToolbarRole },
+ { "tooltip", UserInterfaceTooltipRole }
};
ARIARoleMap& roleMap = *new ARIARoleMap;
@@ -2418,6 +2454,7 @@ bool AccessibilityRenderObject::canSetFocusAttribute() const
case PopUpButtonRole:
case CheckBoxRole:
case RadioButtonRole:
+ case SliderRole:
return true;
default:
return false;
@@ -2429,10 +2466,10 @@ bool AccessibilityRenderObject::canSetValueAttribute() const
if (equalIgnoringCase(getAttribute(aria_readonlyAttr).string(), "true"))
return false;
- if (isWebArea())
+ if (isWebArea() || isTextControl())
return !isReadOnly();
- return isTextControl() || isProgressIndicator() || isSlider();
+ return isProgressIndicator() || isSlider();
}
bool AccessibilityRenderObject::canSetTextRangeAttributes() const
@@ -2639,7 +2676,9 @@ void AccessibilityRenderObject::updateBackingStore()
{
if (!m_renderer)
return;
- m_renderer->view()->layoutIfNeeded();
-}
-
+
+ // Updating layout may delete m_renderer and this object.
+ m_renderer->document()->updateLayoutIgnorePendingStylesheets();
+}
+
} // namespace WebCore
diff --git a/WebCore/accessibility/AccessibilityRenderObject.h b/WebCore/accessibility/AccessibilityRenderObject.h
index 2b29f4a..d82ca71 100644
--- a/WebCore/accessibility/AccessibilityRenderObject.h
+++ b/WebCore/accessibility/AccessibilityRenderObject.h
@@ -133,6 +133,8 @@ public:
virtual void linkedUIElements(AccessibilityChildrenVector&) const;
virtual bool exposesTitleUIElement() const;
virtual AccessibilityObject* titleUIElement() const;
+ virtual AccessibilityObject* correspondingControlForLabelElement() const;
+
virtual AccessibilityRole ariaRoleAttribute() const;
virtual bool isPresentationalChildOfAriaRole() const;
virtual bool ariaRoleHasPresentationalChildren() const;
@@ -188,6 +190,9 @@ public:
virtual void setFocused(bool);
virtual void setSelectedTextRange(const PlainTextRange&);
virtual void setValue(const String&);
+ virtual void changeValueByPercent(float percentChange);
+ virtual void increment();
+ virtual void decrement();
virtual void detach();
virtual void childrenChanged();
diff --git a/WebCore/accessibility/AccessibilitySlider.cpp b/WebCore/accessibility/AccessibilitySlider.cpp
index e3a654b..5aca672 100644
--- a/WebCore/accessibility/AccessibilitySlider.cpp
+++ b/WebCore/accessibility/AccessibilitySlider.cpp
@@ -75,6 +75,7 @@ AccessibilityOrientation AccessibilitySlider::orientation() const
case SliderThumbVerticalPart:
case SliderVerticalPart:
+ case MediaVolumeSliderPart:
return AccessibilityOrientationVertical;
default:
@@ -113,15 +114,6 @@ float AccessibilitySlider::minValueForRange() const
return getAttribute(minAttr).toFloat();
}
-void AccessibilitySlider::changeValue(float percentChange)
-{
- float range = maxValueForRange() - minValueForRange();
- float value = valueForRange();
-
- value += range * (percentChange / 100);
- setValue(String::number(value));
-}
-
void AccessibilitySlider::setValue(const String& value)
{
HTMLInputElement* input = element();
@@ -135,16 +127,6 @@ void AccessibilitySlider::setValue(const String& value)
input->dispatchFormControlChangeEvent();
}
-void AccessibilitySlider::increment()
-{
- return changeValue(5);
-}
-
-void AccessibilitySlider::decrement()
-{
- return changeValue(-5);
-}
-
HTMLInputElement* AccessibilitySlider::element() const
{
return static_cast<HTMLInputElement*>(m_renderer->node());
diff --git a/WebCore/accessibility/AccessibilitySlider.h b/WebCore/accessibility/AccessibilitySlider.h
index eadab08..254ebdd 100644
--- a/WebCore/accessibility/AccessibilitySlider.h
+++ b/WebCore/accessibility/AccessibilitySlider.h
@@ -58,12 +58,10 @@ namespace WebCore {
virtual float minValueForRange() const;
virtual AccessibilityOrientation orientation() const;
- virtual void increment();
- virtual void decrement();
+ protected:
+ AccessibilitySlider(RenderObject*);
private:
- AccessibilitySlider(RenderObject*);
- void changeValue(float /*percentChange*/);
HTMLInputElement* element() const;
};
diff --git a/WebCore/accessibility/chromium/AXObjectCacheChromium.cpp b/WebCore/accessibility/chromium/AXObjectCacheChromium.cpp
index d0f1882..a97dfe2 100644
--- a/WebCore/accessibility/chromium/AXObjectCacheChromium.cpp
+++ b/WebCore/accessibility/chromium/AXObjectCacheChromium.cpp
@@ -43,11 +43,15 @@ void AXObjectCache::attachWrapper(AccessibilityObject*)
// In Chromium, AccessibilityObjects are wrapped lazily.
}
-void AXObjectCache::postPlatformNotification(AccessibilityObject*, const String&)
+void AXObjectCache::postPlatformNotification(AccessibilityObject*, AXNotification)
{
}
-void AXObjectCache::handleFocusedUIElementChanged()
+void AXObjectCache::handleFocusedUIElementChanged(RenderObject*, RenderObject*)
+{
+}
+
+void AXObjectCache::handleScrolledToAnchor(const Node*)
{
}
diff --git a/WebCore/accessibility/gtk/AXObjectCacheAtk.cpp b/WebCore/accessibility/gtk/AXObjectCacheAtk.cpp
index a04367f..cc515ad 100644
--- a/WebCore/accessibility/gtk/AXObjectCacheAtk.cpp
+++ b/WebCore/accessibility/gtk/AXObjectCacheAtk.cpp
@@ -37,20 +37,16 @@ void AXObjectCache::attachWrapper(AccessibilityObject* obj)
g_object_unref(atkObj);
}
-void AXObjectCache::postPlatformNotification(AccessibilityObject* coreObject, const String& message)
+void AXObjectCache::postPlatformNotification(AccessibilityObject* coreObject, AXNotification notification)
{
- if (message == "AXCheckedStateChanged") {
+ if (notification == AXCheckedStateChanged) {
if (!coreObject->isCheckboxOrRadio())
return;
g_signal_emit_by_name(coreObject->wrapper(), "state-change", "checked", coreObject->isChecked());
}
}
-
-void AXObjectCache::handleFocusedUIElementChanged()
-{
-}
-void AXObjectCache::handleFocusedUIElementChangedWithRenderers(RenderObject* oldFocusedRender, RenderObject* newFocusedRender)
+void AXObjectCache::handleFocusedUIElementChanged(RenderObject* oldFocusedRender, RenderObject* newFocusedRender)
{
RefPtr<AccessibilityObject> oldObject = getOrCreate(oldFocusedRender);
if (oldObject) {
@@ -64,4 +60,8 @@ void AXObjectCache::handleFocusedUIElementChangedWithRenderers(RenderObject* old
}
}
+void AXObjectCache::handleScrolledToAnchor(const Node*)
+{
+}
+
} // namespace WebCore
diff --git a/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp b/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp
index 6d3729b..811903d 100644
--- a/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp
+++ b/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp
@@ -60,7 +60,7 @@ using namespace WebCore;
static AccessibilityObject* fallbackObject()
{
- static AXObjectCache* fallbackCache = new AXObjectCache();
+ static AXObjectCache* fallbackCache = new AXObjectCache;
static AccessibilityObject* object = 0;
if (!object) {
// FIXME: using fallbackCache->getOrCreate(ListBoxOptionRole) is a hack
@@ -556,7 +556,7 @@ static PangoLayout* getPangoLayoutForAtk(AtkText* textObject)
HostWindow* hostWindow = coreObject->document()->view()->hostWindow();
if (!hostWindow)
return 0;
- PlatformWidget webView = hostWindow->platformWindow();
+ PlatformPageClient webView = hostWindow->platformPageClient();
if (!webView)
return 0;
diff --git a/WebCore/accessibility/mac/AXObjectCacheMac.mm b/WebCore/accessibility/mac/AXObjectCacheMac.mm
index be7968b..2f18cf3 100644
--- a/WebCore/accessibility/mac/AXObjectCacheMac.mm
+++ b/WebCore/accessibility/mac/AXObjectCacheMac.mm
@@ -51,19 +51,51 @@ void AXObjectCache::attachWrapper(AccessibilityObject* obj)
obj->setWrapper([[AccessibilityObjectWrapper alloc] initWithAccessibilityObject:obj]);
}
-void AXObjectCache::postPlatformNotification(AccessibilityObject* obj, const String& message)
+void AXObjectCache::postPlatformNotification(AccessibilityObject* obj, AXNotification notification)
{
if (!obj)
return;
- NSAccessibilityPostNotification(obj->wrapper(), message);
+ // Some notifications are unique to Safari and do not have NSAccessibility equivalents.
+ String macNotification;
+ switch (notification) {
+ case AXCheckedStateChanged:
+ macNotification = "AXCheckedStateChanged";
+ break;
+ case AXFocusedUIElementChanged:
+ macNotification = NSAccessibilityFocusedUIElementChangedNotification;
+ break;
+ case AXLayoutComplete:
+ macNotification = "AXLayoutComplete";
+ break;
+ case AXLoadComplete:
+ macNotification = "AXLoadComplete";
+ break;
+ case AXSelectedChildrenChanged:
+ macNotification = NSAccessibilitySelectedChildrenChangedNotification;
+ break;
+ case AXSelectedTextChanged:
+ macNotification = NSAccessibilitySelectedTextChangedNotification;
+ break;
+ case AXValueChanged:
+ macNotification = NSAccessibilityValueChangedNotification;
+ break;
+ default:
+ return;
+ }
+
+ NSAccessibilityPostNotification(obj->wrapper(), macNotification);
}
-void AXObjectCache::handleFocusedUIElementChanged()
+void AXObjectCache::handleFocusedUIElementChanged(RenderObject*, RenderObject*)
{
[[WebCoreViewFactory sharedFactory] accessibilityHandleFocusChanged];
}
+void AXObjectCache::handleScrolledToAnchor(const Node*)
+{
+}
+
}
#endif // HAVE(ACCESSIBILITY)
diff --git a/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm b/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm
index d1e0599..e56e77c 100644
--- a/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm
+++ b/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -122,6 +122,7 @@ using namespace std;
#ifdef BUILDING_ON_TIGER
typedef unsigned NSUInteger;
#define NSAccessibilityValueDescriptionAttribute @"AXValueDescription"
+#define NSAccessibilityTimelineSubrole @"AXTimeline"
#endif
@interface NSObject (WebKitAccessibilityArrayCategory)
@@ -378,7 +379,7 @@ static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString,
// add misspelling attribute for the intersection of the marker and the range
int rStart = range.location + (marker.startOffset - offset);
- int rLength = MIN(marker.endOffset, endOffset) - marker.startOffset;
+ int rLength = min(marker.endOffset, endOffset) - marker.startOffset;
NSRange spellRange = NSMakeRange(rStart, rLength);
AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange);
@@ -478,6 +479,9 @@ static NSString* nsStringForReplacedNode(Node* replacedNode)
- (NSAttributedString*)doAXAttributedStringForTextMarkerRange:(WebCoreTextMarkerRange*)textMarkerRange
{
+ if (!m_object)
+ return nil;
+
// extract the start and end VisiblePosition
VisiblePosition startVisiblePosition = visiblePositionForStartOfTextMarkerRange(textMarkerRange);
if (startVisiblePosition.isNull())
@@ -487,6 +491,7 @@ static NSString* nsStringForReplacedNode(Node* replacedNode)
if (endVisiblePosition.isNull())
return nil;
+ VisiblePositionRange visiblePositionRange(startVisiblePosition, endVisiblePosition);
// iterate over the range to build the AX attributed string
NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init];
TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get());
@@ -499,6 +504,11 @@ static NSString* nsStringForReplacedNode(Node* replacedNode)
// non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
if (it.length() != 0) {
+ // Add the text of the list marker item if necessary.
+ String listMarkerText = m_object->listMarkerTextForNodeAndPosition(node, VisiblePosition(it.range()->startPosition()));
+ if (!listMarkerText.isEmpty())
+ AXAttributedStringAppendText(attrString, node, offset, listMarkerText.characters(), listMarkerText.length());
+
AXAttributedStringAppendText(attrString, node, offset, it.characters(), it.length());
} else {
Node* replacedNode = node->childNode(offset);
@@ -536,6 +546,8 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi
return nil;
m_object->updateBackingStore();
+ if (!m_object)
+ return nil;
static NSArray* actionElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityPressAction, NSAccessibilityShowMenuAction, nil];
static NSArray* defaultElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityShowMenuAction, nil];
@@ -563,6 +575,8 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi
return nil;
m_object->updateBackingStore();
+ if (!m_object)
+ return nil;
if (m_object->isAttachment())
return [[self attachmentView] accessibilityAttributeNames];
@@ -669,6 +683,7 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi
[tempArray addObject:NSAccessibilityMinValueAttribute];
[tempArray addObject:NSAccessibilityMaxValueAttribute];
[tempArray addObject:NSAccessibilityOrientationAttribute];
+ [tempArray addObject:NSAccessibilityValueDescriptionAttribute];
rangeAttrs = [[NSArray alloc] initWithArray:tempArray];
[tempArray release];
}
@@ -969,8 +984,23 @@ static const AccessibilityRoleMap& createAccessibilityRoleMap()
{ TableHeaderContainerRole, NSAccessibilityGroupRole },
{ DefinitionListDefinitionRole, NSAccessibilityGroupRole },
{ DefinitionListTermRole, NSAccessibilityGroupRole },
-
{ SliderThumbRole, NSAccessibilityValueIndicatorRole },
+ { LandmarkApplicationRole, NSAccessibilityGroupRole },
+ { LandmarkBannerRole, NSAccessibilityGroupRole },
+ { LandmarkComplementaryRole, NSAccessibilityGroupRole },
+ { LandmarkContentInfoRole, NSAccessibilityGroupRole },
+ { LandmarkMainRole, NSAccessibilityGroupRole },
+ { LandmarkNavigationRole, NSAccessibilityGroupRole },
+ { LandmarkSearchRole, NSAccessibilityGroupRole },
+ { ApplicationLogRole, NSAccessibilityGroupRole },
+ { ApplicationMarqueeRole, NSAccessibilityGroupRole },
+ { ApplicationStatusRole, NSAccessibilityGroupRole },
+ { ApplicationTimerRole, NSAccessibilityGroupRole },
+ { DocumentRole, NSAccessibilityGroupRole },
+ { DocumentArticleRole, NSAccessibilityGroupRole },
+ { DocumentNoteRole, NSAccessibilityGroupRole },
+ { DocumentRegionRole, NSAccessibilityGroupRole },
+ { UserInterfaceTooltipRole, NSAccessibilityGroupRole },
};
@@ -1019,6 +1049,47 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return NSAccessibilityDefinitionListSubrole;
}
+ // ARIA content subroles.
+ switch (m_object->roleValue()) {
+ case LandmarkApplicationRole:
+ return @"AXLandmarkApplication";
+ case LandmarkBannerRole:
+ return @"AXLandmarkBanner";
+ case LandmarkComplementaryRole:
+ return @"AXLandmarkComplementary";
+ case LandmarkContentInfoRole:
+ return @"AXLandmarkContentInfo";
+ case LandmarkMainRole:
+ return @"AXLandmarkMain";
+ case LandmarkNavigationRole:
+ return @"AXLandmarkNavigation";
+ case LandmarkSearchRole:
+ return @"AXLandmarkSearch";
+ case ApplicationLogRole:
+ return @"AXApplicationLog";
+ case ApplicationMarqueeRole:
+ return @"AXApplicationMarquee";
+ case ApplicationStatusRole:
+ return @"AXApplicationStatus";
+ case ApplicationTimerRole:
+ return @"AXApplicationTimer";
+ case DocumentRole:
+ return @"AXDocument";
+ case DocumentArticleRole:
+ return @"AXDocumentArticle";
+ case DocumentNoteRole:
+ return @"AXDocumentNote";
+ case DocumentRegionRole:
+ return @"AXDocumentRegion";
+ case UserInterfaceTooltipRole:
+ return @"AXUserInterfaceTooltip";
+ default:
+ return nil;
+ }
+
+ if (m_object->isMediaTimeline())
+ return NSAccessibilityTimelineSubrole;
+
return nil;
}
@@ -1047,8 +1118,44 @@ static NSString* roleValueToNSString(AccessibilityRole value)
if ([axRole isEqualToString:NSAccessibilityImageRole])
return NSAccessibilityRoleDescription(NSAccessibilityImageRole, [self subrole]);
- if ([axRole isEqualToString:NSAccessibilityGroupRole])
- return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, [self subrole]);
+ if ([axRole isEqualToString:NSAccessibilityGroupRole]) {
+ switch (m_object->roleValue()) {
+ default:
+ return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, [self subrole]);
+ case LandmarkApplicationRole:
+ return AXARIAContentGroupText(@"ARIALandmarkApplication");
+ case LandmarkBannerRole:
+ return AXARIAContentGroupText(@"ARIALandmarkBanner");
+ case LandmarkComplementaryRole:
+ return AXARIAContentGroupText(@"ARIALandmarkComplementary");
+ case LandmarkContentInfoRole:
+ return AXARIAContentGroupText(@"ARIALandmarkContentInfo");
+ case LandmarkMainRole:
+ return AXARIAContentGroupText(@"ARIALandmarkMain");
+ case LandmarkNavigationRole:
+ return AXARIAContentGroupText(@"ARIALandmarkNavigation");
+ case LandmarkSearchRole:
+ return AXARIAContentGroupText(@"ARIALandmarkSearch");
+ case ApplicationLogRole:
+ return AXARIAContentGroupText(@"ARIAApplicationLog");
+ case ApplicationMarqueeRole:
+ return AXARIAContentGroupText(@"ARIAApplicationMarquee");
+ case ApplicationStatusRole:
+ return AXARIAContentGroupText(@"ARIAApplicationStatus");
+ case ApplicationTimerRole:
+ return AXARIAContentGroupText(@"ARIAApplicationTimer");
+ case DocumentRole:
+ return AXARIAContentGroupText(@"ARIADocument");
+ case DocumentArticleRole:
+ return AXARIAContentGroupText(@"ARIADocumentArticle");
+ case DocumentNoteRole:
+ return AXARIAContentGroupText(@"ARIADocumentNote");
+ case DocumentRegionRole:
+ return AXARIAContentGroupText(@"ARIADocumentRegion");
+ case UserInterfaceTooltipRole:
+ return AXARIAContentGroupText(@"ARIAUserInterfaceTooltip");
+ }
+ }
if ([axRole isEqualToString:NSAccessibilityCheckBoxRole])
return NSAccessibilityRoleDescription(NSAccessibilityCheckBoxRole, [self subrole]);
@@ -1111,6 +1218,9 @@ static NSString* roleValueToNSString(AccessibilityRole value)
if ([axRole isEqualToString:NSAccessibilityToolbarRole])
return NSAccessibilityRoleDescription(NSAccessibilityToolbarRole, [self subrole]);
+ if ([axRole isEqualToString:NSAccessibilitySplitterRole])
+ return NSAccessibilityRoleDescription(NSAccessibilitySplitterRole, [self subrole]);
+
return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nil);
}
@@ -1123,6 +1233,8 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return nil;
m_object->updateBackingStore();
+ if (!m_object)
+ return nil;
if ([attributeName isEqualToString: NSAccessibilityRoleAttribute])
return [self role];
@@ -1244,7 +1356,7 @@ static NSString* roleValueToNSString(AccessibilityRole value)
}
return m_object->accessibilityDescription();
}
-
+
if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
if (m_object->isAttachment()) {
if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute])
@@ -1465,6 +1577,8 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return nil;
m_object->updateBackingStore();
+ if (!m_object)
+ return nil;
RefPtr<AccessibilityObject> focusedObj = m_object->focusedUIElement();
@@ -1480,6 +1594,8 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return nil;
m_object->updateBackingStore();
+ if (!m_object)
+ return nil;
RefPtr<AccessibilityObject> axObject = m_object->doAccessibilityHitTest(IntPoint(point));
if (axObject)
@@ -1493,6 +1609,8 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return nil;
m_object->updateBackingStore();
+ if (!m_object)
+ return nil;
if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
return YES;
@@ -1532,6 +1650,8 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return nil;
m_object->updateBackingStore();
+ if (!m_object)
+ return nil;
if (m_object->isAttachment())
return [[self attachmentView] accessibilityIsIgnored];
@@ -1544,6 +1664,8 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return nil;
m_object->updateBackingStore();
+ if (!m_object)
+ return nil;
if (m_object->isAttachment())
return nil;
@@ -1581,6 +1703,7 @@ static NSString* roleValueToNSString(AccessibilityRole value)
@"AXStyleTextMarkerRangeForTextMarker",
@"AXLengthForTextMarkerRange",
NSAccessibilityBoundsForRangeParameterizedAttribute,
+ NSAccessibilityStringForRangeParameterizedAttribute,
nil];
}
@@ -1629,6 +1752,8 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return;
m_object->updateBackingStore();
+ if (!m_object)
+ return;
if (m_object->isAttachment())
[[self attachmentView] accessibilityPerformAction:NSAccessibilityPressAction];
@@ -1642,6 +1767,8 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return;
m_object->updateBackingStore();
+ if (!m_object)
+ return;
if (m_object->isAttachment())
[[self attachmentView] accessibilityPerformAction:NSAccessibilityIncrementAction];
@@ -1655,6 +1782,8 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return;
m_object->updateBackingStore();
+ if (!m_object)
+ return;
if (m_object->isAttachment())
[[self attachmentView] accessibilityPerformAction:NSAccessibilityDecrementAction];
@@ -1704,6 +1833,8 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return;
m_object->updateBackingStore();
+ if (!m_object)
+ return;
if ([action isEqualToString:NSAccessibilityPressAction])
[self accessibilityPerformPressAction];
@@ -1724,6 +1855,8 @@ static NSString* roleValueToNSString(AccessibilityRole value)
return;
m_object->updateBackingStore();
+ if (!m_object)
+ return;
WebCoreTextMarkerRange* textMarkerRange = nil;
NSNumber* number = nil;
@@ -1848,6 +1981,8 @@ static RenderObject* rendererForView(NSView* view)
return nil;
m_object->updateBackingStore();
+ if (!m_object)
+ return nil;
// common parameter type check/casting. Nil checks in handlers catch wrong type case.
// NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from
@@ -1932,6 +2067,14 @@ static RenderObject* rendererForView(NSView* view)
NSRect rect = m_object->boundsForVisiblePositionRange(VisiblePositionRange(start, end));
return [NSValue valueWithRect:rect];
}
+
+ if ([attribute isEqualToString:NSAccessibilityStringForRangeParameterizedAttribute]) {
+ VisiblePosition start = m_object->visiblePositionForIndex(range.location);
+ VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length);
+ if (start.isNull() || end.isNull())
+ return nil;
+ return m_object->stringForVisiblePositionRange(VisiblePositionRange(start, end));
+ }
if ([attribute isEqualToString: @"AXAttributedStringForTextMarkerRange"])
return [self doAXAttributedStringForTextMarkerRange:textMarkerRange];
@@ -2098,7 +2241,9 @@ static RenderObject* rendererForView(NSView* view)
return NSNotFound;
m_object->updateBackingStore();
-
+ if (!m_object)
+ return NSNotFound;
+
const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
if (children.isEmpty())
@@ -2120,6 +2265,8 @@ static RenderObject* rendererForView(NSView* view)
return 0;
m_object->updateBackingStore();
+ if (!m_object)
+ return 0;
if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
@@ -2138,6 +2285,8 @@ static RenderObject* rendererForView(NSView* view)
return nil;
m_object->updateBackingStore();
+ if (!m_object)
+ return nil;
if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
if (m_object->children().isEmpty()) {
diff --git a/WebCore/accessibility/win/AXObjectCacheWin.cpp b/WebCore/accessibility/win/AXObjectCacheWin.cpp
index e39d5a5..a1bdcc0 100644
--- a/WebCore/accessibility/win/AXObjectCacheWin.cpp
+++ b/WebCore/accessibility/win/AXObjectCacheWin.cpp
@@ -28,6 +28,11 @@
#include "AXObjectCache.h"
#include "AccessibilityObject.h"
+#include "Document.h"
+#include "Page.h"
+#include "RenderObject.h"
+
+using namespace std;
namespace WebCore {
@@ -46,12 +51,86 @@ void AXObjectCache::attachWrapper(AccessibilityObject*)
// software requests them via get_accChild.
}
-void AXObjectCache::postPlatformNotification(AccessibilityObject*, const String&)
+void AXObjectCache::handleScrolledToAnchor(const Node* anchorNode)
+{
+ // The anchor node may not be accessible. Post the notification for the
+ // first accessible object.
+ postPlatformNotification(AccessibilityObject::firstAccessibleObjectFromNode(anchorNode), AXScrolledToAnchor);
+}
+
+void AXObjectCache::postPlatformNotification(AccessibilityObject* obj, AXNotification notification)
{
+ if (!obj)
+ return;
+
+ Document* document = obj->document();
+ if (!document)
+ return;
+
+ Page* page = document->page();
+ if (!page || !page->chrome()->platformPageClient())
+ return;
+
+ DWORD msaaEvent;
+ switch (notification) {
+ case AXFocusedUIElementChanged:
+ msaaEvent = EVENT_OBJECT_FOCUS;
+ break;
+
+ case AXScrolledToAnchor:
+ msaaEvent = EVENT_SYSTEM_SCROLLINGSTART;
+ break;
+
+ default:
+ return;
+ }
+
+ // Windows will end up calling get_accChild() on the root accessible
+ // object for the WebView, passing the child ID that we specify below. We
+ // negate the AXID so we know that the caller is passing the ID of an
+ // element, not the index of a child element.
+
+ ASSERT(obj->axObjectID() >= 1);
+ ASSERT(obj->axObjectID() <= numeric_limits<LONG>::max());
+
+ NotifyWinEvent(msaaEvent, page->chrome()->platformPageClient(), OBJID_CLIENT, -static_cast<LONG>(obj->axObjectID()));
}
-void AXObjectCache::handleFocusedUIElementChanged()
+AXID AXObjectCache::platformGenerateAXID() const
{
+ static AXID lastUsedID = 0;
+
+ // Generate a new ID. Windows accessibility relies on a positive AXID,
+ // ranging from 1 to LONG_MAX.
+ AXID objID = lastUsedID;
+ do {
+ ++objID;
+ objID %= std::numeric_limits<LONG>::max();
+ } while (objID == 0 || HashTraits<AXID>::isDeletedValue(objID) || m_idsInUse.contains(objID));
+
+ ASSERT(objID >= 1 && objID <= std::numeric_limits<LONG>::max());
+
+ lastUsedID = objID;
+
+ return objID;
+}
+
+void AXObjectCache::handleFocusedUIElementChanged(RenderObject*, RenderObject* newFocusedRenderer)
+{
+ if (!newFocusedRenderer)
+ return;
+
+ Page* page = newFocusedRenderer->document()->page();
+ if (!page || !page->chrome()->platformPageClient())
+ return;
+
+ AccessibilityObject* focusedObject = focusedUIElementForPage(page);
+ if (!focusedObject)
+ return;
+
+ ASSERT(!focusedObject->accessibilityIsIgnored());
+
+ postPlatformNotification(focusedObject, AXFocusedUIElementChanged);
}
} // namespace WebCore