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(); }
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 }
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 }