diff options
Diffstat (limited to 'WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm')
-rw-r--r-- | WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm | 162 |
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; } |