Backed out 12 changesets (bug 1270916) for a11y crashes a=backout CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Wed, 16 Nov 2016 16:16:13 -0800
changeset 322861 b3b9d24cdb9732fe64ebf2f4486458556b6450db
parent 322860 e089bc358c5c59d95aeb51d488b7c605ec69cd84
child 322862 c428116222e76099999ba5ea0e9178daac7580f9
push id83994
push userkwierso@gmail.com
push dateThu, 17 Nov 2016 00:17:06 +0000
treeherdermozilla-inbound@c428116222e7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1270916
milestone53.0a1
backs out916cbaf21a63da2f7953933481a502d7db9b39a0
8ee47068d1fbde75e42b8e65c5a4781faaa4c9ed
60189bf08272c5afd7c1cc70e88c0b404ae8fcac
5ca49b5d1c51e7f05254aa69e98c2f558a576219
b8ead1b86059ea6454159a6319b66243c47a979d
034efc9a4408c274eb58f57c327d481752b04070
a9d6410f068e633b6fb193a020574e6bdb935fec
eefa622b467a18c5f6147428b6fb57912d705725
91a8f65a69feadf4a3f8ffc725b0eaad549e2721
cd68b5fd88a6922643c848148b7ecf12dacdd407
4c58195d6bcf62a04f8f23b5c199b33db05808e7
8e5f19f19b7f51090ba93d21bae1210f89ba5497
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
Backed out 12 changesets (bug 1270916) for a11y crashes a=backout CLOSED TREE Backed out changeset 916cbaf21a63 (bug 1270916) Backed out changeset 8ee47068d1fb (bug 1270916) Backed out changeset 60189bf08272 (bug 1270916) Backed out changeset 5ca49b5d1c51 (bug 1270916) Backed out changeset b8ead1b86059 (bug 1270916) Backed out changeset 034efc9a4408 (bug 1270916) Backed out changeset a9d6410f068e (bug 1270916) Backed out changeset eefa622b467a (bug 1270916) Backed out changeset 91a8f65a69fe (bug 1270916) Backed out changeset cd68b5fd88a6 (bug 1270916) Backed out changeset 4c58195d6bcf (bug 1270916) Backed out changeset 8e5f19f19b7f (bug 1270916)
accessible/base/AccEvent.cpp
accessible/base/AccEvent.h
accessible/base/EventTree.cpp
accessible/base/EventTree.h
accessible/base/NotificationController.cpp
accessible/base/NotificationController.h
accessible/generic/Accessible.cpp
accessible/generic/Accessible.h
accessible/generic/DocAccessible.cpp
accessible/ipc/DocAccessibleChildBase.cpp
accessible/tests/mochitest/events/test_aria_menu.html
accessible/tests/mochitest/events/test_coalescence.html
accessible/tests/mochitest/events/test_mutation.html
accessible/tests/mochitest/treeupdate/test_ariaowns.html
accessible/tests/mochitest/treeupdate/test_bug1189277.html
accessible/tests/mochitest/treeupdate/test_whitespace.html
--- a/accessible/base/AccEvent.cpp
+++ b/accessible/base/AccEvent.cpp
@@ -37,33 +37,17 @@ AccEvent::AccEvent(uint32_t aEventType, 
     mIsFromUserInput = EventStateManager::IsHandlingUserInput();
   else
     mIsFromUserInput = aIsFromUserInput == eFromUserInput ? true : false;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccEvent cycle collection
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(AccEvent)
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AccEvent)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mAccessible)
-  if (AccTreeMutationEvent* tmEvent = downcast_accEvent(tmp)) {
-    tmEvent->SetNextEvent(nullptr);
-    tmEvent->SetPrevEvent(nullptr);
-  }
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AccEvent)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAccessible)
-  if (AccTreeMutationEvent* tmEvent = downcast_accEvent(tmp)) {
-    CycleCollectionNoteChild(cb, tmEvent->NextEvent(), "mNext");
-    CycleCollectionNoteChild(cb, tmEvent->PrevEvent(), "mPrevEvent");
-  }
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+NS_IMPL_CYCLE_COLLECTION(AccEvent, mAccessible)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AccEvent, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AccEvent, Release)
 
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 // AccTextChangeEvent
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/base/AccEvent.h
+++ b/accessible/base/AccEvent.h
@@ -89,17 +89,16 @@ public:
 
   /**
    * Down casting.
    */
   enum EventGroup {
     eGenericEvent,
     eStateChangeEvent,
     eTextChangeEvent,
-    eTreeMutationEvent,
     eMutationEvent,
     eReorderEvent,
     eHideEvent,
     eShowEvent,
     eCaretMoveEvent,
     eTextSelChangeEvent,
     eSelectionChangeEvent,
     eTableChangeEvent,
@@ -125,17 +124,16 @@ protected:
   bool mIsFromUserInput;
   uint32_t mEventType;
   EEventRule mEventRule;
   RefPtr<Accessible> mAccessible;
 
   friend class EventQueue;
   friend class EventTree;
   friend class ::nsEventShell;
-  friend class NotificationController;
 };
 
 
 /**
  * Accessible state change event.
  */
 class AccStateChangeEvent: public AccEvent
 {
@@ -197,88 +195,53 @@ public:
   const nsString& ModifiedText() const { return mModifiedText; }
 
 private:
   int32_t mStart;
   bool mIsInserted;
   nsString mModifiedText;
 
   friend class EventTree;
-  friend class NotificationController;
 };
 
-/**
- * A base class for events related to tree mutation, either an AccMutation
- * event, or an AccReorderEvent.
- */
-class AccTreeMutationEvent : public AccEvent
-{
-public:
-  AccTreeMutationEvent(uint32_t aEventType, Accessible* aTarget) :
-    AccEvent(aEventType, aTarget, eAutoDetect, eCoalesceReorder), mGeneration(0) {}
-
-  // Event
-  static const EventGroup kEventGroup = eTreeMutationEvent;
-  virtual unsigned int GetEventGroups() const override
-  {
-    return AccEvent::GetEventGroups() | (1U << eTreeMutationEvent);
-  }
-
-  void SetNextEvent(AccTreeMutationEvent* aNext) { mNextEvent = aNext; }
-  void SetPrevEvent(AccTreeMutationEvent* aPrev) { mPrevEvent = aPrev; }
-  AccTreeMutationEvent* NextEvent() const { return mNextEvent; }
-  AccTreeMutationEvent* PrevEvent() const { return mPrevEvent; }
-
-  /**
-   * A sequence number to know when this event was fired.
-   */
-  uint32_t EventGeneration() const { return mGeneration; }
-  void SetEventGeneration(uint32_t aGeneration) { mGeneration = aGeneration; }
-
-private:
-  RefPtr<AccTreeMutationEvent> mNextEvent;
-  RefPtr<AccTreeMutationEvent> mPrevEvent;
-  uint32_t mGeneration;
-};
 
 /**
  * Base class for show and hide accessible events.
  */
-class AccMutationEvent: public AccTreeMutationEvent
+class AccMutationEvent: public AccEvent
 {
 public:
   AccMutationEvent(uint32_t aEventType, Accessible* aTarget) :
-    AccTreeMutationEvent(aEventType, aTarget)
+    AccEvent(aEventType, aTarget, eAutoDetect, eCoalesceReorder)
   {
     // Don't coalesce these since they are coalesced by reorder event. Coalesce
     // contained text change events.
     mParent = mAccessible->Parent();
   }
   virtual ~AccMutationEvent() { }
 
   // Event
   static const EventGroup kEventGroup = eMutationEvent;
   virtual unsigned int GetEventGroups() const override
   {
-    return AccTreeMutationEvent::GetEventGroups() | (1U << eMutationEvent);
+    return AccEvent::GetEventGroups() | (1U << eMutationEvent);
   }
 
   // MutationEvent
   bool IsShow() const { return mEventType == nsIAccessibleEvent::EVENT_SHOW; }
   bool IsHide() const { return mEventType == nsIAccessibleEvent::EVENT_HIDE; }
 
   Accessible* Parent() const { return mParent; }
 
 protected:
   nsCOMPtr<nsINode> mNode;
   RefPtr<Accessible> mParent;
   RefPtr<AccTextChangeEvent> mTextChangeEvent;
 
   friend class EventTree;
-  friend class NotificationController;
 };
 
 
 /**
  * Accessible hide event.
  */
 class AccHideEvent: public AccMutationEvent
 {
@@ -299,17 +262,16 @@ public:
   bool NeedsShutdown() const { return mNeedsShutdown; }
 
 protected:
   bool mNeedsShutdown;
   RefPtr<Accessible> mNextSibling;
   RefPtr<Accessible> mPrevSibling;
 
   friend class EventTree;
-  friend class NotificationController;
 };
 
 
 /**
  * Accessible show event.
  */
 class AccShowEvent: public AccMutationEvent
 {
@@ -331,28 +293,29 @@ private:
 
   friend class EventTree;
 };
 
 
 /**
  * Class for reorder accessible event. Takes care about
  */
-class AccReorderEvent : public AccTreeMutationEvent
+class AccReorderEvent : public AccEvent
 {
 public:
   explicit AccReorderEvent(Accessible* aTarget) :
-    AccTreeMutationEvent(::nsIAccessibleEvent::EVENT_REORDER, aTarget) { }
+    AccEvent(::nsIAccessibleEvent::EVENT_REORDER, aTarget,
+             eAutoDetect, eCoalesceReorder) { }
   virtual ~AccReorderEvent() { }
 
   // Event
   static const EventGroup kEventGroup = eReorderEvent;
   virtual unsigned int GetEventGroups() const override
   {
-    return AccTreeMutationEvent::GetEventGroups() | (1U << eReorderEvent);
+    return AccEvent::GetEventGroups() | (1U << eReorderEvent);
   }
 };
 
 
 /**
  * Accessible caret move event.
  */
 class AccCaretMoveEvent: public AccEvent
--- a/accessible/base/EventTree.cpp
+++ b/accessible/base/EventTree.cpp
@@ -20,18 +20,17 @@ using namespace mozilla::a11y;
 ////////////////////////////////////////////////////////////////////////////////
 // TreeMutation class
 
 EventTree* const TreeMutation::kNoEventTree = reinterpret_cast<EventTree*>(-1);
 
 TreeMutation::TreeMutation(Accessible* aParent, bool aNoEvents) :
   mParent(aParent), mStartIdx(UINT32_MAX),
   mStateFlagsCopy(mParent->mStateFlags),
-  mEventTree(aNoEvents ? kNoEventTree : nullptr),
-  mQueueEvents(!aNoEvents)
+  mEventTree(aNoEvents ? kNoEventTree : nullptr)
 {
 #ifdef DEBUG
   mIsDone = false;
 #endif
 
 #ifdef A11Y_LOG
   if (mEventTree != kNoEventTree && logging::IsEnabled(logging::eEventTree)) {
     logging::MsgBegin("EVENTS_TREE", "reordering tree before");
@@ -58,42 +57,48 @@ void
 TreeMutation::AfterInsertion(Accessible* aChild)
 {
   MOZ_ASSERT(aChild->Parent() == mParent);
 
   if (static_cast<uint32_t>(aChild->mIndexInParent) < mStartIdx) {
     mStartIdx = aChild->mIndexInParent + 1;
   }
 
-  if (!mQueueEvents) {
-    return;
+  if (!mEventTree) {
+    mEventTree = Controller()->QueueMutation(mParent);
+    if (!mEventTree) {
+      mEventTree = kNoEventTree;
+    }
   }
 
-  RefPtr<AccShowEvent> ev = new AccShowEvent(aChild);
-  DebugOnly<bool> added = Controller()->QueueMutationEvent(ev);
-  MOZ_ASSERT(added);
-  aChild->SetShowEventTarget(true);
+  if (mEventTree != kNoEventTree) {
+    mEventTree->Shown(aChild);
+    Controller()->QueueNameChange(aChild);
+  }
 }
 
 void
 TreeMutation::BeforeRemoval(Accessible* aChild, bool aNoShutdown)
 {
   MOZ_ASSERT(aChild->Parent() == mParent);
 
   if (static_cast<uint32_t>(aChild->mIndexInParent) < mStartIdx) {
     mStartIdx = aChild->mIndexInParent;
   }
 
-  if (!mQueueEvents) {
-    return;
+  if (!mEventTree) {
+    mEventTree = Controller()->QueueMutation(mParent);
+    if (!mEventTree) {
+      mEventTree = kNoEventTree;
+    }
   }
 
-  RefPtr<AccHideEvent> ev = new AccHideEvent(aChild, !aNoShutdown);
-  if (Controller()->QueueMutationEvent(ev)) {
-    aChild->SetHideEventTarget(true);
+  if (mEventTree != kNoEventTree) {
+    mEventTree->Hidden(aChild, !aNoShutdown);
+    Controller()->QueueNameChange(aChild);
   }
 }
 
 void
 TreeMutation::Done()
 {
   MOZ_ASSERT(mParent->mStateFlags & Accessible::eKidsMutating);
   mParent->mStateFlags &= ~Accessible::eKidsMutating;
--- a/accessible/base/EventTree.h
+++ b/accessible/base/EventTree.h
@@ -44,21 +44,16 @@ private:
   static const char* PrefixLog(void* aData, Accessible*);
 #endif
 
   Accessible* mParent;
   uint32_t mStartIdx;
   uint32_t mStateFlagsCopy;
   EventTree* mEventTree;
 
-  /*
-   * True if mutation events should be queued.
-   */
-  bool mQueueEvents;
-
 #ifdef DEBUG
   bool mIsDone;
 #endif
 };
 
 
 /**
  * A mutation events coalescence structure.
@@ -67,44 +62,41 @@ class EventTree final {
 public:
   EventTree() :
     mFirst(nullptr), mNext(nullptr), mContainer(nullptr), mFireReorder(false) { }
   explicit EventTree(Accessible* aContainer, bool aFireReorder) :
     mFirst(nullptr), mNext(nullptr), mContainer(aContainer),
     mFireReorder(aFireReorder) { }
   ~EventTree() { Clear(); }
 
-  void Shown(Accessible* aTarget);
-  void Hidden(Accessible*, bool);
+  void Shown(Accessible* aChild);
+
+  void Hidden(Accessible* aChild, bool aNeedsShutdown = true);
 
   /**
    * Return an event tree node for the given accessible.
    */
   const EventTree* Find(const Accessible* aContainer) const;
 
-  /**
-   * Add a mutation event to this event tree.
-   */
-  void Mutated(AccMutationEvent* aEv);
-
 #ifdef A11Y_LOG
   void Log(uint32_t aLevel = UINT32_MAX) const;
 #endif
 
 private:
   /**
    * Processes the event queue and fires events.
    */
   void Process(const RefPtr<DocAccessible>& aDeathGrip);
 
   /**
    * Return an event subtree for the given accessible.
    */
   EventTree* FindOrInsert(Accessible* aContainer);
 
+  void Mutated(AccMutationEvent* aEv);
   void Clear();
 
   UniquePtr<EventTree> mFirst;
   UniquePtr<EventTree> mNext;
 
   Accessible* mContainer;
   nsTArray<RefPtr<AccMutationEvent>> mDependentEvents;
   bool mFireReorder;
--- a/accessible/base/NotificationController.cpp
+++ b/accessible/base/NotificationController.cpp
@@ -19,17 +19,17 @@ using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector
 ////////////////////////////////////////////////////////////////////////////////
 
 NotificationController::NotificationController(DocAccessible* aDocument,
                                                nsIPresShell* aPresShell) :
   EventQueue(aDocument), mObservingState(eNotObservingRefresh),
-  mPresShell(aPresShell), mEventGeneration(0)
+  mPresShell(aPresShell)
 {
 #ifdef DEBUG
   mMoveGuardOnStack = false;
 #endif
 
   // Schedule initial accessible tree construction.
   ScheduleProcessing();
 }
@@ -109,299 +109,16 @@ NotificationController::QueueMutation(Ac
 {
   EventTree* tree = mEventTree.FindOrInsert(aContainer);
   if (tree) {
     ScheduleProcessing();
   }
   return tree;
 }
 
-bool
-NotificationController::QueueMutationEvent(AccTreeMutationEvent* aEvent)
-{
-  // We have to allow there to be a hide and then a show event for a target
-  // because of targets getting moved.  However we need to coalesce a show and
-  // then a hide for a target which means we need to check for that here.
-  if (aEvent->GetEventType() == nsIAccessibleEvent::EVENT_HIDE  &&
-      aEvent->GetAccessible()->ShowEventTarget()) {
-    AccTreeMutationEvent* showEvent = mMutationMap.GetEvent(aEvent->GetAccessible(), EventMap::ShowEvent);
-    DropMutationEvent(showEvent);
-    return false;
-  }
-
-  AccMutationEvent* mutEvent = downcast_accEvent(aEvent);
-  mEventGeneration++;
-  mutEvent->SetEventGeneration(mEventGeneration);
-
-  if (!mFirstMutationEvent) {
-    mFirstMutationEvent = aEvent;
-    ScheduleProcessing();
-  }
-
-  if (mLastMutationEvent) {
-    NS_ASSERTION(!mLastMutationEvent->NextEvent(), "why isn't the last event the end?");
-    mLastMutationEvent->SetNextEvent(aEvent);
-  }
-
-  aEvent->SetPrevEvent(mLastMutationEvent);
-  mLastMutationEvent = aEvent;
-  mMutationMap.PutEvent(aEvent);
-
-  // Because we could be hiding the target of a show event we need to get rid
-  // of any such events.  It may be possible to do less than coallesce all
-  // events, however that is easiest.
-  if (aEvent->GetEventType() == nsIAccessibleEvent::EVENT_HIDE) {
-    CoalesceMutationEvents();
-
-    // mLastMutationEvent will point to something other than aEvent if and only
-    // if aEvent was just coalesced away.  In that case a parent accessible
-    // must already have the required reorder and text change events so we are
-    // done here.
-    if (mLastMutationEvent != aEvent) {
-      return false;
-    }
-  }
-
-  // We need to fire a reorder event after all of the events targeted at shown or
-  // hidden children of a container.  So either queue a new one, or move an
-  // existing one to the end of the queue if the container already has a
-  // reorder event.
-  Accessible* target = aEvent->GetAccessible();
-  Accessible* container = aEvent->GetAccessible()->Parent();
-  RefPtr<AccReorderEvent> reorder;
-  if (!container->ReorderEventTarget()) {
-    reorder = new AccReorderEvent(container);
-    container->SetReorderEventTarget(true);
-    mMutationMap.PutEvent(reorder);
-
-    // Since this is the first child of container that is changing, the name of
-    // container may be changing.
-    QueueNameChange(target);
-  } else {
-    AccReorderEvent* event = downcast_accEvent(mMutationMap.GetEvent(container, EventMap::ReorderEvent));
-    reorder = event;
-    if (mFirstMutationEvent == event) {
-      mFirstMutationEvent = event->NextEvent();
-    } else {
-      event->PrevEvent()->SetNextEvent(event->NextEvent());
-    }
-
-      event->NextEvent()->SetPrevEvent(event->PrevEvent());
-      event->SetNextEvent(nullptr);
-  }
-
-  reorder->SetEventGeneration(mEventGeneration);
-  reorder->SetPrevEvent(mLastMutationEvent);
-  mLastMutationEvent->SetNextEvent(reorder);
-  mLastMutationEvent = reorder;
-
-  // It is not possible to have a text change event for something other than a
-  // hyper text accessible.
-  if (!container->IsHyperText()) {
-    return true;
-  }
-
-  MOZ_ASSERT(mutEvent);
-
-  nsString text;
-  aEvent->GetAccessible()->AppendTextTo(text);
-  if (text.IsEmpty()) {
-    return true;
-  }
-
-  int32_t offset = container->AsHyperText()->GetChildOffset(target);
-  AccTreeMutationEvent* prevEvent = aEvent->PrevEvent();
-  while (prevEvent && prevEvent->GetEventType() == nsIAccessibleEvent::EVENT_REORDER) {
-    prevEvent = prevEvent->PrevEvent();
-  }
-
-  if (prevEvent && prevEvent->GetEventType() == nsIAccessibleEvent::EVENT_HIDE &&
-      mutEvent->IsHide()) {
-    AccHideEvent* prevHide = downcast_accEvent(prevEvent);
-    AccTextChangeEvent* prevTextChange = prevHide->mTextChangeEvent;
-    if (prevTextChange) {
-      if (prevHide->mNextSibling == target) {
-        target->AppendTextTo(prevTextChange->mModifiedText);
-      } else if (prevHide->mPrevSibling == target) {
-        nsString temp;
-        target->AppendTextTo(temp);
-
-        uint32_t extraLen = temp.Length();
-        temp += prevTextChange->mModifiedText;;
-        prevTextChange->mModifiedText = temp;
-        prevTextChange->mStart -= extraLen;
-      }
-
-      prevHide->mTextChangeEvent.swap(mutEvent->mTextChangeEvent);
-    }
-  } else if (prevEvent && mutEvent->IsShow() &&
-             prevEvent->GetEventType() == nsIAccessibleEvent::EVENT_SHOW) {
-    AccShowEvent* prevShow = downcast_accEvent(prevEvent);
-    AccTextChangeEvent* prevTextChange = prevShow->mTextChangeEvent;
-    if (prevTextChange) {
-      int32_t index = target->IndexInParent();
-      int32_t prevIndex = prevShow->GetAccessible()->IndexInParent();
-      if (prevIndex + 1 == index) {
-        target->AppendTextTo(prevTextChange->mModifiedText);
-      } else if (index + 1 == prevIndex) {
-        nsString temp;
-        target->AppendTextTo(temp);
-        prevTextChange->mStart -= temp.Length();
-        temp += prevTextChange->mModifiedText;
-        prevTextChange->mModifiedText = temp;
-      }
-
-      prevShow->mTextChangeEvent.swap(mutEvent->mTextChangeEvent);
-    }
-  }
-
-  if (!mutEvent->mTextChangeEvent) {
-    mutEvent->mTextChangeEvent =
-      new AccTextChangeEvent(container, offset, text, mutEvent->IsShow(),
-                             aEvent->mIsFromUserInput ? eFromUserInput : eNoUserInput);
-  }
-
-  return true;
-}
-
-void
-NotificationController::DropMutationEvent(AccTreeMutationEvent* aEvent)
-{
-  // unset the event bits since the event isn't being fired any more.
-  if (aEvent->GetEventType() == nsIAccessibleEvent::EVENT_REORDER) {
-    aEvent->GetAccessible()->SetReorderEventTarget(false);
-  } else if (aEvent->GetEventType() == nsIAccessibleEvent::EVENT_SHOW) {
-    aEvent->GetAccessible()->SetShowEventTarget(false);
-  } else {
-    AccHideEvent* hideEvent = downcast_accEvent(aEvent);
-    MOZ_ASSERT(hideEvent);
-
-    if (hideEvent->NeedsShutdown()) {
-      mDocument->ShutdownChildrenInSubtree(aEvent->GetAccessible());
-    }
-  }
-
-  // Do the work to splice the event out of the list.
-  if (mFirstMutationEvent == aEvent) {
-    mFirstMutationEvent = aEvent->NextEvent();
-  } else {
-    aEvent->PrevEvent()->SetNextEvent(aEvent->NextEvent());
-  }
-
-  if (mLastMutationEvent == aEvent) {
-    mLastMutationEvent = aEvent->PrevEvent();
-  } else {
-    aEvent->NextEvent()->SetPrevEvent(aEvent->PrevEvent());
-  }
-
-  aEvent->SetPrevEvent(nullptr);
-  aEvent->SetNextEvent(nullptr);
-  mMutationMap.RemoveEvent(aEvent);
-}
-
-void
-NotificationController::CoalesceMutationEvents()
-{
-  AccTreeMutationEvent* event = mFirstMutationEvent;
-  while (event) {
-    AccTreeMutationEvent* nextEvent = event->NextEvent();
-    uint32_t eventType = event->GetEventType();
-    if (event->GetEventType() == nsIAccessibleEvent::EVENT_REORDER) {
-      Accessible* acc = event->GetAccessible();
-      while (acc) {
-        if (acc->IsDoc()) {
-          break;
-        }
-
-        // if a parent of the reorder event's target is being hidden that
-        // hide event's target must have a parent that is also a reorder event
-        // target.  That means we don't need this reorder event.
-        if (acc->HideEventTarget()) {
-          DropMutationEvent(event);
-          break;
-        }
-
-        Accessible* parent = acc->Parent();
-        if (parent->ReorderEventTarget()) {
-          AccReorderEvent* reorder = downcast_accEvent(mMutationMap.GetEvent(parent, EventMap::ReorderEvent));
-
-          // We want to make sure that a reorder event comes after any show or
-          // hide events targeted at the children of its target.  We keep the
-          // invariant that event generation goes up as you are farther in the
-          // queue, so we want to use the spot of the event with the higher
-          // generation number, and keep that generation number.
-          if (reorder && reorder->EventGeneration() < event->EventGeneration()) {
-            // There really should be a show or hide event before the first
-            // reorder event.
-            if (reorder->PrevEvent()) {
-              reorder->PrevEvent()->SetNextEvent(reorder->NextEvent());
-            } else {
-              mFirstMutationEvent = reorder->NextEvent();
-            }
-
-            reorder->NextEvent()->SetPrevEvent(reorder->PrevEvent());
-            event->PrevEvent()->SetNextEvent(reorder);
-            reorder->SetPrevEvent(event->PrevEvent());
-            event->SetPrevEvent(reorder);
-            reorder->SetNextEvent(event);
-            reorder->SetEventGeneration(event->EventGeneration());
-          }
-          DropMutationEvent(event);
-          break;
-        }
-
-        acc = parent;
-      }
-    } else if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
-      Accessible* parent = event->GetAccessible()->Parent();
-      while (parent) {
-        if (parent->IsDoc()) {
-          break;
-        }
-
-        // if the parent of a show event is being either shown or hidden then
-        // we don't need to fire a show event for a subtree of that change.
-        if (parent->ShowEventTarget() || parent->HideEventTarget()) {
-          DropMutationEvent(event);
-          break;
-        }
-
-        parent = parent->Parent();
-      }
-    } else {
-      MOZ_ASSERT(eventType == nsIAccessibleEvent::EVENT_HIDE, "mutation event list has an invalid event");
-
-      AccHideEvent* hideEvent = downcast_accEvent(event);
-      Accessible* parent = hideEvent->Parent();
-      while (parent) {
-        if (parent->IsDoc()) {
-          break;
-        }
-
-        if (parent->HideEventTarget()) {
-          DropMutationEvent(event);
-          break;
-        }
-
-        if (parent->ShowEventTarget()) {
-          AccShowEvent* showEvent = downcast_accEvent(mMutationMap.GetEvent(parent, EventMap::ShowEvent));
-          if (showEvent->EventGeneration() < hideEvent->EventGeneration()) {
-            DropMutationEvent(hideEvent);
-            break;
-          }
-        }
-
-        parent = parent->Parent();
-      }
-    }
-
-    event = nextEvent;
-  }
-}
-
 void
 NotificationController::ScheduleChildDocBinding(DocAccessible* aDocument)
 {
   // Schedule child document binding to the tree.
   mHangingChildDocuments.AppendElement(aDocument);
   ScheduleProcessing();
 }
 
@@ -450,138 +167,16 @@ NotificationController::IsUpdatePending(
 {
   return mPresShell->IsLayoutFlushObserver() ||
     mObservingState == eRefreshProcessingForUpdate ||
     mContentInsertions.Count() != 0 || mNotifications.Length() != 0 ||
     mTextHash.Count() != 0 ||
     !mDocument->HasLoadState(DocAccessible::eTreeConstructed);
 }
 
-void
-NotificationController::ProcessMutationEvents()
-{
-  // there is no reason to fire a hide event for a child of a show event
-  // target.  That can happen if something is inserted into the tree and
-  // removed before the next refresh driver tick, but it should not be
-  // observable outside gecko so it should be safe to coalesce away any such
-  // events.  This means that it should be fine to fire all of the hide events
-  // first, and then deal with any shown subtrees.
-  for (AccTreeMutationEvent* event = mFirstMutationEvent;
-       event; event = event->NextEvent()) {
-    if (event->GetEventType() != nsIAccessibleEvent::EVENT_HIDE) {
-      continue;
-    }
-
-    nsEventShell::FireEvent(event);
-    if (!mDocument) {
-      return;
-    }
-
-    AccMutationEvent* mutEvent = downcast_accEvent(event);
-    if (mutEvent->mTextChangeEvent) {
-      nsEventShell::FireEvent(mutEvent->mTextChangeEvent);
-      if (!mDocument) {
-        return;
-      }
-    }
-
-    // Fire menupopup end event before a hide event if a menu goes away.
-
-    // XXX: We don't look into children of hidden subtree to find hiding
-    // menupopup (as we did prior bug 570275) because we don't do that when
-    // menu is showing (and that's impossible until bug 606924 is fixed).
-    // Nevertheless we should do this at least because layout coalesces
-    // the changes before our processing and we may miss some menupopup
-    // events. Now we just want to be consistent in content insertion/removal
-    // handling.
-    if (event->mAccessible->ARIARole() == roles::MENUPOPUP) {
-      nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
-                              event->mAccessible);
-      if (!mDocument) {
-        return;
-      }
-    }
-
-    AccHideEvent* hideEvent = downcast_accEvent(event);
-    if (hideEvent->NeedsShutdown()) {
-      mDocument->ShutdownChildrenInSubtree(event->mAccessible);
-    }
-  }
-
-  // Group the show events by the parent of their target.
-  nsDataHashtable<nsPtrHashKey<Accessible>, nsTArray<AccTreeMutationEvent*>> showEvents;
-  for (AccTreeMutationEvent* event = mFirstMutationEvent;
-       event; event = event->NextEvent()) {
-    if (event->GetEventType() != nsIAccessibleEvent::EVENT_SHOW) {
-      continue;
-    }
-
-    Accessible* parent = event->GetAccessible()->Parent();
-    showEvents.GetOrInsert(parent).AppendElement(event);
-  }
-
-  // We need to fire show events for the children of an accessible in the order
-  // of their indices at this point.  So sort each set of events for the same
-  // container by the index of their target.
-  for (auto iter = showEvents.Iter(); !iter.Done(); iter.Next()) {
-    struct AccIdxComparator {
-      bool LessThan(const AccTreeMutationEvent* a, const AccTreeMutationEvent* b) const
-      {
-        int32_t aIdx = a->GetAccessible()->IndexInParent();
-        int32_t bIdx = b->GetAccessible()->IndexInParent();
-        MOZ_ASSERT(aIdx >= 0 && bIdx >= 0 && aIdx != bIdx);
-        return aIdx < bIdx;
-      }
-      bool Equals(const AccTreeMutationEvent* a, const AccTreeMutationEvent* b) const
-      {
-        DebugOnly<int32_t> aIdx = a->GetAccessible()->IndexInParent();
-        DebugOnly<int32_t> bIdx = b->GetAccessible()->IndexInParent();
-        MOZ_ASSERT(aIdx >= 0 && bIdx >= 0 && aIdx != bIdx);
-        return false;
-      }
-    };
-
-    nsTArray<AccTreeMutationEvent*>& events = iter.Data();
-    events.Sort(AccIdxComparator());
-    for (AccTreeMutationEvent* event: events) {
-      nsEventShell::FireEvent(event);
-      if (!mDocument) {
-        return;
-      }
-
-      AccMutationEvent* mutEvent = downcast_accEvent(event);
-      if (mutEvent->mTextChangeEvent) {
-        nsEventShell::FireEvent(mutEvent->mTextChangeEvent);
-        if (!mDocument) {
-          return;
-        }
-      }
-    }
-  }
-
-  // Now we can fire the reorder events after all the show and hide events.
-  for (AccTreeMutationEvent* event = mFirstMutationEvent;
-       event; event = event->NextEvent()) {
-    if (event->GetEventType() != nsIAccessibleEvent::EVENT_REORDER) {
-      continue;
-    }
-
-    nsEventShell::FireEvent(event);
-    if (!mDocument) {
-      return;
-    }
-
-    Accessible* target = event->GetAccessible();
-    target->Document()->MaybeNotifyOfValueChange(target);
-    if (!mDocument) {
-      return;
-    }
-  }
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector: private
 
 void
 NotificationController::WillRefresh(mozilla::TimeStamp aTime)
 {
   PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
   Telemetry::AutoTimer<Telemetry::A11Y_UPDATE_TIME> updateTimer;
@@ -797,49 +392,19 @@ NotificationController::WillRefresh(mozi
   }
   mRelocations.Clear();
 
   // If a generic notification occurs after this point then we may be allowed to
   // process it synchronously.  However we do not want to reenter if fireing
   // events causes script to run.
   mObservingState = eRefreshProcessing;
 
-  CoalesceMutationEvents();
-  ProcessMutationEvents();
-  mEventGeneration = 0;
-
-  // Now that we are done with them get rid of the events we fired.
-  RefPtr<AccTreeMutationEvent> mutEvent = Move(mFirstMutationEvent);
-  mLastMutationEvent = nullptr;
-  mFirstMutationEvent = nullptr;
-  while (mutEvent) {
-    RefPtr<AccTreeMutationEvent> nextEvent = mutEvent->NextEvent();
-    Accessible* target = mutEvent->GetAccessible();
-
-    // We need to be careful here, while it may seem that we can simply 0 all
-    // the pending event bits that is not true.  Because accessibles may be
-    // reparented they may be the target of both a hide event and a show event
-    // at the same time.
-    if (mutEvent->GetEventType() == nsIAccessibleEvent::EVENT_SHOW) {
-      target->SetShowEventTarget(false);
-    }
-
-    if (mutEvent->GetEventType() == nsIAccessibleEvent::EVENT_HIDE) {
-      target->SetHideEventTarget(false);
-    }
-
-    // However it is not possible for a reorder event target to also be the
-    // target of a show or hide, so we can just zero that.
-    target->SetReorderEventTarget(false);
-
-    mutEvent->SetPrevEvent(nullptr);
-    mutEvent->SetNextEvent(nullptr);
-    mMutationMap.RemoveEvent(mutEvent);
-    mutEvent = nextEvent;
-  }
+  RefPtr<DocAccessible> deathGrip(mDocument);
+  mEventTree.Process(deathGrip);
+  deathGrip = nullptr;
 
   ProcessEventQueue();
 
   if (IPCAccessibilityActive()) {
     size_t newDocCount = newChildDocs.Length();
     for (size_t i = 0; i < newDocCount; i++) {
       DocAccessible* childDoc = newChildDocs[i];
       Accessible* parent = childDoc->Parent();
@@ -879,57 +444,8 @@ NotificationController::WillRefresh(mozi
   if (mContentInsertions.Count() == 0 && mNotifications.IsEmpty() &&
       mEvents.IsEmpty() && mTextHash.Count() == 0 &&
       mHangingChildDocuments.IsEmpty() &&
       mDocument->HasLoadState(DocAccessible::eCompletelyLoaded) &&
       mPresShell->RemoveRefreshObserver(this, Flush_Display)) {
     mObservingState = eNotObservingRefresh;
   }
 }
-
-void
-NotificationController::EventMap::PutEvent(AccTreeMutationEvent* aEvent)
-{
-  EventType type = GetEventType(aEvent);
-  uint64_t addr = reinterpret_cast<uintptr_t>(aEvent->GetAccessible());
-  MOZ_ASSERT((addr & 0x3) == 0, "accessible is not 4 byte aligned");
-  addr |= type;
-  mTable.Put(addr, aEvent);
-}
-
-AccTreeMutationEvent*
-NotificationController::EventMap::GetEvent(Accessible* aTarget, EventType aType)
-{
-  uint64_t addr = reinterpret_cast<uintptr_t>(aTarget);
-  MOZ_ASSERT((addr & 0x3) == 0, "target is not 4 byte aligned");
-
-  addr |= aType;
-  return mTable.GetWeak(addr);
-}
-
-void
-NotificationController::EventMap::RemoveEvent(AccTreeMutationEvent* aEvent)
-{
-  EventType type = GetEventType(aEvent);
-  uint64_t addr = reinterpret_cast<uintptr_t>(aEvent->GetAccessible());
-  MOZ_ASSERT((addr & 0x3) == 0, "accessible is not 4 byte aligned");
-  addr |= type;
-
-  MOZ_ASSERT(mTable.GetWeak(addr) == aEvent, "mTable has the wrong event");
-  mTable.Remove(addr);
-}
-
-  NotificationController::EventMap::EventType
-NotificationController::EventMap::GetEventType(AccTreeMutationEvent* aEvent)
-{
-  switch(aEvent->GetEventType())
-  {
-    case nsIAccessibleEvent::EVENT_SHOW:
-      return ShowEvent;
-    case nsIAccessibleEvent::EVENT_HIDE:
-      return HideEvent;
-    case nsIAccessibleEvent::EVENT_REORDER:
-      return ReorderEvent;
-    default:
-      MOZ_ASSERT_UNREACHABLE("event has invalid type");
-      return ShowEvent;
-  }
-}
--- a/accessible/base/NotificationController.h
+++ b/accessible/base/NotificationController.h
@@ -155,27 +155,16 @@ public:
     NotificationController* mController;
   };
 
 #ifdef A11Y_LOG
   const EventTree& RootEventTree() const { return mEventTree; };
 #endif
 
   /**
-   * Queue a mutation event to emit if not coalesced away.  Returns true if the
-   * event was queued and has not yet been coalesced.
-   */
-  bool QueueMutationEvent(AccTreeMutationEvent* aEvent);
-
-  /**
-   * Coalesce all queued mutation events.
-   */
-  void CoalesceMutationEvents();
-
-  /**
    * Schedule binding the child document to the tree of this document.
    */
   void ScheduleChildDocBinding(DocAccessible* aDocument);
 
   /**
    * Schedule the accessible tree update because of rendered text changes.
    */
   inline void ScheduleTextUpdate(nsIContent* aTextNode)
@@ -298,26 +287,16 @@ private:
   void StorePrecedingEvents(nsTArray<RefPtr<AccHideEvent>>&& aEvs)
   {
     MOZ_ASSERT(mMoveGuardOnStack, "No move guard on stack!");
     mPrecedingEvents.InsertElementsAt(0, aEvs);
   }
 
 private:
   /**
-   * get rid of a mutation event that is no longer necessary.
-   */
-  void DropMutationEvent(AccTreeMutationEvent* aEvent);
-
-  /**
-   * Fire all necessary mutation events.
-   */
-  void ProcessMutationEvents();
-
-  /**
    * Indicates whether we're waiting on an event queue processing from our
    * notification controller to flush events.
    */
   enum eObservingState {
     eNotObservingRefresh,
     eRefreshObserving,
     eRefreshProcessing,
     eRefreshProcessingForUpdate
@@ -392,48 +371,14 @@ private:
   nsTArray<RefPtr<AccHideEvent>> mPrecedingEvents;
 
 #ifdef DEBUG
   bool mMoveGuardOnStack;
 #endif
 
   friend class MoveGuard;
   friend class EventTree;
-
-  /**
-   * A list of all mutation events we may want to emit.  Ordered from the first
-   * event that should be emitted to the last one to emit.
-   */
-  RefPtr<AccTreeMutationEvent> mFirstMutationEvent;
-  RefPtr<AccTreeMutationEvent> mLastMutationEvent;
-
-  /**
-   * A class to map an accessible and event type to an event.
-   */
-  class EventMap
-  {
-  public:
-    enum EventType
-    {
-      ShowEvent = 0x0,
-      HideEvent = 0x1,
-      ReorderEvent = 0x2,
-    };
-
-    void PutEvent(AccTreeMutationEvent* aEvent);
-    AccTreeMutationEvent* GetEvent(Accessible* aTarget, EventType aType);
-    void RemoveEvent(AccTreeMutationEvent* aEvent);
-    void Clear() { mTable.Clear(); }
-
-  private:
-    EventType GetEventType(AccTreeMutationEvent* aEvent);
-
-    nsRefPtrHashtable<nsUint64HashKey, AccTreeMutationEvent> mTable;
-  };
-
-  EventMap mMutationMap;
-  uint32_t mEventGeneration;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_NotificationController_h_
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -104,18 +104,17 @@ NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Accessible)
 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(Accessible, LastRelease())
 
 Accessible::Accessible(nsIContent* aContent, DocAccessible* aDoc) :
   mContent(aContent), mDoc(aDoc),
   mParent(nullptr), mIndexInParent(-1),
   mRoleMapEntryIndex(aria::NO_ROLE_MAP_ENTRY_INDEX),
-  mStateFlags(0), mContextFlags(0), mType(0), mGenericTypes(0),
-  mReorderEventTarget(false), mShowEventTarget(false), mHideEventTarget(false)
+  mStateFlags(0), mContextFlags(0), mType(0), mGenericTypes(0)
 {
   mBits.groupInfo = nullptr;
   mInt.mIndexOfEmbeddedChild = -1;
 }
 
 Accessible::~Accessible()
 {
   NS_ASSERTION(!mDoc, "LastRelease was never called!?!");
@@ -2153,19 +2152,19 @@ Accessible::MoveChild(uint32_t aNewIndex
 {
   MOZ_ASSERT(aChild, "No child was given");
   MOZ_ASSERT(aChild->mParent == this, "A child from different subtree was given");
   MOZ_ASSERT(aChild->mIndexInParent != -1, "Unbound child was given");
   MOZ_ASSERT(static_cast<uint32_t>(aChild->mIndexInParent) != aNewIndex,
              "No move, same index");
   MOZ_ASSERT(aNewIndex <= mChildren.Length(), "Wrong new index was given");
 
-  RefPtr<AccHideEvent> hideEvent = new AccHideEvent(aChild, false);
-  if (mDoc->Controller()->QueueMutationEvent(hideEvent)) {
-    aChild->SetHideEventTarget(true);
+  EventTree* eventTree = mDoc->Controller()->QueueMutation(this);
+  if (eventTree) {
+    eventTree->Hidden(aChild, false);
   }
 
   mEmbeddedObjCollector = nullptr;
   mChildren.RemoveElementAt(aChild->mIndexInParent);
 
   uint32_t startIdx = aNewIndex, endIdx = aChild->mIndexInParent;
 
   // If the child is moved after its current position.
@@ -2187,20 +2186,20 @@ Accessible::MoveChild(uint32_t aNewIndex
   }
 
   for (uint32_t idx = startIdx; idx <= endIdx; idx++) {
     mChildren[idx]->mIndexInParent = idx;
     mChildren[idx]->mStateFlags |= eGroupInfoDirty;
     mChildren[idx]->mInt.mIndexOfEmbeddedChild = -1;
   }
 
-  RefPtr<AccShowEvent> showEvent = new AccShowEvent(aChild);
-  DebugOnly<bool> added = mDoc->Controller()->QueueMutationEvent(showEvent);
-  MOZ_ASSERT(added);
-  aChild->SetShowEventTarget(true);
+  if (eventTree) {
+    eventTree->Shown(aChild);
+    mDoc->Controller()->QueueNameChange(aChild);
+  }
 }
 
 Accessible*
 Accessible::GetChildAt(uint32_t aIndex) const
 {
   Accessible* child = mChildren.SafeElementAt(aIndex, nullptr);
   if (!child)
     return nullptr;
--- a/accessible/generic/Accessible.h
+++ b/accessible/generic/Accessible.h
@@ -951,46 +951,16 @@ public:
   bool IsARIAHidden() const { return mContextFlags & eARIAHidden; }
   void SetARIAHidden(bool aIsDefined);
 
   /**
    * Return true if the element is inside an alert.
    */
   bool IsInsideAlert() const { return mContextFlags & eInsideAlert; }
 
-  /**
-   * Return true if there is a pending reorder event for this accessible.
-   */
-  bool ReorderEventTarget() const { return mReorderEventTarget; }
-
-  /**
-   * Return true if there is a pending show event for this accessible.
-   */
-  bool ShowEventTarget() const { return mShowEventTarget; }
-
-  /**
-   * Return true if there is a pending hide event for this accessible.
-   */
-  bool HideEventTarget() const { return mHideEventTarget; }
-
-  /**
-   * Set if there is a pending reorder event for this accessible.
-   */
-  void SetReorderEventTarget(bool aTarget) { mReorderEventTarget = aTarget; }
-
-  /**
-   * Set if this accessible is a show event target.
-   */
-  void SetShowEventTarget(bool aTarget) { mShowEventTarget = aTarget; }
-
-  /**
-   * Set if this accessible is a hide event target.
-   */
-  void SetHideEventTarget(bool aTarget) { mHideEventTarget = aTarget; }
-
 protected:
   virtual ~Accessible();
 
   /**
    * Return the accessible name provided by native markup. It doesn't take
    * into account ARIA markup used to specify the name.
    */
   virtual mozilla::a11y::ENameValueFlag NativeName(nsString& aName);
@@ -1157,19 +1127,16 @@ protected:
 
   /**
    * Keep in sync with StateFlags, ContextFlags, and AccTypes.
    */
   uint32_t mStateFlags : kStateFlagsBits;
   uint32_t mContextFlags : kContextFlagsBits;
   uint32_t mType : kTypeBits;
   uint32_t mGenericTypes : kGenericTypesBits;
-  uint32_t mReorderEventTarget : 1;
-  uint32_t mShowEventTarget : 1;
-  uint32_t mHideEventTarget : 1;
 
   void StaticAsserts() const;
 
 #ifdef A11Y_LOG
   friend void logging::Tree(const char* aTitle, const char* aMsgText,
                             Accessible* aRoot,
                             logging::GetTreePrefix aPrefixFunc,
                             void* aGetTreePrefixData);
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -1855,18 +1855,18 @@ DocAccessible::ProcessContentInserted(Ac
     }
 
     if (aContainer->InsertAfter(iter.Child(), iter.ChildBefore())) {
 #ifdef A11Y_LOG
       logging::TreeInfo("accessible was inserted", 0,
                         "container", aContainer, "child", iter.Child(), nullptr);
 #endif
 
+      mt.AfterInsertion(iter.Child());
       CreateSubtree(iter.Child());
-      mt.AfterInsertion(iter.Child());
       continue;
     }
 
     MOZ_ASSERT_UNREACHABLE("accessible was rejected");
     iter.Rejected();
   } while (iter.Next());
 
   mt.Done();
@@ -1902,20 +1902,20 @@ DocAccessible::ProcessContentInserted(Ac
       child = GetAccService()->CreateAccessible(aNode, aContainer);
     }
 
     if (child) {
       TreeMutation mt(aContainer);
       if (!aContainer->InsertAfter(child, walker.Prev())) {
         return;
       }
-      CreateSubtree(child);
       mt.AfterInsertion(child);
       mt.Done();
 
+      CreateSubtree(child);
       FireEventsOnInsertion(aContainer);
     }
   }
 
 #ifdef A11Y_LOG
   logging::TreeInfo("children after insertion", logging::eVerbose, aContainer);
 #endif
 }
--- a/accessible/ipc/DocAccessibleChildBase.cpp
+++ b/accessible/ipc/DocAccessibleChildBase.cpp
@@ -80,17 +80,17 @@ DocAccessibleChildBase::SerializeTree(Ac
   }
 }
 
 void
 DocAccessibleChildBase::ShowEvent(AccShowEvent* aShowEvent)
 {
   Accessible* parent = aShowEvent->Parent();
   uint64_t parentID = parent->IsDoc() ? 0 : reinterpret_cast<uint64_t>(parent->UniqueID());
-  uint32_t idxInParent = aShowEvent->GetAccessible()->IndexInParent();
+  uint32_t idxInParent = aShowEvent->InsertionIndex();
   nsTArray<AccessibleData> shownTree;
   ShowEventData data(parentID, idxInParent, shownTree);
   SerializeTree(aShowEvent->GetAccessible(), data.NewTree());
   SendShowEvent(data, aShowEvent->IsFromUserInput());
 }
 
 } // namespace a11y
 } // namespace mozilla
--- a/accessible/tests/mochitest/events/test_aria_menu.html
+++ b/accessible/tests/mochitest/events/test_aria_menu.html
@@ -50,18 +50,18 @@
     function showMenu(aMenuID, aParentMenuID, aHow)
     {
       this.menuNode = getNode(aMenuID);
 
       // Because of aria-owns processing we may have menupopup start fired before
       // related show event.
       this.eventSeq = [
         new invokerChecker(EVENT_SHOW, this.menuNode),
-        new invokerChecker(EVENT_REORDER, getNode(aParentMenuID)),
-        new invokerChecker(EVENT_MENUPOPUP_START, this.menuNode)
+        new asyncInvokerChecker(EVENT_MENUPOPUP_START, this.menuNode),
+        new invokerChecker(EVENT_REORDER, getNode(aParentMenuID))
       ];
 
       this.invoke = function showMenu_invoke()
       {
         if (aHow == kViaDisplayStyle)
           this.menuNode.style.display = "block";
         else
           this.menuNode.style.visibility = "visible";
--- a/accessible/tests/mochitest/events/test_coalescence.html
+++ b/accessible/tests/mochitest/events/test_coalescence.html
@@ -414,18 +414,18 @@
     function test5()
     {
       this.o = getAccessible("t5_o");
       this.ofc = this.o.firstChild;
       this.b = getAccessible("t5_b");
       this.lb = getAccessible("t5_lb");
 
       this.eventSeq = [
+        new invokerChecker(EVENT_HIDE, this.o),
         new invokerChecker(EVENT_HIDE, this.b),
-        new invokerChecker(EVENT_HIDE, this.o),
         new invokerChecker(EVENT_REORDER, "t5"),
         new unexpectedInvokerChecker(EVENT_HIDE, this.ofc),
         new unexpectedInvokerChecker(EVENT_REORDER, this.o),
         new unexpectedInvokerChecker(EVENT_REORDER, this.lb)
       ];
 
       this.invoke = function test5_invoke()
       {
@@ -534,18 +534,18 @@
      * The hide event should be delivered before the paired show event.
      */
     function test8()
     {
       this.eventSeq = [
         new invokerChecker(EVENT_HIDE, getNode('t8_c1_child')),
         new invokerChecker(EVENT_HIDE, 't8_c2_moved'),
         new invokerChecker(EVENT_SHOW, 't8_c2_moved'),
-        new invokerChecker(EVENT_REORDER, 't8_c2'),
         new invokerChecker(EVENT_REORDER, 't8_c1'),
+        new invokerChecker(EVENT_REORDER, 't8_c2')
       ];
 
       this.invoke = function test8_invoke()
       {
         // Remove a node from 't8_c1' container to give the event tree a
         // desired structure (the 't8_c1' container node goes first in the event
         // tree)
         getNode('t8_c1_child').remove();
@@ -573,23 +573,23 @@
      *
      * 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, getNode('t9_c2_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_c3'),
+        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_c1'),
+        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),
@@ -619,22 +619,22 @@
      *
      * The hide events for 't10_c2_moved' and 't10_c3_moved' should be delivered
      * before the show event for 't10_c2_moved'.
      */
     function test10()
     {
       this.eventSeq = [
         new invokerChecker(EVENT_HIDE, getNode('t10_c1_child')),
-        new invokerChecker(EVENT_HIDE, getNode('t10_c2_child')),
         new invokerChecker(EVENT_HIDE, getNode('t10_c2_moved')),
         new invokerChecker(EVENT_HIDE, getNode('t10_c3_moved')),
         new invokerChecker(EVENT_SHOW, getNode('t10_c2_moved')),
+        new invokerChecker(EVENT_REORDER, 't10_c1'),
+        new invokerChecker(EVENT_HIDE, getNode('t10_c2_child')),
         new invokerChecker(EVENT_REORDER, 't10_c2'),
-        new invokerChecker(EVENT_REORDER, 't10_c1'),
         new invokerChecker(EVENT_REORDER, 't10_c3')
       ];
 
       this.invoke = function test10_invoke()
       {
         // Remove child nodes from 't10_c1' and 't10_c2' containers to give
         // the event tree a needed structure ('t10_c1' and 't10_c2' nodes go first
         // in the event tree),
@@ -654,21 +654,19 @@
      * Move a node by aria-owns from right to left in the tree, and then
      * move its parent too by aria-owns. No hide event should be fired for
      * original node.
      */
     function test11()
     {
       this.eventSeq = [
         new invokerChecker(EVENT_HIDE, getNode('t11_c1_child')),
+        new invokerChecker(EVENT_SHOW, 't11_c2_child'),
         new invokerChecker(EVENT_HIDE, getNode('t11_c2')),
-        new orderChecker(),
-        new asyncInvokerChecker(EVENT_SHOW, 't11_c2_child'),
-        new asyncInvokerChecker(EVENT_SHOW, 't11_c2'),
-        new orderChecker(),
+        new invokerChecker(EVENT_SHOW, 't11_c2'),
         new invokerChecker(EVENT_REORDER, 't11'),
         new unexpectedInvokerChecker(EVENT_HIDE, 't11_c2_child'),
         new unexpectedInvokerChecker(EVENT_REORDER, 't11_c1'),
         new unexpectedInvokerChecker(EVENT_REORDER, 't11_c2'),
         new unexpectedInvokerChecker(EVENT_REORDER, 't11_c3')
       ];
 
       this.invoke = function test11_invoke()
@@ -686,17 +684,17 @@
       this.getID = function test11_getID() {
         return "Move a node by aria-owns to left within the tree";
       };
     }
 
     ////////////////////////////////////////////////////////////////////////////
     // Do tests.
 
-    gA11yEventDumpToConsole = true; // debug stuff
+    //gA11yEventDumpToConsole = true; // debug stuff
     //enableLogging("eventTree");
 
     var gQueue = null;
     function doTests()
     {
       gQueue = new eventQueue();
 
       gQueue.push(new removeChildNParent("option1", "select1"));
--- a/accessible/tests/mochitest/events/test_mutation.html
+++ b/accessible/tests/mochitest/events/test_mutation.html
@@ -336,18 +336,18 @@
       }
     }
 
     function insertReferredElm(aContainerID)
     {
       this.containerNode = getNode(aContainerID);
 
       this.eventSeq = [
+        new invokerChecker(EVENT_SHOW, function(aNode) { return aNode.lastChild; }, this.containerNode),
         new invokerChecker(EVENT_SHOW, function(aNode) { return aNode.firstChild; }, this.containerNode),
-        new invokerChecker(EVENT_SHOW, function(aNode) { return aNode.lastChild; }, this.containerNode),
         new invokerChecker(EVENT_REORDER, this.containerNode)
       ];
 
       this.invoke = function insertReferredElm_invoke()
       {
         this.containerNode.innerHTML =
           "<span id='insertReferredElms_span'></span><input aria-labelledby='insertReferredElms_span'>";
       }
--- a/accessible/tests/mochitest/treeupdate/test_ariaowns.html
+++ b/accessible/tests/mochitest/treeupdate/test_ariaowns.html
@@ -22,21 +22,21 @@
     ////////////////////////////////////////////////////////////////////////////
     // Invokers
     ////////////////////////////////////////////////////////////////////////////
 
     function changeARIAOwns()
     {
       this.eventSeq = [
         new invokerChecker(EVENT_HIDE, getNode("t1_button")),
+        new invokerChecker(EVENT_SHOW, getNode("t1_button")),
+        new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")),
         // no hide for t1_subdiv because it is contained by hidden t1_checkbox
         new invokerChecker(EVENT_HIDE, getNode("t1_checkbox")),
         new invokerChecker(EVENT_SHOW, getNode("t1_checkbox")),
-        new invokerChecker(EVENT_SHOW, getNode("t1_button")),
-        new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")),
         new invokerChecker(EVENT_REORDER, getNode("t1_container"))
       ];
 
       this.invoke = function setARIAOwns_invoke()
       {
         // children are swapped by ARIA owns
         var tree =
           { SECTION: [
@@ -68,22 +68,20 @@
       {
         return "Change @aria-owns attribute";
       }
     }
 
     function removeARIAOwns()
     {
       this.eventSeq = [
+        new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")),
+        new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")),
         new invokerChecker(EVENT_HIDE, getNode("t1_button")),
-        new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")),
-        new orderChecker(),
-        new asyncInvokerChecker(EVENT_SHOW, getNode("t1_button")),
-        new asyncInvokerChecker(EVENT_SHOW, getNode("t1_subdiv")),
-        new orderChecker(),
+        new invokerChecker(EVENT_SHOW, getNode("t1_button")),
         new invokerChecker(EVENT_REORDER, getNode("t1_container")),
         new unexpectedInvokerChecker(EVENT_REORDER, getNode("t1_checkbox"))
       ];
 
       this.invoke = function removeARIAOwns_invoke()
       {
         getNode("t1_container").removeAttribute("aria-owns");
       }
@@ -105,18 +103,18 @@
       {
         return "Remove @aria-owns attribute";
       }
     }
 
     function setARIAOwns()
     {
       this.eventSeq = [
+        new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")),
         new invokerChecker(EVENT_HIDE, getNode("t1_button")),
-        new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")),
         new invokerChecker(EVENT_SHOW, getNode("t1_button")),
         new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")),
         new invokerChecker(EVENT_REORDER, getNode("t1_container"))
       ];
 
       this.invoke = function setARIAOwns_invoke()
       {
         getNode("t1_container").
@@ -444,19 +442,16 @@
       }
     }
 
     function rearrangeARIAOwns(aContainer, aAttr, aIdList, aRoleList)
     {
       this.eventSeq = [];
       for (var id of aIdList) {
         this.eventSeq.push(new invokerChecker(EVENT_HIDE, getNode(id)));
-      }
-
-      for (var id of aIdList) {
         this.eventSeq.push(new invokerChecker(EVENT_SHOW, getNode(id)));
       }
       this.eventSeq.push(new invokerChecker(EVENT_REORDER, getNode(aContainer)));
 
       this.invoke = function rearrangeARIAOwns_invoke()
       {
         getNode(aContainer).setAttribute("aria-owns", aAttr);
       }
--- a/accessible/tests/mochitest/treeupdate/test_bug1189277.html
+++ b/accessible/tests/mochitest/treeupdate/test_bug1189277.html
@@ -16,19 +16,19 @@
           src="../events.js"></script>
 
   <script type="application/javascript">
     function runTest()
     {
       this.containerNode = getNode("outerDiv");
 
       this.eventSeq = [
-        new invokerChecker(EVENT_HIDE, getNode("child")),
         new invokerChecker(EVENT_HIDE, getNode("childDoc")),
         new invokerChecker(EVENT_SHOW, "newChildDoc"),
+        new invokerChecker(EVENT_HIDE, getNode("child")),
         new invokerChecker(EVENT_REORDER, this.containerNode)
       ];
 
       this.invoke = function runTest_invoke()
       {
         this.containerNode.removeChild(getNode("child"));
 
         var docContainer = getNode("docContainer");
@@ -42,17 +42,17 @@
 
       this.getID = function runTest_getID()
       {
         return "check show events are not incorrectly coalesced";
       }
     }
 
     //enableLogging("tree");
-    gA11yEventDumpToConsole = true;
+    //gA11yEventDumpToConsole = true;
     var gQueue = null;
     function doTest()
     {
       gQueue = new eventQueue();
       gQueue.push(new runTest());
       gQueue.invoke(); // SimpleTest.finish();
     }
 
--- a/accessible/tests/mochitest/treeupdate/test_whitespace.html
+++ b/accessible/tests/mochitest/treeupdate/test_whitespace.html
@@ -96,19 +96,18 @@
     {
       this.containerNode = getNode("container2");
       this.topNode = this.containerNode.parentNode;
       this.textNode = this.containerNode.nextSibling;
       this.imgNode = document.createElement("img");
       this.imgNode.setAttribute("src", "../moz.png");
 
       this.eventSeq = [
-        new asyncInvokerChecker(EVENT_SHOW, getAccessible, this.textNode),
-        new asyncInvokerChecker(EVENT_SHOW, getAccessible, this.imgNode),
-        new orderChecker(),
+        new invokerChecker(EVENT_SHOW, getAccessible, this.imgNode),
+        new invokerChecker(EVENT_SHOW, getAccessible, this.textNode),
         new invokerChecker(EVENT_REORDER, this.topNode)
       ];
 
       this.invoke = function insertImg_invoke()
       {
         var tree =
           { SECTION: [
             { LINK: [] },