Bug 1294853 part2 - hide should preceed a parent show if event tree is trimmed, r=yzen
authorAlexander Surkov <surkov.alexander@gmail.com>
Fri, 30 Sep 2016 10:46:05 -0400
changeset 419806 fb9d10ac4f66badced6a4a6fee082c25fbfb1276
parent 419805 4a79b4164b66464e07347cb22b1648f39a8ed89b
child 419807 a35bade493035b8339f2492735dcbf78a0120118
push id31023
push usercykesiopka.bmo@gmail.com
push dateSat, 01 Oct 2016 01:30:33 +0000
reviewersyzen
bugs1294853
milestone52.0a1
Bug 1294853 part2 - hide should preceed a parent show if event tree is trimmed, r=yzen
accessible/base/EventTree.cpp
accessible/tests/mochitest/events/test_coalescence.html
--- a/accessible/base/EventTree.cpp
+++ b/accessible/base/EventTree.cpp
@@ -479,16 +479,69 @@ EventTree::Mutated(AccMutationEvent* aEv
 {
   // If shown or hidden node is a root of previously mutated subtree, then
   // discard those subtree mutations as we are no longer interested in them.
   UniquePtr<EventTree>* node = &mFirst;
   while (*node) {
     Accessible* cntr = (*node)->mContainer;
     while (cntr != mContainer) {
       if (cntr == aEv->mAccessible) {
+#ifdef A11Y_LOG
+        if (logging::IsEnabled(logging::eEventTree)) {
+          logging::MsgBegin("EVENTS_TREE", "Trim subtree");
+          logging::AccessibleInfo("Show/hide container", aEv->mAccessible);
+          logging::AccessibleInfo("Trimmed subtree root", (*node)->mContainer);
+          logging::MsgEnd();
+        }
+#endif
+
+        // If the new hide is part of a move and it contains existing child
+        // shows, then move preceding events from the child shows to the buffer,
+        // so the ongoing show event will pick them up.
+        if (aEv->IsHide()) {
+          AccHideEvent* hideEv = downcast_accEvent(aEv);
+          if (!hideEv->mNeedsShutdown) {
+            for (uint32_t i = 0; i < (*node)->mDependentEvents.Length(); i++) {
+              AccMutationEvent* childEv = (*node)->mDependentEvents[i];
+              if (childEv->IsShow()) {
+                AccShowEvent* childShowEv = downcast_accEvent(childEv);
+                if (childShowEv->mPrecedingEvents.Length() > 0) {
+                  Controller(mContainer)->StorePrecedingEvents(
+                    mozilla::Move(childShowEv->mPrecedingEvents));
+                }
+              }
+            }
+          }
+        }
+        // If the new show contains existing child shows, then move preceding
+        // events from the child shows to the new show.
+        else if (aEv->IsShow()) {
+          AccShowEvent* showEv = downcast_accEvent(aEv);
+          for (uint32_t i = 0; (*node)->mDependentEvents.Length(); i++) {
+            AccMutationEvent* childEv = (*node)->mDependentEvents[i];
+            if (childEv->IsShow()) {
+              AccShowEvent* showChildEv = downcast_accEvent(childEv);
+              if (showChildEv->mPrecedingEvents.Length() > 0) {
+#ifdef A11Y_LOG
+                if (logging::IsEnabled(logging::eEventTree)) {
+                  logging::MsgBegin("EVENTS_TREE", "Adopt preceding events");
+                  logging::AccessibleInfo("Parent", aEv->mAccessible);
+                  for (uint32_t j = 0; j < showChildEv->mPrecedingEvents.Length(); j++) {
+                    logging::AccessibleInfo("Adoptee",
+                      showChildEv->mPrecedingEvents[i]->mAccessible);
+                  }
+                  logging::MsgEnd();
+                }
+#endif
+                showEv->mPrecedingEvents.AppendElements(showChildEv->mPrecedingEvents);
+              }
+            }
+          }
+        }
+
         *node = Move((*node)->mNext);
         break;
       }
       cntr = cntr->Parent();
     }
     if (cntr == aEv->mAccessible) {
       continue;
     }
--- a/accessible/tests/mochitest/events/test_coalescence.html
+++ b/accessible/tests/mochitest/events/test_coalescence.html
@@ -553,16 +553,62 @@
         getNode('t8_c1').setAttribute('aria-owns', 't8_c2_moved');
       };
 
       this.getID = function test8_getID() {
         return "Move a node by aria-owns to left within the tree";
       };
     }
 
+    /**
+     * Move 't9_c2_moved' node by aria-owns, and then move 't9_c3_moved' node
+     * under 't9_c2_moved' (same as test9 but has different aria-owns
+     * ordering), the eventing looks same way as in test9:
+     * reorder for 't9_c1'
+     *   hide for 't9_c1_child'
+     *   show for 't9_c2_moved'
+     * reorder for 't9_c2'
+     *   hide for 't9_c2_moved'
+     * reorder for 't9_c3'
+     *   hide for 't9_c3_moved'
+     *
+     * The hide events for 't9_c2_moved' and 't9_c3_moved' should be delivered
+     * before the show event for 't9_c2_moved'.
+     */
+    function test9()
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_HIDE, getNode('t9_c1_child')),
+        new invokerChecker(EVENT_HIDE, 't9_c3_moved'),
+        new invokerChecker(EVENT_HIDE, 't9_c2_moved'),
+        new invokerChecker(EVENT_SHOW, 't9_c2_moved'),
+        new invokerChecker(EVENT_REORDER, 't9_c1'),
+        new invokerChecker(EVENT_HIDE, getNode('t9_c2_child')),
+        new invokerChecker(EVENT_REORDER, 't9_c2'),
+        new invokerChecker(EVENT_REORDER, 't9_c3'),
+        new unexpectedInvokerChecker(EVENT_SHOW, 't9_c3_moved')
+      ];
+
+      this.invoke = function test9_invoke()
+      {
+        // Remove child nodes from 't9_c1' and 't9_c2' containers to give
+        // the event tree a needed structure ('t9_c1' and 't9_c2' nodes go
+        // first in the event tree),
+        getNode('t9_c1_child').remove();
+        getNode('t9_c2_child').remove();
+        // then do aria-owns magic.
+        getNode('t9_c2_moved').setAttribute('aria-owns', 't9_c3_moved');
+        getNode('t9_c1').setAttribute('aria-owns', 't9_c2_moved');
+      };
+
+      this.getID = function test9_getID() {
+        return "Move node #1 by aria-owns and then move node #2 into node #1";
+      };
+    }
+
     ////////////////////////////////////////////////////////////////////////////
     // Do tests.
 
     //gA11yEventDumpToConsole = true; // debug stuff
     //enableLogging("eventTree");
 
     var gQueue = null;
     function doTests()
@@ -587,16 +633,17 @@
 
       gQueue.push(new removeGrandChildrenNHideParent("t1_child1", "t1_child2", "t1_parent"));
       gQueue.push(new test3());
       gQueue.push(new test4());
       gQueue.push(new test5());
       gQueue.push(new test6());
       gQueue.push(new test7());
       gQueue.push(new test8());
+      gQueue.push(new test9());
 
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTests);
   </script>
 </head>
@@ -694,10 +741,21 @@
   </div>
 
   <div id="t8">
     <div id="t8_c1"><div id="t8_c1_child"></div></div>
     <div id="t8_c2">
       <div id="t8_c2_moved"></div>
     </div>
   </div>
+
+  <div id="t9">
+    <div id="t9_c1"><div id="t9_c1_child"></div></div>
+    <div id="t9_c2">
+      <div id="t9_c2_child"></div>
+      <div id="t9_c2_moved"></div>
+    </div>
+    <div id="t9_c3">
+      <div id="t9_c3_moved"></div>
+    </div>
+  </div>
 </body>
 </html>