Ejemplo n.º 1
0
void
NotificationController::CoalesceEvents()
{
  PRUint32 numQueuedEvents = mEvents.Length();
  PRInt32 tail = numQueuedEvents - 1;
  AccEvent* tailEvent = mEvents[tail];

  // No node means this is application accessible (which can be a subject
  // of reorder events), we do not coalesce events for it currently.
  if (!tailEvent->mNode)
    return;

  switch(tailEvent->mEventRule) {
    case AccEvent::eCoalesceFromSameSubtree:
    {
      for (PRInt32 index = tail - 1; index >= 0; index--) {
        AccEvent* thisEvent = mEvents[index];

        if (thisEvent->mEventType != tailEvent->mEventType)
          continue; // Different type

        // Skip event for application accessible since no coalescence for it
        // is supported. Ignore events from different documents since we don't
        // coalesce them.
        if (!thisEvent->mNode ||
            thisEvent->mNode->GetOwnerDoc() != tailEvent->mNode->GetOwnerDoc())
          continue;

        // Coalesce earlier event for the same target.
        if (thisEvent->mNode == tailEvent->mNode) {
          thisEvent->mEventRule = AccEvent::eDoNotEmit;
          return;
        }

        // If event queue contains an event of the same type and having target
        // that is sibling of target of newly appended event then apply its
        // event rule to the newly appended event.

        // Coalesce hide and show events for sibling targets.
        if (tailEvent->mEventType == nsIAccessibleEvent::EVENT_HIDE) {
          AccHideEvent* tailHideEvent = downcast_accEvent(tailEvent);
          AccHideEvent* thisHideEvent = downcast_accEvent(thisEvent);
          if (thisHideEvent->mParent == tailHideEvent->mParent) {
            tailEvent->mEventRule = thisEvent->mEventRule;

            // Coalesce text change events for hide events.
            if (tailEvent->mEventRule != AccEvent::eDoNotEmit)
              CoalesceTextChangeEventsFor(tailHideEvent, thisHideEvent);

            return;
          }
        } else if (tailEvent->mEventType == nsIAccessibleEvent::EVENT_SHOW) {
          if (thisEvent->mAccessible->GetParent() ==
              tailEvent->mAccessible->GetParent()) {
            tailEvent->mEventRule = thisEvent->mEventRule;

            // Coalesce text change events for show events.
            if (tailEvent->mEventRule != AccEvent::eDoNotEmit) {
              AccShowEvent* tailShowEvent = downcast_accEvent(tailEvent);
              AccShowEvent* thisShowEvent = downcast_accEvent(thisEvent);
              CoalesceTextChangeEventsFor(tailShowEvent, thisShowEvent);
            }

            return;
          }
        }

        // Ignore events unattached from DOM since we don't coalesce them.
        if (!thisEvent->mNode->IsInDoc())
          continue;

        // Coalesce events by sibling targets (this is a case for reorder
        // events).
        if (thisEvent->mNode->GetNodeParent() ==
            tailEvent->mNode->GetNodeParent()) {
          tailEvent->mEventRule = thisEvent->mEventRule;
          return;
        }

        // This and tail events can be anywhere in the tree, make assumptions
        // for mutation events.

        // Coalesce tail event if tail node is descendant of this node. Stop
        // processing if tail event is coalesced since all possible descendants
        // of this node was coalesced before.
        // Note: more older hide event target (thisNode) can't contain recent
        // hide event target (tailNode), i.e. be ancestor of tailNode. Skip
        // this check for hide events.
        if (tailEvent->mEventType != nsIAccessibleEvent::EVENT_HIDE &&
            nsCoreUtils::IsAncestorOf(thisEvent->mNode, tailEvent->mNode)) {
          tailEvent->mEventRule = AccEvent::eDoNotEmit;
          return;
        }

        // If this node is a descendant of tail node then coalesce this event,
        // check other events in the queue. Do not emit thisEvent, also apply
        // this result to sibling nodes of thisNode.
        if (nsCoreUtils::IsAncestorOf(tailEvent->mNode, thisEvent->mNode)) {
          thisEvent->mEventRule = AccEvent::eDoNotEmit;
          ApplyToSiblings(0, index, thisEvent->mEventType,
                          thisEvent->mNode, AccEvent::eDoNotEmit);
          continue;
        }

      } // for (index)

    } break; // case eCoalesceFromSameSubtree

    case AccEvent::eCoalesceFromSameDocument:
    {
      // Used for focus event, coalesce more older event since focus event
      // for accessible can be duplicated by event for its document, we are
      // interested in focus event for accessible.
      for (PRInt32 index = tail - 1; index >= 0; index--) {
        AccEvent* thisEvent = mEvents[index];
        if (thisEvent->mEventType == tailEvent->mEventType &&
            thisEvent->mEventRule == tailEvent->mEventRule &&
            thisEvent->GetDocAccessible() == tailEvent->GetDocAccessible()) {
          thisEvent->mEventRule = AccEvent::eDoNotEmit;
          return;
        }
      }
    } break; // case eCoalesceFromSameDocument

    case AccEvent::eRemoveDupes:
    {
      // Check for repeat events, coalesce newly appended event by more older
      // event.
      for (PRInt32 index = tail - 1; index >= 0; 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

    default:
      break; // case eAllowDupes, eDoNotEmit
  } // switch
}
/* static */
void
nsAccEvent::ApplyEventRules(nsCOMArray<nsIAccessibleEvent> &aEventsToFire)
{
  PRUint32 numQueuedEvents = aEventsToFire.Count();
  for (PRInt32 tail = numQueuedEvents - 1; tail >= 0; tail --) {
    nsRefPtr<nsAccEvent> tailEvent = GetAccEventPtr(aEventsToFire[tail]);
    switch(tailEvent->mEventRule) {
      case nsAccEvent::eCoalesceFromSameSubtree:
      {
        for (PRInt32 index = 0; index < tail; index ++) {
          nsRefPtr<nsAccEvent> thisEvent = GetAccEventPtr(aEventsToFire[index]);
          if (thisEvent->mEventType != tailEvent->mEventType)
            continue; // Different type

          if (thisEvent->mEventRule == nsAccEvent::eAllowDupes ||
              thisEvent->mEventRule == nsAccEvent::eDoNotEmit)
            continue; //  Do not need to check

          if (thisEvent->mDOMNode == tailEvent->mDOMNode) {
            // Dupe
            thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
            continue;
          }
          if (nsAccUtils::IsAncestorOf(tailEvent->mDOMNode,
                                       thisEvent->mDOMNode)) {
            // thisDOMNode is a descendant of tailDOMNode
            // Do not emit thisEvent, also apply this result to sibling
            // nodes of thisDOMNode.
            thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
            ApplyToSiblings(aEventsToFire, 0, index, thisEvent->mEventType,
                            thisEvent->mDOMNode, nsAccEvent::eDoNotEmit);
            continue;
          }
          if (nsAccUtils::IsAncestorOf(thisEvent->mDOMNode,
                                       tailEvent->mDOMNode)) {
            // tailDOMNode is a descendant of thisDOMNode
            // Do not emit tailEvent, also apply this result to sibling
            // nodes of tailDOMNode.
            tailEvent->mEventRule = nsAccEvent::eDoNotEmit;
            ApplyToSiblings(aEventsToFire, 0, tail, tailEvent->mEventType,
                            tailEvent->mDOMNode, nsAccEvent::eDoNotEmit);
            break;
          }
        } // for (index)

        if (tailEvent->mEventRule != nsAccEvent::eDoNotEmit) {
          // Not in another event node's subtree, and no other event is in
          // this event node's subtree.
          // This event should be emitted
          // Apply this result to sibling nodes of tailDOMNode
          ApplyToSiblings(aEventsToFire, 0, tail, tailEvent->mEventType,
                          tailEvent->mDOMNode, nsAccEvent::eAllowDupes);
        }
      } break; // case eCoalesceFromSameSubtree

      case nsAccEvent::eRemoveDupes:
      {
        // Check for repeat events.
        for (PRInt32 index = 0; index < tail; index ++) {
          nsRefPtr<nsAccEvent> accEvent = GetAccEventPtr(aEventsToFire[index]);
          if (accEvent->mEventType == tailEvent->mEventType &&
              accEvent->mEventRule == tailEvent->mEventRule &&
              accEvent->mDOMNode == tailEvent->mDOMNode) {
            accEvent->mEventRule = nsAccEvent::eDoNotEmit;
          }
        }
      } break; // case eRemoveDupes
    } // switch
  } // for (tail)
}