summaryrefslogtreecommitdiffstats
path: root/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm
diff options
context:
space:
mode:
Diffstat (limited to 'WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm')
-rw-r--r--WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm162
1 files changed, 124 insertions, 38 deletions
diff --git a/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm b/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm
index e9361f2..a39dabb 100644
--- a/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm
+++ b/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm
@@ -57,32 +57,11 @@ typedef void (*AXPostedNotificationCallback)(id element, NSString* notification,
@interface NSObject (WebKitAccessibilityAdditions)
- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount;
-- (void)accessibilitySetPostedNotificationCallback:(AXPostedNotificationCallback)function withContext:(void*)context;
+- (void)accessibilitySetShouldRepostNotifications:(BOOL)repost;
- (NSUInteger)accessibilityIndexOfChild:(id)child;
+- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute;
@end
-AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element)
- : m_element(element)
- , m_notificationFunctionCallback(0)
-{
- [m_element retain];
-}
-
-AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other)
- : m_element(other.m_element)
- , m_notificationFunctionCallback(0)
-{
- [m_element retain];
-}
-
-AccessibilityUIElement::~AccessibilityUIElement()
-{
- // Make sure that our notification callback does not stick around.
- if (m_notificationFunctionCallback)
- [m_element accessibilitySetPostedNotificationCallback:0 withContext:0];
- [m_element release];
-}
-
@interface NSString (JSStringRefAdditions)
+ (NSString *)stringWithJSStringRef:(JSStringRef)jsStringRef;
- (JSStringRef)createJSStringRef;
@@ -106,6 +85,88 @@ AccessibilityUIElement::~AccessibilityUIElement()
@end
+@interface AccessibilityNotificationHandler : NSObject
+{
+ id m_platformElement;
+ JSObjectRef m_notificationFunctionCallback;
+}
+
+@end
+
+@implementation AccessibilityNotificationHandler
+
+- (id)initWithPlatformElement:(id)platformElement
+{
+ self = [super init];
+
+ m_platformElement = platformElement;
+
+ // Once an object starts requesting notifications, it's on for the duration of the program.
+ // This is to avoid any race conditions between tests turning this flag on and off. Instead
+ // AccessibilityNotificationHandler can just listen when they want to.
+ [m_platformElement accessibilitySetShouldRepostNotifications:YES];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_notificationReceived:) name:@"AXDRTNotification" object:nil];
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ JSValueUnprotect([mainFrame globalContext], m_notificationFunctionCallback);
+ m_notificationFunctionCallback = 0;
+
+ [super dealloc];
+}
+
+- (void)_notificationReceived:(NSNotification *)notification
+{
+ NSString *notificationName = [[notification userInfo] objectForKey:@"notificationName"];
+ if (!notificationName)
+ return;
+
+ JSRetainPtr<JSStringRef> jsNotification(Adopt, [notificationName createJSStringRef]);
+ JSValueRef argument = JSValueMakeString([mainFrame globalContext], jsNotification.get());
+ JSObjectCallAsFunction([mainFrame globalContext], m_notificationFunctionCallback, 0, 1, &argument, 0);
+}
+
+- (void)setCallback:(JSObjectRef)callback
+{
+ if (!callback)
+ return;
+
+ // Release the old callback.
+ if (m_notificationFunctionCallback)
+ JSValueUnprotect([mainFrame globalContext], m_notificationFunctionCallback);
+
+ m_notificationFunctionCallback = callback;
+ JSValueProtect([mainFrame globalContext], m_notificationFunctionCallback);
+}
+
+@end
+
+AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element)
+ : m_element(element)
+ , m_notificationHandler(0)
+{
+ // FIXME: ap@webkit.org says ObjC objects need to be CFRetained/CFRelease to be GC-compliant on the mac.
+ [m_element retain];
+}
+
+AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other)
+ : m_element(other.m_element)
+ , m_notificationHandler(0)
+{
+ [m_element retain];
+}
+
+AccessibilityUIElement::~AccessibilityUIElement()
+{
+ // The notification handler should be nil because removeNotificationListener() should have been called in the test.
+ ASSERT(!m_notificationHandler);
+ [m_element release];
+}
+
static NSString* descriptionOfValue(id valueObject, id focusedAccessibilityObject)
{
if (!valueObject)
@@ -439,6 +500,12 @@ JSStringRef AccessibilityUIElement::language()
return concatenateAttributeAndValue(@"AXLanguage", description);
}
+JSStringRef AccessibilityUIElement::helpText() const
+{
+ id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityHelpAttribute], m_element);
+ return concatenateAttributeAndValue(@"AXHelp", description);
+}
+
double AccessibilityUIElement::x()
{
NSValue* positionValue = [m_element accessibilityAttributeValue:NSAccessibilityPositionAttribute];
@@ -676,6 +743,16 @@ JSStringRef AccessibilityUIElement::attributesOfHeader()
return descriptionOfElements(headerVector);
}
+int AccessibilityUIElement::rowCount()
+{
+ return [m_element accessibilityArrayAttributeCount:NSAccessibilityRowsAttribute];
+}
+
+int AccessibilityUIElement::columnCount()
+{
+ return [m_element accessibilityArrayAttributeCount:NSAccessibilityColumnsAttribute];
+}
+
int AccessibilityUIElement::indexInTable()
{
NSNumber* indexNumber = [m_element accessibilityAttributeValue:NSAccessibilityIndexAttribute];
@@ -736,6 +813,11 @@ void AccessibilityUIElement::showMenu()
[m_element accessibilityPerformAction:NSAccessibilityShowMenuAction];
}
+void AccessibilityUIElement::press()
+{
+ [m_element accessibilityPerformAction:NSAccessibilityPressAction];
+}
+
JSStringRef AccessibilityUIElement::accessibilityValue() const
{
// FIXME: implement
@@ -758,28 +840,30 @@ JSStringRef AccessibilityUIElement::url()
return [[url absoluteString] createJSStringRef];
}
-static void _accessibilityNotificationCallback(id element, NSString* notification, void* context)
-{
- if (!context)
- return;
-
- JSObjectRef functionCallback = static_cast<JSObjectRef>(context);
-
- JSRetainPtr<JSStringRef> jsNotification(Adopt, [notification createJSStringRef]);
- JSValueRef argument = JSValueMakeString([mainFrame globalContext], jsNotification.get());
- JSObjectCallAsFunction([mainFrame globalContext], functionCallback, NULL, 1, &argument, NULL);
-}
-
bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback)
{
if (!functionCallback)
return false;
- m_notificationFunctionCallback = functionCallback;
- [platformUIElement() accessibilitySetPostedNotificationCallback:_accessibilityNotificationCallback withContext:reinterpret_cast<void*>(m_notificationFunctionCallback)];
+ // Mac programmers should not be adding more than one notification listener per element.
+ // Other platforms may be different.
+ if (m_notificationHandler)
+ return false;
+ m_notificationHandler = [[AccessibilityNotificationHandler alloc] initWithPlatformElement:platformUIElement()];
+ [m_notificationHandler setCallback:functionCallback];
+
return true;
}
+void AccessibilityUIElement::removeNotificationListener()
+{
+ // Mac programmers should not be trying to remove a listener that's already removed.
+ ASSERT(m_notificationHandler);
+
+ [m_notificationHandler release];
+ m_notificationHandler = nil;
+}
+
bool AccessibilityUIElement::isSelectable() const
{
// FIXME: implement
@@ -812,7 +896,9 @@ bool AccessibilityUIElement::isCollapsed() const
bool AccessibilityUIElement::hasPopup() const
{
- // FIXME: implement
+ id value = [m_element accessibilityAttributeValue:@"AXHasPopup"];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [value boolValue];
return false;
}