aria-liveregion-notifications.html fails on leopard release bot
authorcfleizach@apple.com <cfleizach@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Apr 2010 00:25:32 +0000 (00:25 +0000)
committercfleizach@apple.com <cfleizach@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Apr 2010 00:25:32 +0000 (00:25 +0000)
https://bugs.webkit.org/show_bug.cgi?id=37112

Reviewed by Alexey Proskuryakov.

WebCore:

Change the method that DRT uses to monitor AX notifications so that its robust
by just sending out NSNotification that can be listened to by anyone, instead
of keeping a static function pointer around.

This change is aimed to avoid flakiness seen in DRT when the notification handlers
are not being called at the appropriate time.

Tests: platform/mac/accessibility/aria-liveregions-addedelement.html
       platform/mac/accessibility/aria-liveregions-changedalt.html
       platform/mac/accessibility/aria-liveregions-changedtext.html
       platform/mac/accessibility/aria-liveregions-removedelement.html

* accessibility/mac/AccessibilityObjectWrapper.h:
* accessibility/mac/AccessibilityObjectWrapper.mm:
(-[AccessibilityObjectWrapper accessibilitySetShouldRepostNotifications:]):
(-[AccessibilityObjectWrapper accessibilityPostedNotification:]):

WebKitTools:

Change the way that notifications are listened for by forcing clients
to call a remove listener as well to match the add listener. DRT will
assert if those are not done in the correct order.

* DumpRenderTree/AccessibilityUIElement.cpp:
(removeNotificationListenerCallback):
(AccessibilityUIElement::getJSClass):
* DumpRenderTree/AccessibilityUIElement.h:
* DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
(AccessibilityUIElement::removeNotificationListener):
* DumpRenderTree/mac/AccessibilityUIElementMac.mm:
(-[AccessibilityNotificationHandler initWithPlatformElement:]):
(-[AccessibilityNotificationHandler dealloc]):
(-[AccessibilityNotificationHandler _notificationReceived:]):
(-[AccessibilityNotificationHandler setCallback:]):
(AccessibilityUIElement::AccessibilityUIElement):
(AccessibilityUIElement::~AccessibilityUIElement):
(AccessibilityUIElement::addNotificationListener):
(AccessibilityUIElement::removeNotificationListener):
* DumpRenderTree/win/AccessibilityUIElementWin.cpp:
(AccessibilityUIElement::removeNotificationListener):

LayoutTests:

Add four more tests that test specific live region functionality. Having these
four tests run in order seems to stress the notification mechanism and will expose issues
more frequently.
Modify tests that use notification listeners to also "removeNotificationListener".

* platform/mac-leopard/Skipped:
* platform/mac/accessibility/aria-listbox-selectedchildren-change.html:
* platform/mac/accessibility/aria-liveregion-on-image.html:
* platform/mac/accessibility/aria-liveregions-addedelement-expected.txt: Added.
* platform/mac/accessibility/aria-liveregions-addedelement.html: Added.
* platform/mac/accessibility/aria-liveregions-changedalt-expected.txt: Added.
* platform/mac/accessibility/aria-liveregions-changedalt.html: Added.
* platform/mac/accessibility/aria-liveregions-changedtext-expected.txt: Added.
* platform/mac/accessibility/aria-liveregions-changedtext.html: Added.
* platform/mac/accessibility/aria-liveregions-notifications.html:
* platform/mac/accessibility/aria-liveregions-removedelement-expected.txt: Added.
* platform/mac/accessibility/aria-liveregions-removedelement.html: Added.
* platform/mac/accessibility/change-notification-on-scroll.html:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@58031 268f45cc-cd09-0410-ab3c-d52691b4dbfc

23 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/mac-leopard/Skipped
LayoutTests/platform/mac/accessibility/aria-listbox-selectedchildren-change.html
LayoutTests/platform/mac/accessibility/aria-liveregion-on-image.html
LayoutTests/platform/mac/accessibility/aria-liveregions-addedelement-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/accessibility/aria-liveregions-addedelement.html [new file with mode: 0644]
LayoutTests/platform/mac/accessibility/aria-liveregions-changedalt-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/accessibility/aria-liveregions-changedalt.html [new file with mode: 0644]
LayoutTests/platform/mac/accessibility/aria-liveregions-changedtext-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/accessibility/aria-liveregions-changedtext.html [new file with mode: 0644]
LayoutTests/platform/mac/accessibility/aria-liveregions-notifications.html
LayoutTests/platform/mac/accessibility/aria-liveregions-removedelement-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/accessibility/aria-liveregions-removedelement.html [new file with mode: 0644]
LayoutTests/platform/mac/accessibility/change-notification-on-scroll.html
WebCore/ChangeLog
WebCore/accessibility/mac/AccessibilityObjectWrapper.h
WebCore/accessibility/mac/AccessibilityObjectWrapper.mm
WebKitTools/ChangeLog
WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp
WebKitTools/DumpRenderTree/AccessibilityUIElement.h
WebKitTools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp
WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm
WebKitTools/DumpRenderTree/win/AccessibilityUIElementWin.cpp

index 8d05513..afead91 100644 (file)
@@ -1,3 +1,29 @@
+2010-04-21  Chris Fleizach  <cfleizach@apple.com>
+
+        Reviewed by Alexey Proskuryakov.
+
+        aria-liveregion-notifications.html fails on leopard release bot
+        https://bugs.webkit.org/show_bug.cgi?id=37112
+
+        Add four more tests that test specific live region functionality. Having these
+        four tests run in order seems to stress the notification mechanism and will expose issues 
+        more frequently.
+        Modify tests that use notification listeners to also "removeNotificationListener".
+
+        * platform/mac-leopard/Skipped:
+        * platform/mac/accessibility/aria-listbox-selectedchildren-change.html:
+        * platform/mac/accessibility/aria-liveregion-on-image.html:
+        * platform/mac/accessibility/aria-liveregions-addedelement-expected.txt: Added.
+        * platform/mac/accessibility/aria-liveregions-addedelement.html: Added.
+        * platform/mac/accessibility/aria-liveregions-changedalt-expected.txt: Added.
+        * platform/mac/accessibility/aria-liveregions-changedalt.html: Added.
+        * platform/mac/accessibility/aria-liveregions-changedtext-expected.txt: Added.
+        * platform/mac/accessibility/aria-liveregions-changedtext.html: Added.
+        * platform/mac/accessibility/aria-liveregions-notifications.html:
+        * platform/mac/accessibility/aria-liveregions-removedelement-expected.txt: Added.
+        * platform/mac/accessibility/aria-liveregions-removedelement.html: Added.
+        * platform/mac/accessibility/change-notification-on-scroll.html:
+
 2010-04-21  John Gregg  <johnnyg@google.com>
 
         Reviewed by David Levin.
index 2f6a92b..e73b7ca 100644 (file)
@@ -9,8 +9,6 @@ svg/css/glyph-orientation-rounding-test.xhtml
 platform/mac/accessibility/table-multi-bodies.html
 # Lists are not supported on Leopard.
 platform/mac/accessibility/aria-directory.html
-# https://bugs.webkit.org/show_bug.cgi?id=37112 Live regions fails on leopard release bot.
-platform/mac/accessibility/aria-liveregions-notifications.html
 
 # Tests of font features not supported by ATSUI
 platform/mac/fast/text/myanmar-shaping.html
index fea68ca..649fb99 100644 (file)
@@ -22,6 +22,7 @@ var successfullyParsed = false;
 
     description("This tests that when aria-selected is changed in a listbox, the correct notification is sent.");
 
+    var listbox = 0;
     var notificationCount = 0;
     function ariaCallback(notification) {
         if (notification == "AXSelectedChildrenChanged") {
@@ -29,6 +30,7 @@ var successfullyParsed = false;
 
             // We should get a total of 4 live region changes.
             if (notificationCount == 2) {
+               listbox.removeNotificationListener();
                window.layoutTestController.notifyDone();
             }
         }
@@ -38,7 +40,7 @@ var successfullyParsed = false;
         window.layoutTestController.waitUntilDone();
 
         document.getElementById("listbox").focus();
-        var listbox = window.accessibilityController.focusedElement;
+        listbox = window.accessibilityController.focusedElement;
 
         var addedNotification = listbox.addNotificationListener(ariaCallback);
         shouldBe("addedNotification", "true");
index 7c57c6a..44fac75 100644 (file)
@@ -18,8 +18,10 @@ var successfullyParsed = false;
 
     description("This tests that ARIA live regions that is on an image will work when the alt tag is changed.");
 
+    var image = 0;
     function ariaCallback(notification) {
         if (notification == "AXLiveRegionChanged") {
+            image.removeNotificationListener();
             window.layoutTestController.notifyDone();
         }
     }
@@ -28,7 +30,7 @@ var successfullyParsed = false;
         window.layoutTestController.waitUntilDone();
 
         document.getElementById("image").focus();
-        var image = window.accessibilityController.focusedElement;
+        image = window.accessibilityController.focusedElement;
 
         var addedNotification = image.addNotificationListener(ariaCallback);
         shouldBe("addedNotification", "true");
diff --git a/LayoutTests/platform/mac/accessibility/aria-liveregions-addedelement-expected.txt b/LayoutTests/platform/mac/accessibility/aria-liveregions-addedelement-expected.txt
new file mode 100644 (file)
index 0000000..51ab032
--- /dev/null
@@ -0,0 +1,14 @@
+ALERT: Successfully received AXLiveRegionChanged
+text
+
+hellonew text element
+This tests that adding an element to a live region will trigger the right notification.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS addedNotification is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/mac/accessibility/aria-liveregions-addedelement.html b/LayoutTests/platform/mac/accessibility/aria-liveregions-addedelement.html
new file mode 100644 (file)
index 0000000..22eb5fa
--- /dev/null
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../../../fast/js/resources/js-test-style.css">
+<script>
+var successfullyParsed = false;
+</script>
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body id="body">
+
+<div role="group" tabindex=0 id="liveregion" aria-live="polite" aria-relevant="additions">
+<h3 id="innerlive">text</h3>
+<div id="addregion">hello</div>
+</div>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+
+    description("This tests that adding an element to a live region will trigger the right notification.");
+
+    var liveRegion = 0;
+    function ariaCallback(notification) {
+        if (notification == "AXLiveRegionChanged") {
+           alert("Successfully received " + notification);
+           liveRegion.removeNotificationListener();
+           window.layoutTestController.notifyDone();
+        }
+    }
+
+    if (window.accessibilityController) {
+        window.layoutTestController.waitUntilDone();
+
+        document.getElementById("liveregion").focus();
+        liveRegion = window.accessibilityController.focusedElement;
+
+        var addedNotification = liveRegion.addNotificationListener(ariaCallback);
+        shouldBe("addedNotification", "true");
+
+        // this should trigger our live region callback for a new element.
+        document.getElementById("addregion").innerHTML += "new text element";
+    }
+
+    successfullyParsed = true;
+</script>
+
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/platform/mac/accessibility/aria-liveregions-changedalt-expected.txt b/LayoutTests/platform/mac/accessibility/aria-liveregions-changedalt-expected.txt
new file mode 100644 (file)
index 0000000..9dcbeaf
--- /dev/null
@@ -0,0 +1,12 @@
+ALERT: Successfully received AXLiveRegionChanged
+
+This tests that changing the alt tag of an image in a live region triggers a live region notification.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS addedNotification is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/mac/accessibility/aria-liveregions-changedalt.html b/LayoutTests/platform/mac/accessibility/aria-liveregions-changedalt.html
new file mode 100644 (file)
index 0000000..8333a40
--- /dev/null
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../../../fast/js/resources/js-test-style.css">
+<script>
+var successfullyParsed = false;
+</script>
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body id="body">
+
+<div role="group" tabindex=0 id="liveregion" aria-live="polite" aria-relevant="additions">
+<img src="test.gif" width=100 height=100 alt="alt text" id="image">
+</div>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+
+    description("This tests that changing the alt tag of an image in a live region triggers a live region notification.");
+
+    var liveRegionAlt = 0;
+    function ariaCallbackAlt(notification) {
+        if (notification == "AXLiveRegionChanged") {
+           alert("Successfully received " + notification);
+           liveRegionAlt.removeNotificationListener();
+           window.layoutTestController.notifyDone();
+        }
+    }
+
+    if (window.accessibilityController) {
+        window.layoutTestController.waitUntilDone();
+
+        document.getElementById("liveregion").focus();
+        liveRegionAlt = window.accessibilityController.focusedElement;
+
+        var addedNotification = liveRegionAlt.addNotificationListener(ariaCallbackAlt);
+        shouldBe("addedNotification", "true");
+
+        // this should also trigger our live region change because its a text alternative change. 
+        document.getElementById("image").setAttribute('alt', "new image text");
+    }
+
+    successfullyParsed = true;
+</script>
+
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/platform/mac/accessibility/aria-liveregions-changedtext-expected.txt b/LayoutTests/platform/mac/accessibility/aria-liveregions-changedtext-expected.txt
new file mode 100644 (file)
index 0000000..799f71e
--- /dev/null
@@ -0,0 +1,13 @@
+ALERT: Successfully received AXLiveRegionChanged
+changed text
+
+This tests that when you change text in a live region, the proper notification is sent.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS addedNotification is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/mac/accessibility/aria-liveregions-changedtext.html b/LayoutTests/platform/mac/accessibility/aria-liveregions-changedtext.html
new file mode 100644 (file)
index 0000000..7988302
--- /dev/null
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../../../fast/js/resources/js-test-style.css">
+<script>
+var successfullyParsed = false;
+</script>
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body id="body">
+
+<div role="group" tabindex=0 id="liveregion" aria-live="polite" aria-relevant="additions">
+<h3 id="innerlive">text</h3>
+</div>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+
+    description("This tests that when you change text in a live region, the proper notification is sent.");
+
+    var liveRegionText = 0;
+    function ariaCallbackText(notification) {
+        if (notification == "AXLiveRegionChanged") {
+           alert("Successfully received " + notification);
+           liveRegionText.removeNotificationListener();
+           window.layoutTestController.notifyDone();
+        }
+    }
+
+    if (window.accessibilityController) {
+        window.layoutTestController.waitUntilDone();
+
+        document.getElementById("liveregion").focus();
+        liveRegionText = window.accessibilityController.focusedElement;
+
+        var addedNotification = liveRegionText.addNotificationListener(ariaCallbackText);
+        shouldBe("addedNotification", "true");
+
+        // this should trigger our live region callback for a text change.
+        document.getElementById("innerlive").innerText = "changed text";
+    }
+
+    successfullyParsed = true;
+</script>
+
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
index d44281d..5a98e14 100644 (file)
@@ -21,6 +21,7 @@ var successfullyParsed = false;
 
     description("This tests that ARIA live regions are sending out the correct notifications. We perform four operations (add, remove, change text, change alt tag), each one should trigger a live region notification");
 
+    var liveRegion = 0;
     var liveRegionChangeCount = 0;
     function ariaCallback(notification) {
         if (notification == "AXLiveRegionChanged") {
@@ -28,6 +29,7 @@ var successfullyParsed = false;
 
             // We should get a total of 4 live region changes.
             if (liveRegionChangeCount == 4) {
+               liveRegion.removeNotificationListener();
                window.layoutTestController.notifyDone();
             }
         }
@@ -37,7 +39,7 @@ var successfullyParsed = false;
         window.layoutTestController.waitUntilDone();
 
         document.getElementById("liveregion").focus();
-        var liveRegion = window.accessibilityController.focusedElement;
+        liveRegion = window.accessibilityController.focusedElement;
 
         var addedNotification = liveRegion.addNotificationListener(ariaCallback);
         shouldBe("addedNotification", "true");
diff --git a/LayoutTests/platform/mac/accessibility/aria-liveregions-removedelement-expected.txt b/LayoutTests/platform/mac/accessibility/aria-liveregions-removedelement-expected.txt
new file mode 100644 (file)
index 0000000..c5d7387
--- /dev/null
@@ -0,0 +1,12 @@
+ALERT: Successfully received AXLiveRegionChanged
+
+This tests that ARIA removing an element from a live region sends the correct notification.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS addedNotification is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/mac/accessibility/aria-liveregions-removedelement.html b/LayoutTests/platform/mac/accessibility/aria-liveregions-removedelement.html
new file mode 100644 (file)
index 0000000..6f21f54
--- /dev/null
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../../../fast/js/resources/js-test-style.css">
+<script>
+var successfullyParsed = false;
+</script>
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body id="body">
+
+<div role="group" tabindex=0 id="liveregion" aria-live="polite" aria-relevant="additions">
+<h3 id="innerlive">text</h3>
+<img src="test.gif" width=100 height=100 alt="alt text" tabindex=0 id="image">
+</div>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+
+    description("This tests that ARIA removing an element from a live region sends the correct notification.");
+
+    var liveRegion = 0;
+    function ariaCallback(notification) {
+        if (notification == "AXLiveRegionChanged") {
+           alert("Successfully received " + notification);
+           liveRegion.removeNotificationListener();
+           window.layoutTestController.notifyDone();
+        }
+    }
+
+    if (window.accessibilityController) {
+        window.layoutTestController.waitUntilDone();
+
+        document.getElementById("liveregion").focus();
+        liveRegion = window.accessibilityController.focusedElement;
+
+        var addedNotification = liveRegion.addNotificationListener(ariaCallback);
+        shouldBe("addedNotification", "true");
+
+        // this should trigger our live region callback for a removed element.
+        document.getElementById("liveregion").removeChild(document.getElementById("innerlive")); 
+    }
+
+    successfullyParsed = true;
+</script>
+
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
index 96725c2..b22148f 100644 (file)
@@ -11,10 +11,12 @@ hello hello hello hello hello hello hello hello hello hello hello hello hello he
     if (window.layoutTestController)
         layoutTestController.dumpAsText();
 
+    var textarea = 0;
     function ariaCallback(notification) {
         if (notification == "AXValueChanged") {
             var result = document.getElementById("result");
             result.innerHTML = "Success!"; 
+            textarea.removeNotificationListener();
             window.layoutTestController.notifyDone();
         }
     }
@@ -22,7 +24,7 @@ hello hello hello hello hello hello hello hello hello hello hello hello hello he
     if (window.accessibilityController) {
         window.layoutTestController.waitUntilDone();
         document.getElementById("textarea").focus();
-        var textarea = window.accessibilityController.focusedElement;
+        textarea = window.accessibilityController.focusedElement;
         
         var addedNotification = textarea.addNotificationListener(ariaCallback);
         
index 274d640..9700ffe 100644 (file)
@@ -1,3 +1,27 @@
+2009-04-21  Chris Fleizach  <cfleizach@apple.com>
+
+        Reviewed by Alexey Proskuryakov.
+
+        aria-liveregion-notifications.html fails on leopard release bot
+        https://bugs.webkit.org/show_bug.cgi?id=37112
+
+        Change the method that DRT uses to monitor AX notifications so that its robust
+        by just sending out NSNotification that can be listened to by anyone, instead
+        of keeping a static function pointer around.
+   
+        This change is aimed to avoid flakiness seen in DRT when the notification handlers
+        are not being called at the appropriate time.
+
+        Tests: platform/mac/accessibility/aria-liveregions-addedelement.html
+               platform/mac/accessibility/aria-liveregions-changedalt.html
+               platform/mac/accessibility/aria-liveregions-changedtext.html
+               platform/mac/accessibility/aria-liveregions-removedelement.html
+
+        * accessibility/mac/AccessibilityObjectWrapper.h:
+        * accessibility/mac/AccessibilityObjectWrapper.mm:
+        (-[AccessibilityObjectWrapper accessibilitySetShouldRepostNotifications:]):
+        (-[AccessibilityObjectWrapper accessibilityPostedNotification:]):
+
 2010-04-21  Gavin Barraclough  <barraclough@apple.com>
 
         Reviewed by NOBODY (Leopard build fix).
index 1f0a9e3..e6cc706 100644 (file)
@@ -53,7 +53,7 @@ class VisiblePosition;
 - (WebCore::AccessibilityObject*)accessibilityObject;
 
 // Used to inform an element when a notification is posted for it. Used by DRT.
-- (void)accessibilityPostedNotification:(NSString *)notification;
+- (void)accessibilityPostedNotification:(NSString *)notificationName;
 
 - (NSView*)attachmentView;
 
index ab71cf4..f13968d 100644 (file)
@@ -2667,22 +2667,19 @@ static RenderObject* rendererForView(NSView* view)
     return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
 }
 
-// These are used by DRT so that it can know when notifications are sent.
-// Since they are static, only one callback can be installed at a time (that's all DRT should need).
-typedef void (*AXPostedNotificationCallback)(id element, NSString* notification, void* context);
-static AXPostedNotificationCallback AXNotificationCallback = 0;
-static void* AXPostedNotificationContext = 0;
-
-- (void)accessibilitySetPostedNotificationCallback:(AXPostedNotificationCallback)function withContext:(void*)context
+// This is set by DRT when it wants to listen for notifications.
+static BOOL accessibilityShouldRepostNotifications;
+- (void)accessibilitySetShouldRepostNotifications:(BOOL)repost
 {
-    AXNotificationCallback = function;
-    AXPostedNotificationContext = context;
+    accessibilityShouldRepostNotifications = repost;
 }
 
-- (void)accessibilityPostedNotification:(NSString *)notification
+- (void)accessibilityPostedNotification:(NSString *)notificationName
 {
-    if (AXNotificationCallback)
-        AXNotificationCallback(self, notification, AXPostedNotificationContext);
+    if (accessibilityShouldRepostNotifications) {
+        NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:notificationName, @"notificationName", nil];
+        [[NSNotificationCenter defaultCenter] postNotificationName:@"AXDRTNotification" object:nil userInfo:userInfo];
+    }
 }
 
 @end
index c8ad669..a03ae52 100644 (file)
@@ -1,3 +1,32 @@
+2010-04-21  Chris Fleizach  <cfleizach@apple.com>
+
+        Reviewed by Alexey Proskuryakov.
+
+        aria-liveregion-notifications.html fails on leopard release bot
+        https://bugs.webkit.org/show_bug.cgi?id=37112
+
+        Change the way that notifications are listened for by forcing clients
+        to call a remove listener as well to match the add listener. DRT will
+        assert if those are not done in the correct order. 
+
+        * DumpRenderTree/AccessibilityUIElement.cpp:
+        (removeNotificationListenerCallback):
+        (AccessibilityUIElement::getJSClass):
+        * DumpRenderTree/AccessibilityUIElement.h:
+        * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+        (AccessibilityUIElement::removeNotificationListener):
+        * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+        (-[AccessibilityNotificationHandler initWithPlatformElement:]):
+        (-[AccessibilityNotificationHandler dealloc]):
+        (-[AccessibilityNotificationHandler _notificationReceived:]):
+        (-[AccessibilityNotificationHandler setCallback:]):
+        (AccessibilityUIElement::AccessibilityUIElement):
+        (AccessibilityUIElement::~AccessibilityUIElement):
+        (AccessibilityUIElement::addNotificationListener):
+        (AccessibilityUIElement::removeNotificationListener):
+        * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+        (AccessibilityUIElement::removeNotificationListener):
+
 2010-04-21  Anders Carlsson  <andersca@apple.com>
 
         Reviewed by Sam Weinig.
index 5fbdfc7..9cf34de 100644 (file)
@@ -624,6 +624,12 @@ static JSValueRef addNotificationListenerCallback(JSContextRef context, JSObject
     return JSValueMakeBoolean(context, succeeded);
 }
 
+static JSValueRef removeNotificationListenerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    toAXElement(thisObject)->removeNotificationListener();
+    return JSValueMakeUndefined(context);
+}
+
 // Destruction
 
 static void finalize(JSObjectRef thisObject)
@@ -728,6 +734,7 @@ JSClassRef AccessibilityUIElement::getJSClass()
         { "selectedRowAtIndex", selectedRowAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "isEqual", isEqualCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "addNotificationListener", addNotificationListenerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+        { "removeNotificationListener", removeNotificationListenerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "takeFocus", takeFocusCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "takeSelection", takeSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "addSelection", addSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
index b1c2536..f62ec1a 100644 (file)
@@ -51,6 +51,14 @@ typedef AtkObject* PlatformUIElement;
 typedef void* PlatformUIElement;
 #endif
 
+#if PLATFORM(MAC)
+#ifdef __OBJC__
+typedef id NotificationHandler;
+#else
+typedef struct objc_object* NotificationHandler;
+#endif
+#endif
+
 class AccessibilityUIElement {
 public:
     AccessibilityUIElement(PlatformUIElement);
@@ -174,12 +182,17 @@ public:
     // Notifications
     // Function callback should take one argument, the name of the notification.
     bool addNotificationListener(JSObjectRef functionCallback);
+    // Make sure you call remove, because you can't rely on objects being deallocated in a timely fashion.
+    void removeNotificationListener();
     
 private:
     static JSClassRef getJSClass();
-
     PlatformUIElement m_element;
-    JSObjectRef m_notificationFunctionCallback;
+    
+    // A retained, platform specific object used to help manage notifications for this object.
+#if PLATFORM(MAC)
+    NotificationHandler m_notificationHandler;
+#endif
 };
 
 #endif // AccessibilityUIElement_h
index b56fbda..fabada3 100644 (file)
@@ -588,6 +588,11 @@ bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallbac
     return false;
 }
 
+void AccessibilityUIElement::removeNotificationListener()
+{
+    // FIXME: implement
+}
+
 bool AccessibilityUIElement::isSelectable() const
 {
     // FIXME: implement
index 0167718..a39dabb 100644 (file)
@@ -57,33 +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;
@@ -107,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)
@@ -780,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
index 3d6bf04..9f00ae4 100644 (file)
@@ -562,6 +562,11 @@ bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallbac
     return true;
 }
 
+void AccessibilityUIElement::removeNotificationListener()
+{
+    // FIXME: implement
+}
+
 bool AccessibilityUIElement::isSelectable() const
 {
     DWORD state = accessibilityState(m_element);