author | Lorien Hu <lorien@lorienhu.com> |
Tue, 04 Aug 2015 23:35:54 -0400 | |
changeset 256222 | 89002bda1f558d5df20a36e0db4b1a5c10d517f8 |
parent 256221 | ef291c49717330a7e9132b075a68baccbd2e8748 |
child 256223 | 6d03329ef85e157515b3262966c420cfe3bc98f6 |
push id | 63270 |
push user | lhu@mozilla.com |
push date | Wed, 05 Aug 2015 03:48:47 +0000 |
treeherder | mozilla-inbound@6d03329ef85e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | tbsaunde |
bugs | 1175913 |
milestone | 42.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/accessible/base/nsAccessibilityService.cpp +++ b/accessible/base/nsAccessibilityService.cpp @@ -17,16 +17,17 @@ #include "HTMLLinkAccessible.h" #include "HTMLListAccessible.h" #include "HTMLSelectAccessible.h" #include "HTMLTableAccessibleWrap.h" #include "HyperTextAccessibleWrap.h" #include "RootAccessible.h" #include "nsAccessiblePivot.h" #include "nsAccUtils.h" +#include "nsArrayUtils.h" #include "nsAttrName.h" #include "nsEventShell.h" #include "nsIURI.h" #include "OuterDocAccessible.h" #include "Platform.h" #include "Role.h" #ifdef MOZ_ACCESSIBILITY_ATK #include "RootAccessibleWrap.h" @@ -269,23 +270,82 @@ nsAccessibilityService::nsAccessibilityS nsAccessibilityService::~nsAccessibilityService() { NS_ASSERTION(gIsShutdown, "Accessibility wasn't shutdown!"); gAccessibilityService = nullptr; } //////////////////////////////////////////////////////////////////////////////// +// nsIListenerChangeListener + +NS_IMETHODIMP +nsAccessibilityService::ListenersChanged(nsIArray* aEventChanges) +{ + uint32_t targetCount; + nsresult rv = aEventChanges->GetLength(&targetCount); + NS_ENSURE_SUCCESS(rv, rv); + + for (uint32_t i = 0 ; i < targetCount ; i++) { + nsCOMPtr<nsIEventListenerChange> change = do_QueryElementAt(aEventChanges, i); + + nsCOMPtr<nsIDOMEventTarget> target; + change->GetTarget(getter_AddRefs(target)); + nsCOMPtr<nsIContent> node(do_QueryInterface(target)); + if (!node || !node->IsHTMLElement()) { + continue; + } + nsCOMPtr<nsIArray> listenerNames; + change->GetChangedListenerNames(getter_AddRefs(listenerNames)); + + uint32_t changeCount; + rv = listenerNames->GetLength(&changeCount); + NS_ENSURE_SUCCESS(rv, rv); + + for (uint32_t i = 0 ; i < changeCount ; i++) { + nsCOMPtr<nsIAtom> listenerName = do_QueryElementAt(listenerNames, i); + + // We are only interested in event listener changes which may + // make an element accessible or inaccessible. + if (listenerName != nsGkAtoms::onclick && + listenerName != nsGkAtoms::onmousedown && + listenerName != nsGkAtoms::onmouseup) { + continue; + } + + nsIDocument* ownerDoc = node->OwnerDoc(); + DocAccessible* document = GetExistingDocAccessible(ownerDoc); + + // Always recreate for onclick changes. + if (document) { + if (nsCoreUtils::HasClickListener(node)) { + if (!document->GetAccessible(node)) { + document->RecreateAccessible(node); + } + } else { + if (document->GetAccessible(node)) { + document->RecreateAccessible(node); + } + } + break; + } + } + } + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// // nsISupports NS_IMPL_ISUPPORTS_INHERITED(nsAccessibilityService, DocManager, nsIAccessibilityService, nsIAccessibleRetrieval, nsIObserver, + nsIListenerChangeListener, nsISelectionListener) // from SelectionManager //////////////////////////////////////////////////////////////////////////////// // nsIObserver NS_IMETHODIMP nsAccessibilityService::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData) @@ -1253,16 +1313,24 @@ nsAccessibilityService::Init() if (!observerService) return false; observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); static const char16_t kInitIndicator[] = { '1', 0 }; observerService->NotifyObservers(nullptr, "a11y-init-or-shutdown", kInitIndicator); + // Subscribe to EventListenerService. + nsCOMPtr<nsIEventListenerService> eventListenerService = + do_GetService("@mozilla.org/eventlistenerservice;1"); + if (!eventListenerService) + return false; + + eventListenerService->AddListenerChangeListener(this); + for (uint32_t i = 0; i < ArrayLength(sMarkupMapList); i++) mMarkupMaps.Put(*sMarkupMapList[i].tag, &sMarkupMapList[i]); #ifdef A11Y_LOG logging::CheckEnv(); #endif if (XRE_IsParentProcess())
--- a/accessible/base/nsAccessibilityService.h +++ b/accessible/base/nsAccessibilityService.h @@ -10,18 +10,20 @@ #include "mozilla/a11y/DocManager.h" #include "mozilla/a11y/FocusManager.h" #include "mozilla/a11y/Role.h" #include "mozilla/a11y/SelectionManager.h" #include "mozilla/Preferences.h" #include "nsIObserver.h" +#include "nsIEventListenerService.h" class nsImageFrame; +class nsIArray; class nsIPersistentProperties; class nsPluginFrame; class nsITreeView; namespace mozilla { namespace a11y { class ApplicationAccessible; @@ -62,22 +64,26 @@ struct MarkupMapInfo { } // namespace a11y } // namespace mozilla class nsAccessibilityService final : public mozilla::a11y::DocManager, public mozilla::a11y::FocusManager, public mozilla::a11y::SelectionManager, public nsIAccessibilityService, + public nsIListenerChangeListener, public nsIObserver { public: typedef mozilla::a11y::Accessible Accessible; typedef mozilla::a11y::DocAccessible DocAccessible; + // nsIListenerChangeListener + NS_IMETHOD ListenersChanged(nsIArray* aEventChanges) override; + protected: virtual ~nsAccessibilityService(); public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIACCESSIBLERETRIEVAL NS_DECL_NSIOBSERVER
--- a/accessible/generic/DocAccessible.cpp +++ b/accessible/generic/DocAccessible.cpp @@ -1606,18 +1606,17 @@ DocAccessible::UpdateAccessibleOnAttrCha // Recreate the accessible when role is changed because we might require a // different accessible class for the new role or the accessible may expose // a different sets of interfaces (COM restriction). RecreateAccessible(aElement); return true; } - if (aAttribute == nsGkAtoms::href || - aAttribute == nsGkAtoms::onclick) { + if (aAttribute == nsGkAtoms::href) { // Not worth the expense to ensure which namespace these are in. It doesn't // kill use to recreate the accessible even if the attribute was used in // the wrong namespace or an element that doesn't support it. // Make sure the accessible is recreated asynchronously to allow the content // to handle the attribute change. RecreateAccessible(aElement); return true;
--- a/accessible/tests/mochitest/treeupdate/a11y.ini +++ b/accessible/tests/mochitest/treeupdate/a11y.ini @@ -2,16 +2,17 @@ [test_ariadialog.html] [test_bug852150.xhtml] [test_bug883708.xhtml] [test_bug884251.xhtml] [test_bug895082.html] [test_bug1040735.html] [test_bug1100602.html] +[test_bug1175913.html] [test_canvas.html] [test_colorpicker.xul] [test_contextmenu.xul] [test_cssoverflow.html] [test_deck.xul] [test_doc.html] [test_gencontent.html] [test_hidden.html]
new file mode 100644 --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_bug1175913.html @@ -0,0 +1,103 @@ +<html> + +<head> + <title>Test hide/show events on event listener changes</title> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../role.js"></script> + <script type="application/javascript" + src="../events.js"></script> + + <script type="application/javascript"> + + function dummyListener() {} + + function testAddListener() + { + this.eventSeq = [ + new invokerChecker(EVENT_SHOW, getNode("parent")), + ]; + + this.invoke = function testAddListener_invoke() + { + is(getAccessible("parent", null, null, DONOTFAIL_IF_NO_ACC), null, "Check that parent is not accessible."); + is(getAccessible("child", null, null, DONOTFAIL_IF_NO_ACC), null, "Check that child is not accessible."); + getNode("parent").addEventListener("click", dummyListener); + } + + this.finalCheck = function testAddListener_finalCheck() + { + var tree = { TEXT: [] }; + testAccessibleTree("parent", tree); + } + + this.getID = function testAddListener_getID() + { + return "Test that show event is sent when click listener is added"; + } + } + + function testRemoveListener() + { + this.eventSeq = [ + new invokerChecker(EVENT_HIDE, getNode("parent")), + ]; + + this.invoke = function testRemoveListener_invoke() + { + getNode("parent").removeEventListener("click", dummyListener); + } + + this.finalCheck = function testRemoveListener_finalCheck() + { + is(getAccessible("parent", null, null, DONOTFAIL_IF_NO_ACC), null, "Check that parent is not accessible."); + is(getAccessible("child", null, null, DONOTFAIL_IF_NO_ACC), null, "Check that child is not accessible."); + } + + this.getID = function testRemoveListener_getID() + { + return "Test that hide event is sent when click listener is removed"; + } + } + + var gQueue = null; + function doTest() + { + gQueue = new eventQueue(); + gQueue.push(new testAddListener()); + gQueue.push(new testRemoveListener()); + gQueue.invoke(); // SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> + +</head> + +<body> + + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=1175913" + title="Crash in mozilla::a11y::DocAccessibleParent::RemoveAccessible(ProxyAccessible* aAccessible)"> + Mozilla Bug 1175913 + </a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <span id="parent"> + <span id="child"> + </span> + </span> + +</body> +</html>
--- a/accessible/tests/mochitest/treeupdate/test_textleaf.html +++ b/accessible/tests/mochitest/treeupdate/test_textleaf.html @@ -35,27 +35,20 @@ var textLeaf = getAccessible(this.node).firstChild; is(textLeaf.actionCount, (aIsTextLeafLinkable ? 1 : 0), "Wrong action numbers!"); } } function setOnClickAttr(aID) { - this.__proto__ = new textLeafUpdate(aID, true); - - this.invoke = function setOnClickAttr_invoke() - { - this.node.setAttribute("onclick", "alert(3);"); - } - - this.getID = function setOnClickAttr_getID() - { - return "make " + prettyName(aID) + " linkable"; - } + var node = getNode(aID); + node.setAttribute("onclick", "alert(3);"); + var textLeaf = getAccessible(node).firstChild; + is(textLeaf.actionCount, 1, "Wrong action numbers!"); } function removeOnClickAttr(aID) { this.__proto__ = new textLeafUpdate(aID, false); this.invoke = function removeOnClickAttr_invoke() { @@ -129,21 +122,20 @@ //gA11yEventDumpID = "eventdump"; // debug stuff //gA11yEventDumpToConsole = true; var gQueue = null; function doTest() { + // adds onclick on element, text leaf should inherit its action + setOnClickAttr("div"); + // Call rest of event tests. gQueue = new eventQueue(); - - // adds onclick on element, text leaf should inherit its action - gQueue.push(new setOnClickAttr("div")); - // remove onclick attribute, text leaf shouldn't have any action gQueue.push(new removeOnClickAttr("div")); // set onclick attribute making span accessible, it's inserted into tree // and adopts text leaf accessible, text leaf should have an action gQueue.push(new setOnClickNRoleAttrs("span")); // text data removal of text node should remove its text accessible