1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/accessible/src/base/EventQueue.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,559 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "EventQueue.h" 1.10 + 1.11 +#include "Accessible-inl.h" 1.12 +#include "nsEventShell.h" 1.13 +#include "DocAccessible.h" 1.14 +#include "nsAccessibilityService.h" 1.15 +#include "nsTextEquivUtils.h" 1.16 +#ifdef A11Y_LOG 1.17 +#include "Logging.h" 1.18 +#endif 1.19 + 1.20 +using namespace mozilla; 1.21 +using namespace mozilla::a11y; 1.22 + 1.23 +// Defines the number of selection add/remove events in the queue when they 1.24 +// aren't packed into single selection within event. 1.25 +const unsigned int kSelChangeCountToPack = 5; 1.26 + 1.27 +//////////////////////////////////////////////////////////////////////////////// 1.28 +// EventQueue 1.29 +//////////////////////////////////////////////////////////////////////////////// 1.30 + 1.31 +bool 1.32 +EventQueue::PushEvent(AccEvent* aEvent) 1.33 +{ 1.34 + NS_ASSERTION((aEvent->mAccessible && aEvent->mAccessible->IsApplication()) || 1.35 + aEvent->GetDocAccessible() == mDocument, 1.36 + "Queued event belongs to another document!"); 1.37 + 1.38 + if (!mEvents.AppendElement(aEvent)) 1.39 + return false; 1.40 + 1.41 + // Filter events. 1.42 + CoalesceEvents(); 1.43 + 1.44 + // Fire name change event on parent given that this event hasn't been 1.45 + // coalesced, the parent's name was calculated from its subtree, and the 1.46 + // subtree was changed. 1.47 + Accessible* target = aEvent->mAccessible; 1.48 + if (aEvent->mEventRule != AccEvent::eDoNotEmit && 1.49 + target->HasNameDependentParent() && 1.50 + (aEvent->mEventType == nsIAccessibleEvent::EVENT_NAME_CHANGE || 1.51 + aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_REMOVED || 1.52 + aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_INSERTED || 1.53 + aEvent->mEventType == nsIAccessibleEvent::EVENT_SHOW || 1.54 + aEvent->mEventType == nsIAccessibleEvent::EVENT_HIDE)) { 1.55 + // Only continue traversing up the tree if it's possible that the parent 1.56 + // accessible's name can depend on this accessible's name. 1.57 + Accessible* parent = target->Parent(); 1.58 + while (parent && 1.59 + nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeIfReqRule)) { 1.60 + // Test possible name dependent parent. 1.61 + if (nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeRule)) { 1.62 + nsAutoString name; 1.63 + ENameValueFlag nameFlag = parent->Name(name); 1.64 + // If name is obtained from subtree, fire name change event. 1.65 + if (nameFlag == eNameFromSubtree) { 1.66 + nsRefPtr<AccEvent> nameChangeEvent = 1.67 + new AccEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, parent); 1.68 + PushEvent(nameChangeEvent); 1.69 + } 1.70 + break; 1.71 + } 1.72 + parent = parent->Parent(); 1.73 + } 1.74 + } 1.75 + 1.76 + // Associate text change with hide event if it wasn't stolen from hiding 1.77 + // siblings during coalescence. 1.78 + AccMutationEvent* showOrHideEvent = downcast_accEvent(aEvent); 1.79 + if (showOrHideEvent && !showOrHideEvent->mTextChangeEvent) 1.80 + CreateTextChangeEventFor(showOrHideEvent); 1.81 + 1.82 + return true; 1.83 +} 1.84 + 1.85 +//////////////////////////////////////////////////////////////////////////////// 1.86 +// EventQueue: private 1.87 + 1.88 +void 1.89 +EventQueue::CoalesceEvents() 1.90 +{ 1.91 + NS_ASSERTION(mEvents.Length(), "There should be at least one pending event!"); 1.92 + uint32_t tail = mEvents.Length() - 1; 1.93 + AccEvent* tailEvent = mEvents[tail]; 1.94 + 1.95 + switch(tailEvent->mEventRule) { 1.96 + case AccEvent::eCoalesceReorder: 1.97 + CoalesceReorderEvents(tailEvent); 1.98 + break; // case eCoalesceReorder 1.99 + 1.100 + case AccEvent::eCoalesceMutationTextChange: 1.101 + { 1.102 + for (uint32_t index = tail - 1; index < tail; index--) { 1.103 + AccEvent* thisEvent = mEvents[index]; 1.104 + if (thisEvent->mEventRule != tailEvent->mEventRule) 1.105 + continue; 1.106 + 1.107 + // We don't currently coalesce text change events from show/hide events. 1.108 + if (thisEvent->mEventType != tailEvent->mEventType) 1.109 + continue; 1.110 + 1.111 + // Show events may be duped because of reinsertion (removal is ignored 1.112 + // because initial insertion is not processed). Ignore initial 1.113 + // insertion. 1.114 + if (thisEvent->mAccessible == tailEvent->mAccessible) 1.115 + thisEvent->mEventRule = AccEvent::eDoNotEmit; 1.116 + 1.117 + AccMutationEvent* tailMutationEvent = downcast_accEvent(tailEvent); 1.118 + AccMutationEvent* thisMutationEvent = downcast_accEvent(thisEvent); 1.119 + if (tailMutationEvent->mParent != thisMutationEvent->mParent) 1.120 + continue; 1.121 + 1.122 + // Coalesce text change events for hide and show events. 1.123 + if (thisMutationEvent->IsHide()) { 1.124 + AccHideEvent* tailHideEvent = downcast_accEvent(tailEvent); 1.125 + AccHideEvent* thisHideEvent = downcast_accEvent(thisEvent); 1.126 + CoalesceTextChangeEventsFor(tailHideEvent, thisHideEvent); 1.127 + break; 1.128 + } 1.129 + 1.130 + AccShowEvent* tailShowEvent = downcast_accEvent(tailEvent); 1.131 + AccShowEvent* thisShowEvent = downcast_accEvent(thisEvent); 1.132 + CoalesceTextChangeEventsFor(tailShowEvent, thisShowEvent); 1.133 + break; 1.134 + } 1.135 + } break; // case eCoalesceMutationTextChange 1.136 + 1.137 + case AccEvent::eCoalesceOfSameType: 1.138 + { 1.139 + // Coalesce old events by newer event. 1.140 + for (uint32_t index = tail - 1; index < tail; index--) { 1.141 + AccEvent* accEvent = mEvents[index]; 1.142 + if (accEvent->mEventType == tailEvent->mEventType && 1.143 + accEvent->mEventRule == tailEvent->mEventRule) { 1.144 + accEvent->mEventRule = AccEvent::eDoNotEmit; 1.145 + return; 1.146 + } 1.147 + } 1.148 + } break; // case eCoalesceOfSameType 1.149 + 1.150 + case AccEvent::eCoalesceSelectionChange: 1.151 + { 1.152 + AccSelChangeEvent* tailSelChangeEvent = downcast_accEvent(tailEvent); 1.153 + for (uint32_t index = tail - 1; index < tail; index--) { 1.154 + AccEvent* thisEvent = mEvents[index]; 1.155 + if (thisEvent->mEventRule == tailEvent->mEventRule) { 1.156 + AccSelChangeEvent* thisSelChangeEvent = 1.157 + downcast_accEvent(thisEvent); 1.158 + 1.159 + // Coalesce selection change events within same control. 1.160 + if (tailSelChangeEvent->mWidget == thisSelChangeEvent->mWidget) { 1.161 + CoalesceSelChangeEvents(tailSelChangeEvent, thisSelChangeEvent, index); 1.162 + return; 1.163 + } 1.164 + } 1.165 + } 1.166 + 1.167 + } break; // eCoalesceSelectionChange 1.168 + 1.169 + case AccEvent::eCoalesceStateChange: 1.170 + { 1.171 + // If state change event is duped then ignore previous event. If state 1.172 + // change event is opposite to previous event then no event is emitted 1.173 + // (accessible state wasn't changed). 1.174 + for (uint32_t index = tail - 1; index < tail; index--) { 1.175 + AccEvent* thisEvent = mEvents[index]; 1.176 + if (thisEvent->mEventRule != AccEvent::eDoNotEmit && 1.177 + thisEvent->mEventType == tailEvent->mEventType && 1.178 + thisEvent->mAccessible == tailEvent->mAccessible) { 1.179 + AccStateChangeEvent* thisSCEvent = downcast_accEvent(thisEvent); 1.180 + AccStateChangeEvent* tailSCEvent = downcast_accEvent(tailEvent); 1.181 + if (thisSCEvent->mState == tailSCEvent->mState) { 1.182 + thisEvent->mEventRule = AccEvent::eDoNotEmit; 1.183 + if (thisSCEvent->mIsEnabled != tailSCEvent->mIsEnabled) 1.184 + tailEvent->mEventRule = AccEvent::eDoNotEmit; 1.185 + } 1.186 + } 1.187 + } 1.188 + break; // eCoalesceStateChange 1.189 + } 1.190 + 1.191 + case AccEvent::eCoalesceTextSelChange: 1.192 + { 1.193 + // Coalesce older event by newer event for the same selection or target. 1.194 + // Events for same selection may have different targets and vice versa one 1.195 + // target may be pointed by different selections (for latter see 1.196 + // bug 927159). 1.197 + for (uint32_t index = tail - 1; index < tail; index--) { 1.198 + AccEvent* thisEvent = mEvents[index]; 1.199 + if (thisEvent->mEventRule != AccEvent::eDoNotEmit && 1.200 + thisEvent->mEventType == tailEvent->mEventType) { 1.201 + AccTextSelChangeEvent* thisTSCEvent = downcast_accEvent(thisEvent); 1.202 + AccTextSelChangeEvent* tailTSCEvent = downcast_accEvent(tailEvent); 1.203 + if (thisTSCEvent->mSel == tailTSCEvent->mSel || 1.204 + thisEvent->mAccessible == tailEvent->mAccessible) 1.205 + thisEvent->mEventRule = AccEvent::eDoNotEmit; 1.206 + } 1.207 + 1.208 + } 1.209 + } break; // eCoalesceTextSelChange 1.210 + 1.211 + case AccEvent::eRemoveDupes: 1.212 + { 1.213 + // Check for repeat events, coalesce newly appended event by more older 1.214 + // event. 1.215 + for (uint32_t index = tail - 1; index < tail; index--) { 1.216 + AccEvent* accEvent = mEvents[index]; 1.217 + if (accEvent->mEventType == tailEvent->mEventType && 1.218 + accEvent->mEventRule == tailEvent->mEventRule && 1.219 + accEvent->mAccessible == tailEvent->mAccessible) { 1.220 + tailEvent->mEventRule = AccEvent::eDoNotEmit; 1.221 + return; 1.222 + } 1.223 + } 1.224 + } break; // case eRemoveDupes 1.225 + 1.226 + default: 1.227 + break; // case eAllowDupes, eDoNotEmit 1.228 + } // switch 1.229 +} 1.230 + 1.231 +void 1.232 +EventQueue::CoalesceReorderEvents(AccEvent* aTailEvent) 1.233 +{ 1.234 + uint32_t count = mEvents.Length(); 1.235 + for (uint32_t index = count - 2; index < count; index--) { 1.236 + AccEvent* thisEvent = mEvents[index]; 1.237 + 1.238 + // Skip events of different types and targeted to application accessible. 1.239 + if (thisEvent->mEventType != aTailEvent->mEventType || 1.240 + thisEvent->mAccessible->IsApplication()) 1.241 + continue; 1.242 + 1.243 + // If thisEvent target is not in document longer, i.e. if it was 1.244 + // removed from the tree then do not emit the event. 1.245 + if (!thisEvent->mAccessible->IsDoc() && 1.246 + !thisEvent->mAccessible->IsInDocument()) { 1.247 + thisEvent->mEventRule = AccEvent::eDoNotEmit; 1.248 + continue; 1.249 + } 1.250 + 1.251 + // Coalesce earlier event of the same target. 1.252 + if (thisEvent->mAccessible == aTailEvent->mAccessible) { 1.253 + if (thisEvent->mEventRule == AccEvent::eDoNotEmit) { 1.254 + AccReorderEvent* tailReorder = downcast_accEvent(aTailEvent); 1.255 + tailReorder->DoNotEmitAll(); 1.256 + } else { 1.257 + thisEvent->mEventRule = AccEvent::eDoNotEmit; 1.258 + } 1.259 + 1.260 + return; 1.261 + } 1.262 + 1.263 + // If tailEvent contains thisEvent 1.264 + // then 1.265 + // if show or hide of tailEvent contains a grand parent of thisEvent 1.266 + // then ignore thisEvent and its show and hide events 1.267 + // otherwise ignore thisEvent but not its show and hide events 1.268 + Accessible* thisParent = thisEvent->mAccessible; 1.269 + while (thisParent && thisParent != mDocument) { 1.270 + if (thisParent->Parent() == aTailEvent->mAccessible) { 1.271 + AccReorderEvent* tailReorder = downcast_accEvent(aTailEvent); 1.272 + uint32_t eventType = tailReorder->IsShowHideEventTarget(thisParent); 1.273 + 1.274 + // Sometimes InvalidateChildren() and 1.275 + // DocAccessible::CacheChildrenInSubtree() can conspire to reparent an 1.276 + // accessible in this case no need for mutation events. Se bug 883708 1.277 + // for details. 1.278 + if (eventType == nsIAccessibleEvent::EVENT_SHOW || 1.279 + eventType == nsIAccessibleEvent::EVENT_HIDE) { 1.280 + AccReorderEvent* thisReorder = downcast_accEvent(thisEvent); 1.281 + thisReorder->DoNotEmitAll(); 1.282 + } else { 1.283 + thisEvent->mEventRule = AccEvent::eDoNotEmit; 1.284 + } 1.285 + 1.286 + return; 1.287 + } 1.288 + 1.289 + thisParent = thisParent->Parent(); 1.290 + } 1.291 + 1.292 + // If tailEvent is contained by thisEvent 1.293 + // then 1.294 + // if show of thisEvent contains the tailEvent 1.295 + // then ignore tailEvent 1.296 + // if hide of thisEvent contains the tailEvent 1.297 + // then assert 1.298 + // otherwise ignore tailEvent but not its show and hide events 1.299 + Accessible* tailParent = aTailEvent->mAccessible; 1.300 + while (tailParent && tailParent != mDocument) { 1.301 + if (tailParent->Parent() == thisEvent->mAccessible) { 1.302 + AccReorderEvent* thisReorder = downcast_accEvent(thisEvent); 1.303 + AccReorderEvent* tailReorder = downcast_accEvent(aTailEvent); 1.304 + uint32_t eventType = thisReorder->IsShowHideEventTarget(tailParent); 1.305 + if (eventType == nsIAccessibleEvent::EVENT_SHOW) 1.306 + tailReorder->DoNotEmitAll(); 1.307 + else if (eventType == nsIAccessibleEvent::EVENT_HIDE) 1.308 + NS_ERROR("Accessible tree was modified after it was removed! Huh?"); 1.309 + else 1.310 + aTailEvent->mEventRule = AccEvent::eDoNotEmit; 1.311 + 1.312 + return; 1.313 + } 1.314 + 1.315 + tailParent = tailParent->Parent(); 1.316 + } 1.317 + 1.318 + } // for (index) 1.319 +} 1.320 + 1.321 +void 1.322 +EventQueue::CoalesceSelChangeEvents(AccSelChangeEvent* aTailEvent, 1.323 + AccSelChangeEvent* aThisEvent, 1.324 + uint32_t aThisIndex) 1.325 +{ 1.326 + aTailEvent->mPreceedingCount = aThisEvent->mPreceedingCount + 1; 1.327 + 1.328 + // Pack all preceding events into single selection within event 1.329 + // when we receive too much selection add/remove events. 1.330 + if (aTailEvent->mPreceedingCount >= kSelChangeCountToPack) { 1.331 + aTailEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION_WITHIN; 1.332 + aTailEvent->mAccessible = aTailEvent->mWidget; 1.333 + aThisEvent->mEventRule = AccEvent::eDoNotEmit; 1.334 + 1.335 + // Do not emit any preceding selection events for same widget if they 1.336 + // weren't coalesced yet. 1.337 + if (aThisEvent->mEventType != nsIAccessibleEvent::EVENT_SELECTION_WITHIN) { 1.338 + for (uint32_t jdx = aThisIndex - 1; jdx < aThisIndex; jdx--) { 1.339 + AccEvent* prevEvent = mEvents[jdx]; 1.340 + if (prevEvent->mEventRule == aTailEvent->mEventRule) { 1.341 + AccSelChangeEvent* prevSelChangeEvent = 1.342 + downcast_accEvent(prevEvent); 1.343 + if (prevSelChangeEvent->mWidget == aTailEvent->mWidget) 1.344 + prevSelChangeEvent->mEventRule = AccEvent::eDoNotEmit; 1.345 + } 1.346 + } 1.347 + } 1.348 + return; 1.349 + } 1.350 + 1.351 + // Pack sequential selection remove and selection add events into 1.352 + // single selection change event. 1.353 + if (aTailEvent->mPreceedingCount == 1 && 1.354 + aTailEvent->mItem != aThisEvent->mItem) { 1.355 + if (aTailEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd && 1.356 + aThisEvent->mSelChangeType == AccSelChangeEvent::eSelectionRemove) { 1.357 + aThisEvent->mEventRule = AccEvent::eDoNotEmit; 1.358 + aTailEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION; 1.359 + aTailEvent->mPackedEvent = aThisEvent; 1.360 + return; 1.361 + } 1.362 + 1.363 + if (aThisEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd && 1.364 + aTailEvent->mSelChangeType == AccSelChangeEvent::eSelectionRemove) { 1.365 + aTailEvent->mEventRule = AccEvent::eDoNotEmit; 1.366 + aThisEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION; 1.367 + aThisEvent->mPackedEvent = aTailEvent; 1.368 + return; 1.369 + } 1.370 + } 1.371 + 1.372 + // Unpack the packed selection change event because we've got one 1.373 + // more selection add/remove. 1.374 + if (aThisEvent->mEventType == nsIAccessibleEvent::EVENT_SELECTION) { 1.375 + if (aThisEvent->mPackedEvent) { 1.376 + aThisEvent->mPackedEvent->mEventType = 1.377 + aThisEvent->mPackedEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd ? 1.378 + nsIAccessibleEvent::EVENT_SELECTION_ADD : 1.379 + nsIAccessibleEvent::EVENT_SELECTION_REMOVE; 1.380 + 1.381 + aThisEvent->mPackedEvent->mEventRule = 1.382 + AccEvent::eCoalesceSelectionChange; 1.383 + 1.384 + aThisEvent->mPackedEvent = nullptr; 1.385 + } 1.386 + 1.387 + aThisEvent->mEventType = 1.388 + aThisEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd ? 1.389 + nsIAccessibleEvent::EVENT_SELECTION_ADD : 1.390 + nsIAccessibleEvent::EVENT_SELECTION_REMOVE; 1.391 + 1.392 + return; 1.393 + } 1.394 + 1.395 + // Convert into selection add since control has single selection but other 1.396 + // selection events for this control are queued. 1.397 + if (aTailEvent->mEventType == nsIAccessibleEvent::EVENT_SELECTION) 1.398 + aTailEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION_ADD; 1.399 +} 1.400 + 1.401 +void 1.402 +EventQueue::CoalesceTextChangeEventsFor(AccHideEvent* aTailEvent, 1.403 + AccHideEvent* aThisEvent) 1.404 +{ 1.405 + // XXX: we need a way to ignore SplitNode and JoinNode() when they do not 1.406 + // affect the text within the hypertext. 1.407 + 1.408 + AccTextChangeEvent* textEvent = aThisEvent->mTextChangeEvent; 1.409 + if (!textEvent) 1.410 + return; 1.411 + 1.412 + if (aThisEvent->mNextSibling == aTailEvent->mAccessible) { 1.413 + aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText); 1.414 + 1.415 + } else if (aThisEvent->mPrevSibling == aTailEvent->mAccessible) { 1.416 + uint32_t oldLen = textEvent->GetLength(); 1.417 + aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText); 1.418 + textEvent->mStart -= textEvent->GetLength() - oldLen; 1.419 + } 1.420 + 1.421 + aTailEvent->mTextChangeEvent.swap(aThisEvent->mTextChangeEvent); 1.422 +} 1.423 + 1.424 +void 1.425 +EventQueue::CoalesceTextChangeEventsFor(AccShowEvent* aTailEvent, 1.426 + AccShowEvent* aThisEvent) 1.427 +{ 1.428 + AccTextChangeEvent* textEvent = aThisEvent->mTextChangeEvent; 1.429 + if (!textEvent) 1.430 + return; 1.431 + 1.432 + if (aTailEvent->mAccessible->IndexInParent() == 1.433 + aThisEvent->mAccessible->IndexInParent() + 1) { 1.434 + // If tail target was inserted after this target, i.e. tail target is next 1.435 + // sibling of this target. 1.436 + aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText); 1.437 + 1.438 + } else if (aTailEvent->mAccessible->IndexInParent() == 1.439 + aThisEvent->mAccessible->IndexInParent() -1) { 1.440 + // If tail target was inserted before this target, i.e. tail target is 1.441 + // previous sibling of this target. 1.442 + nsAutoString startText; 1.443 + aTailEvent->mAccessible->AppendTextTo(startText); 1.444 + textEvent->mModifiedText = startText + textEvent->mModifiedText; 1.445 + textEvent->mStart -= startText.Length(); 1.446 + } 1.447 + 1.448 + aTailEvent->mTextChangeEvent.swap(aThisEvent->mTextChangeEvent); 1.449 +} 1.450 + 1.451 +void 1.452 +EventQueue::CreateTextChangeEventFor(AccMutationEvent* aEvent) 1.453 +{ 1.454 + Accessible* container = aEvent->mAccessible->Parent(); 1.455 + if (!container) 1.456 + return; 1.457 + 1.458 + HyperTextAccessible* textAccessible = container->AsHyperText(); 1.459 + if (!textAccessible) 1.460 + return; 1.461 + 1.462 + // Don't fire event for the first html:br in an editor. 1.463 + if (aEvent->mAccessible->Role() == roles::WHITESPACE) { 1.464 + nsCOMPtr<nsIEditor> editor = textAccessible->GetEditor(); 1.465 + if (editor) { 1.466 + bool isEmpty = false; 1.467 + editor->GetDocumentIsEmpty(&isEmpty); 1.468 + if (isEmpty) 1.469 + return; 1.470 + } 1.471 + } 1.472 + 1.473 + int32_t offset = textAccessible->GetChildOffset(aEvent->mAccessible); 1.474 + 1.475 + nsAutoString text; 1.476 + aEvent->mAccessible->AppendTextTo(text); 1.477 + if (text.IsEmpty()) 1.478 + return; 1.479 + 1.480 + aEvent->mTextChangeEvent = 1.481 + new AccTextChangeEvent(textAccessible, offset, text, aEvent->IsShow(), 1.482 + aEvent->mIsFromUserInput ? eFromUserInput : eNoUserInput); 1.483 +} 1.484 + 1.485 +//////////////////////////////////////////////////////////////////////////////// 1.486 +// EventQueue: event queue 1.487 + 1.488 +void 1.489 +EventQueue::ProcessEventQueue() 1.490 +{ 1.491 + // Process only currently queued events. 1.492 + nsTArray<nsRefPtr<AccEvent> > events; 1.493 + events.SwapElements(mEvents); 1.494 + 1.495 + uint32_t eventCount = events.Length(); 1.496 +#ifdef A11Y_LOG 1.497 + if (eventCount > 0 && logging::IsEnabled(logging::eEvents)) { 1.498 + logging::MsgBegin("EVENTS", "events processing"); 1.499 + logging::Address("document", mDocument); 1.500 + logging::MsgEnd(); 1.501 + } 1.502 +#endif 1.503 + 1.504 + for (uint32_t idx = 0; idx < eventCount; idx++) { 1.505 + AccEvent* event = events[idx]; 1.506 + if (event->mEventRule != AccEvent::eDoNotEmit) { 1.507 + Accessible* target = event->GetAccessible(); 1.508 + if (!target || target->IsDefunct()) 1.509 + continue; 1.510 + 1.511 + // Dispatch the focus event if target is still focused. 1.512 + if (event->mEventType == nsIAccessibleEvent::EVENT_FOCUS) { 1.513 + FocusMgr()->ProcessFocusEvent(event); 1.514 + continue; 1.515 + } 1.516 + 1.517 + // Dispatch caret moved and text selection change events. 1.518 + if (event->mEventType == nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED) { 1.519 + SelectionMgr()->ProcessTextSelChangeEvent(event); 1.520 + continue; 1.521 + } 1.522 + 1.523 + // Fire selected state change events in support to selection events. 1.524 + if (event->mEventType == nsIAccessibleEvent::EVENT_SELECTION_ADD) { 1.525 + nsEventShell::FireEvent(event->mAccessible, states::SELECTED, 1.526 + true, event->mIsFromUserInput); 1.527 + 1.528 + } else if (event->mEventType == nsIAccessibleEvent::EVENT_SELECTION_REMOVE) { 1.529 + nsEventShell::FireEvent(event->mAccessible, states::SELECTED, 1.530 + false, event->mIsFromUserInput); 1.531 + 1.532 + } else if (event->mEventType == nsIAccessibleEvent::EVENT_SELECTION) { 1.533 + AccSelChangeEvent* selChangeEvent = downcast_accEvent(event); 1.534 + nsEventShell::FireEvent(event->mAccessible, states::SELECTED, 1.535 + (selChangeEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd), 1.536 + event->mIsFromUserInput); 1.537 + 1.538 + if (selChangeEvent->mPackedEvent) { 1.539 + nsEventShell::FireEvent(selChangeEvent->mPackedEvent->mAccessible, 1.540 + states::SELECTED, 1.541 + (selChangeEvent->mPackedEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd), 1.542 + selChangeEvent->mPackedEvent->mIsFromUserInput); 1.543 + } 1.544 + } 1.545 + 1.546 + nsEventShell::FireEvent(event); 1.547 + 1.548 + // Fire text change events. 1.549 + AccMutationEvent* mutationEvent = downcast_accEvent(event); 1.550 + if (mutationEvent) { 1.551 + if (mutationEvent->mTextChangeEvent) 1.552 + nsEventShell::FireEvent(mutationEvent->mTextChangeEvent); 1.553 + } 1.554 + } 1.555 + 1.556 + if (event->mEventType == nsIAccessibleEvent::EVENT_HIDE) 1.557 + mDocument->ShutdownChildrenInSubtree(event->mAccessible); 1.558 + 1.559 + if (!mDocument) 1.560 + return; 1.561 + } 1.562 +}