Exemplo n.º 1
0
void
EventTree::Process()
{
  while (mFirst) {
    // Skip a node and its subtree if its container is not in the document.
    if (mFirst->mContainer->IsInDocument()) {
      mFirst->Process();
    }
    mFirst = mFirst->mNext.forget();
  }

  MOZ_ASSERT(mContainer || mDependentEvents.IsEmpty(),
             "No container, no events");
  MOZ_ASSERT(!mContainer || !mContainer->IsDefunct(),
             "Processing events for defunct container");

  // Fire mutation events.
  uint32_t eventsCount = mDependentEvents.Length();
  for (uint32_t jdx = 0; jdx < eventsCount; jdx++) {
    AccMutationEvent* mtEvent = mDependentEvents[jdx];
    MOZ_ASSERT(mtEvent->mEventRule != AccEvent::eDoNotEmit,
               "The event shouldn't be presented in the tree");

    nsEventShell::FireEvent(mtEvent);
    if (mtEvent->mTextChangeEvent) {
      nsEventShell::FireEvent(mtEvent->mTextChangeEvent);
    }

    if (mtEvent->IsHide()) {
      // 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 (mtEvent->mAccessible->ARIARole() == roles::MENUPOPUP) {
        nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
                                mtEvent->mAccessible);
      }

      AccHideEvent* hideEvent = downcast_accEvent(mtEvent);
      if (hideEvent->NeedsShutdown()) {
        mtEvent->GetDocAccessible()->ShutdownChildrenInSubtree(mtEvent->mAccessible);
      }
    }
  }

  // Fire reorder event at last.
  if (mFireReorder) {
    MOZ_ASSERT(mContainer);
    nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_REORDER, mContainer);
    mContainer->Document()->MaybeNotifyOfValueChange(mContainer);
  }

  mDependentEvents.Clear();
}
Exemplo n.º 2
0
void
EventTree::Log(uint32_t aLevel) const
{
  if (aLevel == UINT32_MAX) {
    if (mFirst) {
      mFirst->Log(0);
    }
    return;
  }

  for (uint32_t i = 0; i < aLevel; i++) {
    printf("  ");
  }
  logging::AccessibleInfo("container", mContainer);

  for (uint32_t i = 0; i < mDependentEvents.Length(); i++) {
    AccMutationEvent* ev = mDependentEvents[i];
    if (ev->IsShow()) {
      for (uint32_t i = 0; i < aLevel + 1; i++) {
        printf("  ");
      }
      logging::AccessibleInfo("shown", ev->mAccessible);

      AccShowEvent* showEv = downcast_accEvent(ev);
      for (uint32_t i = 0; i < showEv->mPrecedingEvents.Length(); i++) {
        for (uint32_t j = 0; j < aLevel + 1; j++) {
          printf("  ");
        }
        logging::AccessibleInfo("preceding",
                                showEv->mPrecedingEvents[i]->mAccessible);
      }
    }
    else {
      for (uint32_t i = 0; i < aLevel + 1; i++) {
        printf("  ");
      }
      logging::AccessibleInfo("hidden", ev->mAccessible);
    }
  }

  if (mFirst) {
    mFirst->Log(aLevel + 1);
  }

  if (mNext) {
    mNext->Log(aLevel);
  }
}
void
EventQueue::CoalesceEvents()
{
    NS_ASSERTION(mEvents.Length(), "There should be at least one pending event!");
    uint32_t tail = mEvents.Length() - 1;
    AccEvent* tailEvent = mEvents[tail];

    switch(tailEvent->mEventRule) {
    case AccEvent::eCoalesceReorder:
        CoalesceReorderEvents(tailEvent);
        break; // case eCoalesceReorder

    case AccEvent::eCoalesceMutationTextChange:
    {
        for (uint32_t index = tail - 1; index < tail; index--) {
            AccEvent* thisEvent = mEvents[index];
            if (thisEvent->mEventRule != tailEvent->mEventRule)
                continue;

            // We don't currently coalesce text change events from show/hide events.
            if (thisEvent->mEventType != tailEvent->mEventType)
                continue;

            // Show events may be duped because of reinsertion (removal is ignored
            // because initial insertion is not processed). Ignore initial
            // insertion.
            if (thisEvent->mAccessible == tailEvent->mAccessible)
                thisEvent->mEventRule = AccEvent::eDoNotEmit;

            AccMutationEvent* tailMutationEvent = downcast_accEvent(tailEvent);
            AccMutationEvent* thisMutationEvent = downcast_accEvent(thisEvent);
            if (tailMutationEvent->mParent != thisMutationEvent->mParent)
                continue;

            // Coalesce text change events for hide and show events.
            if (thisMutationEvent->IsHide()) {
                AccHideEvent* tailHideEvent = downcast_accEvent(tailEvent);
                AccHideEvent* thisHideEvent = downcast_accEvent(thisEvent);
                CoalesceTextChangeEventsFor(tailHideEvent, thisHideEvent);
                break;
            }

            AccShowEvent* tailShowEvent = downcast_accEvent(tailEvent);
            AccShowEvent* thisShowEvent = downcast_accEvent(thisEvent);
            CoalesceTextChangeEventsFor(tailShowEvent, thisShowEvent);
            break;
        }
    }
    break; // case eCoalesceMutationTextChange

    case AccEvent::eCoalesceOfSameType:
    {
        // Coalesce old events by newer event.
        for (uint32_t index = tail - 1; index < tail; index--) {
            AccEvent* accEvent = mEvents[index];
            if (accEvent->mEventType == tailEvent->mEventType &&
                    accEvent->mEventRule == tailEvent->mEventRule) {
                accEvent->mEventRule = AccEvent::eDoNotEmit;
                return;
            }
        }
    }
    break; // case eCoalesceOfSameType

    case AccEvent::eCoalesceSelectionChange:
    {
        AccSelChangeEvent* tailSelChangeEvent = downcast_accEvent(tailEvent);
        for (uint32_t index = tail - 1; index < tail; index--) {
            AccEvent* thisEvent = mEvents[index];
            if (thisEvent->mEventRule == tailEvent->mEventRule) {
                AccSelChangeEvent* thisSelChangeEvent =
                    downcast_accEvent(thisEvent);

                // Coalesce selection change events within same control.
                if (tailSelChangeEvent->mWidget == thisSelChangeEvent->mWidget) {
                    CoalesceSelChangeEvents(tailSelChangeEvent, thisSelChangeEvent, index);
                    return;
                }
            }
        }

    }
    break; // eCoalesceSelectionChange

    case AccEvent::eCoalesceStateChange:
    {
        // If state change event is duped then ignore previous event. If state
        // change event is opposite to previous event then no event is emitted
        // (accessible state wasn't changed).
        for (uint32_t index = tail - 1; index < tail; index--) {
            AccEvent* thisEvent = mEvents[index];
            if (thisEvent->mEventRule != AccEvent::eDoNotEmit &&
                    thisEvent->mEventType == tailEvent->mEventType &&
                    thisEvent->mAccessible == tailEvent->mAccessible) {
                AccStateChangeEvent* thisSCEvent = downcast_accEvent(thisEvent);
                AccStateChangeEvent* tailSCEvent = downcast_accEvent(tailEvent);
                if (thisSCEvent->mState == tailSCEvent->mState) {
                    thisEvent->mEventRule = AccEvent::eDoNotEmit;
                    if (thisSCEvent->mIsEnabled != tailSCEvent->mIsEnabled)
                        tailEvent->mEventRule = AccEvent::eDoNotEmit;
                }
            }
        }
        break; // eCoalesceStateChange
    }

    case AccEvent::eRemoveDupes:
    {
        // Check for repeat events, coalesce newly appended event by more older
        // event.
        for (uint32_t index = tail - 1; index < tail; index--) {
            AccEvent* accEvent = mEvents[index];
            if (accEvent->mEventType == tailEvent->mEventType &&
                    accEvent->mEventRule == tailEvent->mEventRule &&
                    accEvent->mAccessible == tailEvent->mAccessible) {
                tailEvent->mEventRule = AccEvent::eDoNotEmit;
                return;
            }
        }
    }
    break; // case eRemoveDupes

    default:
        break; // case eAllowDupes, eDoNotEmit
    } // switch
}
Exemplo n.º 4
0
nsresult AccessibleWrap::HandleAccEvent(AccEvent* aEvent) {
  auto accessible = static_cast<AccessibleWrap*>(aEvent->GetAccessible());
  NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE);
  DocAccessibleWrap* doc =
      static_cast<DocAccessibleWrap*>(accessible->Document());
  if (doc) {
    switch (aEvent->GetEventType()) {
      case nsIAccessibleEvent::EVENT_FOCUS: {
        if (DocAccessibleWrap* topContentDoc =
                doc->GetTopLevelContentDoc(accessible)) {
          topContentDoc->CacheFocusPath(accessible);
        }
        break;
      }
      case nsIAccessibleEvent::EVENT_VIRTUALCURSOR_CHANGED: {
        AccVCChangeEvent* vcEvent = downcast_accEvent(aEvent);
        auto newPosition =
            static_cast<AccessibleWrap*>(vcEvent->NewAccessible());
        if (newPosition) {
          if (DocAccessibleWrap* topContentDoc =
                  doc->GetTopLevelContentDoc(accessible)) {
            topContentDoc->CacheFocusPath(newPosition);
          }
        }
        break;
      }
    }
  }

  nsresult rv = Accessible::HandleAccEvent(aEvent);
  NS_ENSURE_SUCCESS(rv, rv);

  if (IPCAccessibilityActive()) {
    return NS_OK;
  }

  // The accessible can become defunct if we have an xpcom event listener
  // which decides it would be fun to change the DOM and flush layout.
  if (accessible->IsDefunct() || !accessible->IsBoundToParent()) {
    return NS_OK;
  }

  if (doc) {
    if (!nsCoreUtils::IsContentDocument(doc->DocumentNode())) {
      return NS_OK;
    }
  }

  SessionAccessibility* sessionAcc =
      SessionAccessibility::GetInstanceFor(accessible);
  if (!sessionAcc) {
    return NS_OK;
  }

  switch (aEvent->GetEventType()) {
    case nsIAccessibleEvent::EVENT_FOCUS:
      sessionAcc->SendFocusEvent(accessible);
      break;
    case nsIAccessibleEvent::EVENT_VIRTUALCURSOR_CHANGED: {
      AccVCChangeEvent* vcEvent = downcast_accEvent(aEvent);
      auto newPosition = static_cast<AccessibleWrap*>(vcEvent->NewAccessible());
      auto oldPosition = static_cast<AccessibleWrap*>(vcEvent->OldAccessible());

      if (sessionAcc && newPosition) {
        if (oldPosition != newPosition) {
          if (vcEvent->Reason() == nsIAccessiblePivot::REASON_POINT) {
            sessionAcc->SendHoverEnterEvent(newPosition);
          } else {
            sessionAcc->SendAccessibilityFocusedEvent(newPosition);
          }
        }

        if (vcEvent->BoundaryType() != nsIAccessiblePivot::NO_BOUNDARY) {
          sessionAcc->SendTextTraversedEvent(
              newPosition, vcEvent->NewStartOffset(), vcEvent->NewEndOffset());
        }
      }
      break;
    }
    case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: {
      AccCaretMoveEvent* event = downcast_accEvent(aEvent);
      sessionAcc->SendTextSelectionChangedEvent(accessible,
                                                event->GetCaretOffset());
      break;
    }
    case nsIAccessibleEvent::EVENT_TEXT_INSERTED:
    case nsIAccessibleEvent::EVENT_TEXT_REMOVED: {
      AccTextChangeEvent* event = downcast_accEvent(aEvent);
      sessionAcc->SendTextChangedEvent(
          accessible, event->ModifiedText(), event->GetStartOffset(),
          event->GetLength(), event->IsTextInserted(),
          event->IsFromUserInput());
      break;
    }
    case nsIAccessibleEvent::EVENT_STATE_CHANGE: {
      AccStateChangeEvent* event = downcast_accEvent(aEvent);
      auto state = event->GetState();
      if (state & states::CHECKED) {
        sessionAcc->SendClickedEvent(accessible, event->IsStateEnabled());
      }

      if (state & states::SELECTED) {
        sessionAcc->SendSelectedEvent(accessible, event->IsStateEnabled());
      }

      if (state & states::BUSY) {
        sessionAcc->SendWindowStateChangedEvent(accessible);
      }
      break;
    }
    case nsIAccessibleEvent::EVENT_SCROLLING: {
      AccScrollingEvent* event = downcast_accEvent(aEvent);
      sessionAcc->SendScrollingEvent(accessible, event->ScrollX(),
                                     event->ScrollY(), event->MaxScrollX(),
                                     event->MaxScrollY());
      break;
    }
    case nsIAccessibleEvent::EVENT_SHOW:
    case nsIAccessibleEvent::EVENT_HIDE: {
      AccMutationEvent* event = downcast_accEvent(aEvent);
      auto parent = static_cast<AccessibleWrap*>(event->Parent());
      sessionAcc->SendWindowContentChangedEvent(parent);
      break;
    }
    default:
      break;
  }

  return NS_OK;
}
void
NotificationController::CoalesceEvents()
{
  uint32_t numQueuedEvents = mEvents.Length();
  int32_t tail = numQueuedEvents - 1;
  AccEvent* tailEvent = mEvents[tail];

  switch(tailEvent->mEventRule) {
    case AccEvent::eCoalesceReorder:
      CoalesceReorderEvents(tailEvent);
      break; // case eCoalesceReorder

    case AccEvent::eCoalesceMutationTextChange:
    {
      for (uint32_t index = tail - 1; index < tail; index--) {
        AccEvent* thisEvent = mEvents[index];
        if (thisEvent->mEventRule != tailEvent->mEventRule)
          continue;

        // We don't currently coalesce text change events from show/hide events.
        if (thisEvent->mEventType != tailEvent->mEventType)
          continue;

        // Show events may be duped because of reinsertion (removal is ignored
        // because initial insertion is not processed). Ignore initial
        // insertion.
        if (thisEvent->mAccessible == tailEvent->mAccessible)
          thisEvent->mEventRule = AccEvent::eDoNotEmit;

        AccMutationEvent* tailMutationEvent = downcast_accEvent(tailEvent);
        AccMutationEvent* thisMutationEvent = downcast_accEvent(thisEvent);
        if (tailMutationEvent->mParent != thisMutationEvent->mParent)
          continue;

        // Coalesce text change events for hide and show events.
        if (thisMutationEvent->IsHide()) {
          AccHideEvent* tailHideEvent = downcast_accEvent(tailEvent);
          AccHideEvent* thisHideEvent = downcast_accEvent(thisEvent);
          CoalesceTextChangeEventsFor(tailHideEvent, thisHideEvent);
          break;
        }

        AccShowEvent* tailShowEvent = downcast_accEvent(tailEvent);
        AccShowEvent* thisShowEvent = downcast_accEvent(thisEvent);
        CoalesceTextChangeEventsFor(tailShowEvent, thisShowEvent);
        break;
      }
    } break; // case eCoalesceMutationTextChange

    case AccEvent::eCoalesceOfSameType:
    {
      // Coalesce old events by newer event.
      for (uint32_t index = tail - 1; index < tail; index--) {
        AccEvent* accEvent = mEvents[index];
        if (accEvent->mEventType == tailEvent->mEventType &&
          accEvent->mEventRule == tailEvent->mEventRule) {
          accEvent->mEventRule = AccEvent::eDoNotEmit;
          return;
        }
      }
    } break; // case eCoalesceOfSameType

    case AccEvent::eRemoveDupes:
    {
      // Check for repeat events, coalesce newly appended event by more older
      // event.
      for (uint32_t index = tail - 1; index < tail; index--) {
        AccEvent* accEvent = mEvents[index];
        if (accEvent->mEventType == tailEvent->mEventType &&
            accEvent->mEventRule == tailEvent->mEventRule &&
            accEvent->mNode == tailEvent->mNode) {
          tailEvent->mEventRule = AccEvent::eDoNotEmit;
          return;
        }
      }
    } break; // case eRemoveDupes

    case AccEvent::eCoalesceSelectionChange:
    {
      AccSelChangeEvent* tailSelChangeEvent = downcast_accEvent(tailEvent);
      int32_t index = tail - 1;
      for (; index >= 0; index--) {
        AccEvent* thisEvent = mEvents[index];
        if (thisEvent->mEventRule == tailEvent->mEventRule) {
          AccSelChangeEvent* thisSelChangeEvent =
            downcast_accEvent(thisEvent);

          // Coalesce selection change events within same control.
          if (tailSelChangeEvent->mWidget == thisSelChangeEvent->mWidget) {
            CoalesceSelChangeEvents(tailSelChangeEvent, thisSelChangeEvent, index);
            return;
          }
        }
      }

    } break; // eCoalesceSelectionChange

    default:
      break; // case eAllowDupes, eDoNotEmit
  } // switch
}
Exemplo n.º 6
0
void
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;
    }
    node = &(*node)->mNext;
  }

  AccMutationEvent* prevEvent = mDependentEvents.SafeLastElement(nullptr);
  mDependentEvents.AppendElement(aEv);

  // Coalesce text change events from this hide/show event and the previous one.
  if (prevEvent && aEv->mEventType == prevEvent->mEventType) {
    if (aEv->IsHide()) {
      // XXX: we need a way to ignore SplitNode and JoinNode() when they do not
      // affect the text within the hypertext.
      AccTextChangeEvent* prevTextEvent = prevEvent->mTextChangeEvent;
      if (prevTextEvent) {
        AccHideEvent* hideEvent = downcast_accEvent(aEv);
        AccHideEvent* prevHideEvent = downcast_accEvent(prevEvent);

        if (prevHideEvent->mNextSibling == hideEvent->mAccessible) {
          hideEvent->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
        }
        else if (prevHideEvent->mPrevSibling == hideEvent->mAccessible) {
          uint32_t oldLen = prevTextEvent->GetLength();
          hideEvent->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
          prevTextEvent->mStart -= prevTextEvent->GetLength() - oldLen;
        }

        hideEvent->mTextChangeEvent.swap(prevEvent->mTextChangeEvent);
      }
    }
    else {
      AccTextChangeEvent* prevTextEvent = prevEvent->mTextChangeEvent;
      if (prevTextEvent) {
        if (aEv->mAccessible->IndexInParent() ==
            prevEvent->mAccessible->IndexInParent() + 1) {
          // If tail target was inserted after this target, i.e. tail target is next
          // sibling of this target.
          aEv->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
        }
        else if (aEv->mAccessible->IndexInParent() ==
                 prevEvent->mAccessible->IndexInParent() - 1) {
          // If tail target was inserted before this target, i.e. tail target is
          // previous sibling of this target.
          nsAutoString startText;
          aEv->mAccessible->AppendTextTo(startText);
          prevTextEvent->mModifiedText = startText + prevTextEvent->mModifiedText;
          prevTextEvent->mStart -= startText.Length();
        }

        aEv->mTextChangeEvent.swap(prevEvent->mTextChangeEvent);
      }
    }
  }

  // Create a text change event caused by this hide/show event. When a node is
  // hidden/removed or shown/appended, the text in an ancestor hyper text will
  // lose or get new characters.
  if (aEv->mTextChangeEvent || !mContainer->IsHyperText()) {
    return;
  }

  nsAutoString text;
  aEv->mAccessible->AppendTextTo(text);
  if (text.IsEmpty()) {
    return;
  }

  int32_t offset = mContainer->AsHyperText()->GetChildOffset(aEv->mAccessible);
  aEv->mTextChangeEvent =
    new AccTextChangeEvent(mContainer, offset, text, aEv->IsShow(),
                           aEv->mIsFromUserInput ? eFromUserInput : eNoUserInput);
}
Exemplo n.º 7
0
EventTree*
EventTree::FindOrInsert(Accessible* aContainer)
{
  if (!mFirst) {
    mFirst.reset(new EventTree(aContainer, mDependentEvents.IsEmpty()));
    return mFirst.get();
  }

  EventTree* prevNode = nullptr;
  EventTree* node = mFirst.get();
  do {
    MOZ_ASSERT(!node->mContainer->IsApplication(),
               "No event for application accessible is expected here");
    MOZ_ASSERT(!node->mContainer->IsDefunct(), "An event target has to be alive");

    // Case of same target.
    if (node->mContainer == aContainer) {
      return node;
    }

    // Check if the given container is contained by a current node
    Accessible* top = mContainer ? mContainer : aContainer->Document();
    Accessible* parent = aContainer;
    while (parent) {
      // Reached a top, no match for a current event.
      if (parent == top) {
        break;
      }

      // We got a match.
      if (parent->Parent() == node->mContainer) {
        // Reject the node if it's contained by a show/hide event target
        uint32_t evCount = node->mDependentEvents.Length();
        for (uint32_t idx = 0; idx < evCount; idx++) {
          AccMutationEvent* ev = node->mDependentEvents[idx];
          if (ev->GetAccessible() == parent) {
#ifdef A11Y_LOG
            if (logging::IsEnabled(logging::eEventTree)) {
              logging::MsgBegin("EVENTS_TREE",
                "Rejecting node contained by show/hide");
              logging::AccessibleInfo("Node", aContainer);
              logging::MsgEnd();
            }
#endif
            // If the node is rejected, then check if it has related hide event
            // on stack, and if so, then connect it to the parent show event.
            if (ev->IsShow()) {
              AccShowEvent* showEv = downcast_accEvent(ev);
              Controller(aContainer)->
                WithdrawPrecedingEvents(&showEv->mPrecedingEvents);
            }
            return nullptr;
          }
        }

        return node->FindOrInsert(aContainer);
      }

      parent = parent->Parent();
      MOZ_ASSERT(parent, "Wrong tree");
    }

    // If the given container contains a current node
    // then
    //   if show or hide of the given node contains a grand parent of the current node
    //   then ignore the current node and its show and hide events
    //   otherwise ignore the current node, but not its show and hide events
    Accessible* curParent = node->mContainer;
    while (curParent && !curParent->IsDoc()) {
      if (curParent->Parent() != aContainer) {
        curParent = curParent->Parent();
        continue;
      }

      // Insert the tail node into the hierarchy between the current node and
      // its parent.
      node->mFireReorder = false;
      UniquePtr<EventTree>& nodeOwnerRef = prevNode ? prevNode->mNext : mFirst;
      UniquePtr<EventTree> newNode(new EventTree(aContainer, mDependentEvents.IsEmpty()));
      newNode->mFirst = Move(nodeOwnerRef);
      nodeOwnerRef = Move(newNode);
      nodeOwnerRef->mNext = Move(node->mNext);

      // Check if a next node is contained by the given node too, and move them
      // under the given node if so.
      prevNode = nodeOwnerRef.get();
      node = nodeOwnerRef->mNext.get();
      UniquePtr<EventTree>* nodeRef = &nodeOwnerRef->mNext;
      EventTree* insNode = nodeOwnerRef->mFirst.get();
      while (node) {
        Accessible* curParent = node->mContainer;
        while (curParent && !curParent->IsDoc()) {
          if (curParent->Parent() != aContainer) {
            curParent = curParent->Parent();
            continue;
          }

          MOZ_ASSERT(!insNode->mNext);

          node->mFireReorder = false;
          insNode->mNext = Move(*nodeRef);
          insNode = insNode->mNext.get();

          prevNode->mNext = Move(node->mNext);
          node = prevNode;
          break;
        }

        prevNode = node;
        nodeRef = &node->mNext;
        node = node->mNext.get();
      }

      return nodeOwnerRef.get();
    }

    prevNode = node;
  } while ((node = node->mNext.get()));

  MOZ_ASSERT(prevNode, "Nowhere to insert");
  MOZ_ASSERT(!prevNode->mNext, "Taken by another node");

  // If 'this' node contains the given container accessible, then
  //   do not emit a reorder event for the container
  //   if a dependent show event target contains the given container then do not
  //   emit show / hide events (see Process() method)

  prevNode->mNext.reset(new EventTree(aContainer, mDependentEvents.IsEmpty()));
  return prevNode->mNext.get();
}