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 }