Bug 676267 - expose stale state on accessibles unattached from tree, r=tbsaunde
authorAlexander Surkov <surkov.alexander@gmail.com>
Thu, 04 Aug 2011 18:54:06 +0900
changeset 73851 dd38dafe931bf15332057edd46a96ad8c1b28602
parent 73850 7b917981c44dfa8cd6869fc42c54496dc54a8a3d
child 73852 d201bfd052b397f6213dbc2266664e024aae5ba9
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
reviewerstbsaunde
bugs676267
milestone8.0a1
Bug 676267 - expose stale state on accessibles unattached from tree, r=tbsaunde
accessible/src/base/nsAccessible.cpp
accessible/src/base/nsDocAccessible.h
accessible/tests/mochitest/states/Makefile.in
accessible/tests/mochitest/states/test_stale.html
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -658,16 +658,21 @@ nsAccessible::IsVisible(PRBool* aIsOffsc
   }
   return isVisible;
 }
 
 PRUint64
 nsAccessible::NativeState()
 {
   PRUint64 state = 0;
+
+  nsDocAccessible* document = GetDocAccessible();
+  if (!document || !document->IsInDocument(this))
+    state |= states::STALE;
+
   PRBool disabled = PR_FALSE;
   if (mContent->IsElement()) {
     nsEventStates elementState = mContent->AsElement()->State();
 
     if (elementState.HasState(NS_EVENT_STATE_INVALID))
       state |= states::INVALID;
 
     if (elementState.HasState(NS_EVENT_STATE_REQUIRED))
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -230,19 +230,29 @@ public:
    *
    * @return the accessible object
    */
   nsAccessible* GetAccessible(nsINode* aNode) const;
 
   /**
    * Return whether the given DOM node has an accessible or not.
    */
-  inline bool HasAccessible(nsINode* aNode)
+  inline bool HasAccessible(nsINode* aNode) const
+    { return GetAccessible(aNode); }
+
+  /**
+   * Return true if the given accessible is in document.
+   */
+  inline bool IsInDocument(nsAccessible* aAccessible) const
   {
-    return GetAccessible(aNode);
+    nsAccessible* acc = aAccessible;
+    while (acc && !acc->IsPrimaryForNode())
+      acc = acc->Parent();
+
+    return acc ? mNodeToAccessibleMap.Get(acc->GetNode()) : false;
   }
 
   /**
    * Return the cached accessible by the given unique ID within this document.
    *
    * @note   the unique ID matches with the uniqueID() of nsAccessNode
    *
    * @param  aUniqueID  [in] the unique ID used to cache the node.
--- a/accessible/tests/mochitest/states/Makefile.in
+++ b/accessible/tests/mochitest/states/Makefile.in
@@ -53,16 +53,17 @@ include $(topsrcdir)/config/rules.mk
 		test_doc.html \
 		test_docarticle.html \
 		test_editablebody.html \
 		test_frames.html \
 		test_inputs.html \
 		test_inputs.xul \
 		test_link.html \
 		test_popup.xul \
+		test_stale.html \
 		test_textbox.xul \
 		test_tree.xul \
 		z_frames.html \
 		z_frames_article.html \
 		z_frames_checkbox.html \
 		z_frames_textbox.html \
 		z_frames_update.html \
 		$(NULL)
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/states/test_stale.html
@@ -0,0 +1,115 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Stale state testing</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <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="../states.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+
+  <script type="application/javascript">
+    function addChild(aContainerID)
+    {
+      this.containerNode = getNode(aContainerID);
+      this.childNode = null;
+
+      this.eventSeq = [
+        new invokerChecker(EVENT_REORDER, this.containerNode)
+      ];
+
+      this.invoke = function addChild_invoke()
+      {
+        this.childNode = document.createElement("div");
+        this.containerNode.appendChild(this.childNode);
+      }
+
+      this.finalCheck = function addChild_finalCheck()
+      {
+        // no stale state should be set
+        testStates(this.childNode, 0, 0, 0, EXT_STATE_STALE);
+      }
+
+      this.getID = function addChild_getID()
+      {
+        return "add child for " + prettyName(aContainerID);
+      }
+    }
+
+    function removeChildChecker(aInvoker)
+    {
+      this.type = EVENT_HIDE;
+      this.__defineGetter__("target", function() { return aInvoker.child; });
+
+      this.check = function removeChildChecker_check()
+      {
+        // stale state should be set
+        testStates(aInvoker.child, 0, EXT_STATE_STALE);
+      }
+    }
+
+    function removeChild(aContainerID)
+    {
+      this.containerNode = getNode(aContainerID);
+      this.child = null;
+
+      this.eventSeq = [
+        new removeChildChecker(this)
+      ];
+
+      this.invoke = function removeChild_invoke()
+      {
+        var childNode = this.containerNode.firstChild;
+        this.child = getAccessible(childNode);
+
+        this.containerNode.removeChild(childNode);
+      }
+
+      this.getID = function removeChild_getID()
+      {
+        return "remove child from " + prettyName(aContainerID);
+      }
+    }
+
+    //gA11yEventDumpToConsole = true; //debugging
+
+    var gQueue = null;
+    function doTest()
+    {
+      gQueue = new eventQueue();
+
+      gQueue.push(new addChild("container"));
+      gQueue.push(new removeChild("container"));
+
+      gQueue.invoke(); // will call SimpleTest.finish()
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+
+<body role="">
+
+  <a target="_blank"
+     title="Expose stale state on accessibles unattached from tree"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=676267">Mozilla Bug 676267</a>
+
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <div id="container"></div>
+
+</body>
+</html>