accessible/src/base/EventQueue.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "EventQueue.h"
michael@0 7
michael@0 8 #include "Accessible-inl.h"
michael@0 9 #include "nsEventShell.h"
michael@0 10 #include "DocAccessible.h"
michael@0 11 #include "nsAccessibilityService.h"
michael@0 12 #include "nsTextEquivUtils.h"
michael@0 13 #ifdef A11Y_LOG
michael@0 14 #include "Logging.h"
michael@0 15 #endif
michael@0 16
michael@0 17 using namespace mozilla;
michael@0 18 using namespace mozilla::a11y;
michael@0 19
michael@0 20 // Defines the number of selection add/remove events in the queue when they
michael@0 21 // aren't packed into single selection within event.
michael@0 22 const unsigned int kSelChangeCountToPack = 5;
michael@0 23
michael@0 24 ////////////////////////////////////////////////////////////////////////////////
michael@0 25 // EventQueue
michael@0 26 ////////////////////////////////////////////////////////////////////////////////
michael@0 27
michael@0 28 bool
michael@0 29 EventQueue::PushEvent(AccEvent* aEvent)
michael@0 30 {
michael@0 31 NS_ASSERTION((aEvent->mAccessible && aEvent->mAccessible->IsApplication()) ||
michael@0 32 aEvent->GetDocAccessible() == mDocument,
michael@0 33 "Queued event belongs to another document!");
michael@0 34
michael@0 35 if (!mEvents.AppendElement(aEvent))
michael@0 36 return false;
michael@0 37
michael@0 38 // Filter events.
michael@0 39 CoalesceEvents();
michael@0 40
michael@0 41 // Fire name change event on parent given that this event hasn't been
michael@0 42 // coalesced, the parent's name was calculated from its subtree, and the
michael@0 43 // subtree was changed.
michael@0 44 Accessible* target = aEvent->mAccessible;
michael@0 45 if (aEvent->mEventRule != AccEvent::eDoNotEmit &&
michael@0 46 target->HasNameDependentParent() &&
michael@0 47 (aEvent->mEventType == nsIAccessibleEvent::EVENT_NAME_CHANGE ||
michael@0 48 aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_REMOVED ||
michael@0 49 aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_INSERTED ||
michael@0 50 aEvent->mEventType == nsIAccessibleEvent::EVENT_SHOW ||
michael@0 51 aEvent->mEventType == nsIAccessibleEvent::EVENT_HIDE)) {
michael@0 52 // Only continue traversing up the tree if it's possible that the parent
michael@0 53 // accessible's name can depend on this accessible's name.
michael@0 54 Accessible* parent = target->Parent();
michael@0 55 while (parent &&
michael@0 56 nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeIfReqRule)) {
michael@0 57 // Test possible name dependent parent.
michael@0 58 if (nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeRule)) {
michael@0 59 nsAutoString name;
michael@0 60 ENameValueFlag nameFlag = parent->Name(name);
michael@0 61 // If name is obtained from subtree, fire name change event.
michael@0 62 if (nameFlag == eNameFromSubtree) {
michael@0 63 nsRefPtr<AccEvent> nameChangeEvent =
michael@0 64 new AccEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, parent);
michael@0 65 PushEvent(nameChangeEvent);
michael@0 66 }
michael@0 67 break;
michael@0 68 }
michael@0 69 parent = parent->Parent();
michael@0 70 }
michael@0 71 }
michael@0 72
michael@0 73 // Associate text change with hide event if it wasn't stolen from hiding
michael@0 74 // siblings during coalescence.
michael@0 75 AccMutationEvent* showOrHideEvent = downcast_accEvent(aEvent);
michael@0 76 if (showOrHideEvent && !showOrHideEvent->mTextChangeEvent)
michael@0 77 CreateTextChangeEventFor(showOrHideEvent);
michael@0 78
michael@0 79 return true;
michael@0 80 }
michael@0 81
michael@0 82 ////////////////////////////////////////////////////////////////////////////////
michael@0 83 // EventQueue: private
michael@0 84
michael@0 85 void
michael@0 86 EventQueue::CoalesceEvents()
michael@0 87 {
michael@0 88 NS_ASSERTION(mEvents.Length(), "There should be at least one pending event!");
michael@0 89 uint32_t tail = mEvents.Length() - 1;
michael@0 90 AccEvent* tailEvent = mEvents[tail];
michael@0 91
michael@0 92 switch(tailEvent->mEventRule) {
michael@0 93 case AccEvent::eCoalesceReorder:
michael@0 94 CoalesceReorderEvents(tailEvent);
michael@0 95 break; // case eCoalesceReorder
michael@0 96
michael@0 97 case AccEvent::eCoalesceMutationTextChange:
michael@0 98 {
michael@0 99 for (uint32_t index = tail - 1; index < tail; index--) {
michael@0 100 AccEvent* thisEvent = mEvents[index];
michael@0 101 if (thisEvent->mEventRule != tailEvent->mEventRule)
michael@0 102 continue;
michael@0 103
michael@0 104 // We don't currently coalesce text change events from show/hide events.
michael@0 105 if (thisEvent->mEventType != tailEvent->mEventType)
michael@0 106 continue;
michael@0 107
michael@0 108 // Show events may be duped because of reinsertion (removal is ignored
michael@0 109 // because initial insertion is not processed). Ignore initial
michael@0 110 // insertion.
michael@0 111 if (thisEvent->mAccessible == tailEvent->mAccessible)
michael@0 112 thisEvent->mEventRule = AccEvent::eDoNotEmit;
michael@0 113
michael@0 114 AccMutationEvent* tailMutationEvent = downcast_accEvent(tailEvent);
michael@0 115 AccMutationEvent* thisMutationEvent = downcast_accEvent(thisEvent);
michael@0 116 if (tailMutationEvent->mParent != thisMutationEvent->mParent)
michael@0 117 continue;
michael@0 118
michael@0 119 // Coalesce text change events for hide and show events.
michael@0 120 if (thisMutationEvent->IsHide()) {
michael@0 121 AccHideEvent* tailHideEvent = downcast_accEvent(tailEvent);
michael@0 122 AccHideEvent* thisHideEvent = downcast_accEvent(thisEvent);
michael@0 123 CoalesceTextChangeEventsFor(tailHideEvent, thisHideEvent);
michael@0 124 break;
michael@0 125 }
michael@0 126
michael@0 127 AccShowEvent* tailShowEvent = downcast_accEvent(tailEvent);
michael@0 128 AccShowEvent* thisShowEvent = downcast_accEvent(thisEvent);
michael@0 129 CoalesceTextChangeEventsFor(tailShowEvent, thisShowEvent);
michael@0 130 break;
michael@0 131 }
michael@0 132 } break; // case eCoalesceMutationTextChange
michael@0 133
michael@0 134 case AccEvent::eCoalesceOfSameType:
michael@0 135 {
michael@0 136 // Coalesce old events by newer event.
michael@0 137 for (uint32_t index = tail - 1; index < tail; index--) {
michael@0 138 AccEvent* accEvent = mEvents[index];
michael@0 139 if (accEvent->mEventType == tailEvent->mEventType &&
michael@0 140 accEvent->mEventRule == tailEvent->mEventRule) {
michael@0 141 accEvent->mEventRule = AccEvent::eDoNotEmit;
michael@0 142 return;
michael@0 143 }
michael@0 144 }
michael@0 145 } break; // case eCoalesceOfSameType
michael@0 146
michael@0 147 case AccEvent::eCoalesceSelectionChange:
michael@0 148 {
michael@0 149 AccSelChangeEvent* tailSelChangeEvent = downcast_accEvent(tailEvent);
michael@0 150 for (uint32_t index = tail - 1; index < tail; index--) {
michael@0 151 AccEvent* thisEvent = mEvents[index];
michael@0 152 if (thisEvent->mEventRule == tailEvent->mEventRule) {
michael@0 153 AccSelChangeEvent* thisSelChangeEvent =
michael@0 154 downcast_accEvent(thisEvent);
michael@0 155
michael@0 156 // Coalesce selection change events within same control.
michael@0 157 if (tailSelChangeEvent->mWidget == thisSelChangeEvent->mWidget) {
michael@0 158 CoalesceSelChangeEvents(tailSelChangeEvent, thisSelChangeEvent, index);
michael@0 159 return;
michael@0 160 }
michael@0 161 }
michael@0 162 }
michael@0 163
michael@0 164 } break; // eCoalesceSelectionChange
michael@0 165
michael@0 166 case AccEvent::eCoalesceStateChange:
michael@0 167 {
michael@0 168 // If state change event is duped then ignore previous event. If state
michael@0 169 // change event is opposite to previous event then no event is emitted
michael@0 170 // (accessible state wasn't changed).
michael@0 171 for (uint32_t index = tail - 1; index < tail; index--) {
michael@0 172 AccEvent* thisEvent = mEvents[index];
michael@0 173 if (thisEvent->mEventRule != AccEvent::eDoNotEmit &&
michael@0 174 thisEvent->mEventType == tailEvent->mEventType &&
michael@0 175 thisEvent->mAccessible == tailEvent->mAccessible) {
michael@0 176 AccStateChangeEvent* thisSCEvent = downcast_accEvent(thisEvent);
michael@0 177 AccStateChangeEvent* tailSCEvent = downcast_accEvent(tailEvent);
michael@0 178 if (thisSCEvent->mState == tailSCEvent->mState) {
michael@0 179 thisEvent->mEventRule = AccEvent::eDoNotEmit;
michael@0 180 if (thisSCEvent->mIsEnabled != tailSCEvent->mIsEnabled)
michael@0 181 tailEvent->mEventRule = AccEvent::eDoNotEmit;
michael@0 182 }
michael@0 183 }
michael@0 184 }
michael@0 185 break; // eCoalesceStateChange
michael@0 186 }
michael@0 187
michael@0 188 case AccEvent::eCoalesceTextSelChange:
michael@0 189 {
michael@0 190 // Coalesce older event by newer event for the same selection or target.
michael@0 191 // Events for same selection may have different targets and vice versa one
michael@0 192 // target may be pointed by different selections (for latter see
michael@0 193 // bug 927159).
michael@0 194 for (uint32_t index = tail - 1; index < tail; index--) {
michael@0 195 AccEvent* thisEvent = mEvents[index];
michael@0 196 if (thisEvent->mEventRule != AccEvent::eDoNotEmit &&
michael@0 197 thisEvent->mEventType == tailEvent->mEventType) {
michael@0 198 AccTextSelChangeEvent* thisTSCEvent = downcast_accEvent(thisEvent);
michael@0 199 AccTextSelChangeEvent* tailTSCEvent = downcast_accEvent(tailEvent);
michael@0 200 if (thisTSCEvent->mSel == tailTSCEvent->mSel ||
michael@0 201 thisEvent->mAccessible == tailEvent->mAccessible)
michael@0 202 thisEvent->mEventRule = AccEvent::eDoNotEmit;
michael@0 203 }
michael@0 204
michael@0 205 }
michael@0 206 } break; // eCoalesceTextSelChange
michael@0 207
michael@0 208 case AccEvent::eRemoveDupes:
michael@0 209 {
michael@0 210 // Check for repeat events, coalesce newly appended event by more older
michael@0 211 // event.
michael@0 212 for (uint32_t index = tail - 1; index < tail; index--) {
michael@0 213 AccEvent* accEvent = mEvents[index];
michael@0 214 if (accEvent->mEventType == tailEvent->mEventType &&
michael@0 215 accEvent->mEventRule == tailEvent->mEventRule &&
michael@0 216 accEvent->mAccessible == tailEvent->mAccessible) {
michael@0 217 tailEvent->mEventRule = AccEvent::eDoNotEmit;
michael@0 218 return;
michael@0 219 }
michael@0 220 }
michael@0 221 } break; // case eRemoveDupes
michael@0 222
michael@0 223 default:
michael@0 224 break; // case eAllowDupes, eDoNotEmit
michael@0 225 } // switch
michael@0 226 }
michael@0 227
michael@0 228 void
michael@0 229 EventQueue::CoalesceReorderEvents(AccEvent* aTailEvent)
michael@0 230 {
michael@0 231 uint32_t count = mEvents.Length();
michael@0 232 for (uint32_t index = count - 2; index < count; index--) {
michael@0 233 AccEvent* thisEvent = mEvents[index];
michael@0 234
michael@0 235 // Skip events of different types and targeted to application accessible.
michael@0 236 if (thisEvent->mEventType != aTailEvent->mEventType ||
michael@0 237 thisEvent->mAccessible->IsApplication())
michael@0 238 continue;
michael@0 239
michael@0 240 // If thisEvent target is not in document longer, i.e. if it was
michael@0 241 // removed from the tree then do not emit the event.
michael@0 242 if (!thisEvent->mAccessible->IsDoc() &&
michael@0 243 !thisEvent->mAccessible->IsInDocument()) {
michael@0 244 thisEvent->mEventRule = AccEvent::eDoNotEmit;
michael@0 245 continue;
michael@0 246 }
michael@0 247
michael@0 248 // Coalesce earlier event of the same target.
michael@0 249 if (thisEvent->mAccessible == aTailEvent->mAccessible) {
michael@0 250 if (thisEvent->mEventRule == AccEvent::eDoNotEmit) {
michael@0 251 AccReorderEvent* tailReorder = downcast_accEvent(aTailEvent);
michael@0 252 tailReorder->DoNotEmitAll();
michael@0 253 } else {
michael@0 254 thisEvent->mEventRule = AccEvent::eDoNotEmit;
michael@0 255 }
michael@0 256
michael@0 257 return;
michael@0 258 }
michael@0 259
michael@0 260 // If tailEvent contains thisEvent
michael@0 261 // then
michael@0 262 // if show or hide of tailEvent contains a grand parent of thisEvent
michael@0 263 // then ignore thisEvent and its show and hide events
michael@0 264 // otherwise ignore thisEvent but not its show and hide events
michael@0 265 Accessible* thisParent = thisEvent->mAccessible;
michael@0 266 while (thisParent && thisParent != mDocument) {
michael@0 267 if (thisParent->Parent() == aTailEvent->mAccessible) {
michael@0 268 AccReorderEvent* tailReorder = downcast_accEvent(aTailEvent);
michael@0 269 uint32_t eventType = tailReorder->IsShowHideEventTarget(thisParent);
michael@0 270
michael@0 271 // Sometimes InvalidateChildren() and
michael@0 272 // DocAccessible::CacheChildrenInSubtree() can conspire to reparent an
michael@0 273 // accessible in this case no need for mutation events. Se bug 883708
michael@0 274 // for details.
michael@0 275 if (eventType == nsIAccessibleEvent::EVENT_SHOW ||
michael@0 276 eventType == nsIAccessibleEvent::EVENT_HIDE) {
michael@0 277 AccReorderEvent* thisReorder = downcast_accEvent(thisEvent);
michael@0 278 thisReorder->DoNotEmitAll();
michael@0 279 } else {
michael@0 280 thisEvent->mEventRule = AccEvent::eDoNotEmit;
michael@0 281 }
michael@0 282
michael@0 283 return;
michael@0 284 }
michael@0 285
michael@0 286 thisParent = thisParent->Parent();
michael@0 287 }
michael@0 288
michael@0 289 // If tailEvent is contained by thisEvent
michael@0 290 // then
michael@0 291 // if show of thisEvent contains the tailEvent
michael@0 292 // then ignore tailEvent
michael@0 293 // if hide of thisEvent contains the tailEvent
michael@0 294 // then assert
michael@0 295 // otherwise ignore tailEvent but not its show and hide events
michael@0 296 Accessible* tailParent = aTailEvent->mAccessible;
michael@0 297 while (tailParent && tailParent != mDocument) {
michael@0 298 if (tailParent->Parent() == thisEvent->mAccessible) {
michael@0 299 AccReorderEvent* thisReorder = downcast_accEvent(thisEvent);
michael@0 300 AccReorderEvent* tailReorder = downcast_accEvent(aTailEvent);
michael@0 301 uint32_t eventType = thisReorder->IsShowHideEventTarget(tailParent);
michael@0 302 if (eventType == nsIAccessibleEvent::EVENT_SHOW)
michael@0 303 tailReorder->DoNotEmitAll();
michael@0 304 else if (eventType == nsIAccessibleEvent::EVENT_HIDE)
michael@0 305 NS_ERROR("Accessible tree was modified after it was removed! Huh?");
michael@0 306 else
michael@0 307 aTailEvent->mEventRule = AccEvent::eDoNotEmit;
michael@0 308
michael@0 309 return;
michael@0 310 }
michael@0 311
michael@0 312 tailParent = tailParent->Parent();
michael@0 313 }
michael@0 314
michael@0 315 } // for (index)
michael@0 316 }
michael@0 317
michael@0 318 void
michael@0 319 EventQueue::CoalesceSelChangeEvents(AccSelChangeEvent* aTailEvent,
michael@0 320 AccSelChangeEvent* aThisEvent,
michael@0 321 uint32_t aThisIndex)
michael@0 322 {
michael@0 323 aTailEvent->mPreceedingCount = aThisEvent->mPreceedingCount + 1;
michael@0 324
michael@0 325 // Pack all preceding events into single selection within event
michael@0 326 // when we receive too much selection add/remove events.
michael@0 327 if (aTailEvent->mPreceedingCount >= kSelChangeCountToPack) {
michael@0 328 aTailEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION_WITHIN;
michael@0 329 aTailEvent->mAccessible = aTailEvent->mWidget;
michael@0 330 aThisEvent->mEventRule = AccEvent::eDoNotEmit;
michael@0 331
michael@0 332 // Do not emit any preceding selection events for same widget if they
michael@0 333 // weren't coalesced yet.
michael@0 334 if (aThisEvent->mEventType != nsIAccessibleEvent::EVENT_SELECTION_WITHIN) {
michael@0 335 for (uint32_t jdx = aThisIndex - 1; jdx < aThisIndex; jdx--) {
michael@0 336 AccEvent* prevEvent = mEvents[jdx];
michael@0 337 if (prevEvent->mEventRule == aTailEvent->mEventRule) {
michael@0 338 AccSelChangeEvent* prevSelChangeEvent =
michael@0 339 downcast_accEvent(prevEvent);
michael@0 340 if (prevSelChangeEvent->mWidget == aTailEvent->mWidget)
michael@0 341 prevSelChangeEvent->mEventRule = AccEvent::eDoNotEmit;
michael@0 342 }
michael@0 343 }
michael@0 344 }
michael@0 345 return;
michael@0 346 }
michael@0 347
michael@0 348 // Pack sequential selection remove and selection add events into
michael@0 349 // single selection change event.
michael@0 350 if (aTailEvent->mPreceedingCount == 1 &&
michael@0 351 aTailEvent->mItem != aThisEvent->mItem) {
michael@0 352 if (aTailEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd &&
michael@0 353 aThisEvent->mSelChangeType == AccSelChangeEvent::eSelectionRemove) {
michael@0 354 aThisEvent->mEventRule = AccEvent::eDoNotEmit;
michael@0 355 aTailEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION;
michael@0 356 aTailEvent->mPackedEvent = aThisEvent;
michael@0 357 return;
michael@0 358 }
michael@0 359
michael@0 360 if (aThisEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd &&
michael@0 361 aTailEvent->mSelChangeType == AccSelChangeEvent::eSelectionRemove) {
michael@0 362 aTailEvent->mEventRule = AccEvent::eDoNotEmit;
michael@0 363 aThisEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION;
michael@0 364 aThisEvent->mPackedEvent = aTailEvent;
michael@0 365 return;
michael@0 366 }
michael@0 367 }
michael@0 368
michael@0 369 // Unpack the packed selection change event because we've got one
michael@0 370 // more selection add/remove.
michael@0 371 if (aThisEvent->mEventType == nsIAccessibleEvent::EVENT_SELECTION) {
michael@0 372 if (aThisEvent->mPackedEvent) {
michael@0 373 aThisEvent->mPackedEvent->mEventType =
michael@0 374 aThisEvent->mPackedEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd ?
michael@0 375 nsIAccessibleEvent::EVENT_SELECTION_ADD :
michael@0 376 nsIAccessibleEvent::EVENT_SELECTION_REMOVE;
michael@0 377
michael@0 378 aThisEvent->mPackedEvent->mEventRule =
michael@0 379 AccEvent::eCoalesceSelectionChange;
michael@0 380
michael@0 381 aThisEvent->mPackedEvent = nullptr;
michael@0 382 }
michael@0 383
michael@0 384 aThisEvent->mEventType =
michael@0 385 aThisEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd ?
michael@0 386 nsIAccessibleEvent::EVENT_SELECTION_ADD :
michael@0 387 nsIAccessibleEvent::EVENT_SELECTION_REMOVE;
michael@0 388
michael@0 389 return;
michael@0 390 }
michael@0 391
michael@0 392 // Convert into selection add since control has single selection but other
michael@0 393 // selection events for this control are queued.
michael@0 394 if (aTailEvent->mEventType == nsIAccessibleEvent::EVENT_SELECTION)
michael@0 395 aTailEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION_ADD;
michael@0 396 }
michael@0 397
michael@0 398 void
michael@0 399 EventQueue::CoalesceTextChangeEventsFor(AccHideEvent* aTailEvent,
michael@0 400 AccHideEvent* aThisEvent)
michael@0 401 {
michael@0 402 // XXX: we need a way to ignore SplitNode and JoinNode() when they do not
michael@0 403 // affect the text within the hypertext.
michael@0 404
michael@0 405 AccTextChangeEvent* textEvent = aThisEvent->mTextChangeEvent;
michael@0 406 if (!textEvent)
michael@0 407 return;
michael@0 408
michael@0 409 if (aThisEvent->mNextSibling == aTailEvent->mAccessible) {
michael@0 410 aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText);
michael@0 411
michael@0 412 } else if (aThisEvent->mPrevSibling == aTailEvent->mAccessible) {
michael@0 413 uint32_t oldLen = textEvent->GetLength();
michael@0 414 aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText);
michael@0 415 textEvent->mStart -= textEvent->GetLength() - oldLen;
michael@0 416 }
michael@0 417
michael@0 418 aTailEvent->mTextChangeEvent.swap(aThisEvent->mTextChangeEvent);
michael@0 419 }
michael@0 420
michael@0 421 void
michael@0 422 EventQueue::CoalesceTextChangeEventsFor(AccShowEvent* aTailEvent,
michael@0 423 AccShowEvent* aThisEvent)
michael@0 424 {
michael@0 425 AccTextChangeEvent* textEvent = aThisEvent->mTextChangeEvent;
michael@0 426 if (!textEvent)
michael@0 427 return;
michael@0 428
michael@0 429 if (aTailEvent->mAccessible->IndexInParent() ==
michael@0 430 aThisEvent->mAccessible->IndexInParent() + 1) {
michael@0 431 // If tail target was inserted after this target, i.e. tail target is next
michael@0 432 // sibling of this target.
michael@0 433 aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText);
michael@0 434
michael@0 435 } else if (aTailEvent->mAccessible->IndexInParent() ==
michael@0 436 aThisEvent->mAccessible->IndexInParent() -1) {
michael@0 437 // If tail target was inserted before this target, i.e. tail target is
michael@0 438 // previous sibling of this target.
michael@0 439 nsAutoString startText;
michael@0 440 aTailEvent->mAccessible->AppendTextTo(startText);
michael@0 441 textEvent->mModifiedText = startText + textEvent->mModifiedText;
michael@0 442 textEvent->mStart -= startText.Length();
michael@0 443 }
michael@0 444
michael@0 445 aTailEvent->mTextChangeEvent.swap(aThisEvent->mTextChangeEvent);
michael@0 446 }
michael@0 447
michael@0 448 void
michael@0 449 EventQueue::CreateTextChangeEventFor(AccMutationEvent* aEvent)
michael@0 450 {
michael@0 451 Accessible* container = aEvent->mAccessible->Parent();
michael@0 452 if (!container)
michael@0 453 return;
michael@0 454
michael@0 455 HyperTextAccessible* textAccessible = container->AsHyperText();
michael@0 456 if (!textAccessible)
michael@0 457 return;
michael@0 458
michael@0 459 // Don't fire event for the first html:br in an editor.
michael@0 460 if (aEvent->mAccessible->Role() == roles::WHITESPACE) {
michael@0 461 nsCOMPtr<nsIEditor> editor = textAccessible->GetEditor();
michael@0 462 if (editor) {
michael@0 463 bool isEmpty = false;
michael@0 464 editor->GetDocumentIsEmpty(&isEmpty);
michael@0 465 if (isEmpty)
michael@0 466 return;
michael@0 467 }
michael@0 468 }
michael@0 469
michael@0 470 int32_t offset = textAccessible->GetChildOffset(aEvent->mAccessible);
michael@0 471
michael@0 472 nsAutoString text;
michael@0 473 aEvent->mAccessible->AppendTextTo(text);
michael@0 474 if (text.IsEmpty())
michael@0 475 return;
michael@0 476
michael@0 477 aEvent->mTextChangeEvent =
michael@0 478 new AccTextChangeEvent(textAccessible, offset, text, aEvent->IsShow(),
michael@0 479 aEvent->mIsFromUserInput ? eFromUserInput : eNoUserInput);
michael@0 480 }
michael@0 481
michael@0 482 ////////////////////////////////////////////////////////////////////////////////
michael@0 483 // EventQueue: event queue
michael@0 484
michael@0 485 void
michael@0 486 EventQueue::ProcessEventQueue()
michael@0 487 {
michael@0 488 // Process only currently queued events.
michael@0 489 nsTArray<nsRefPtr<AccEvent> > events;
michael@0 490 events.SwapElements(mEvents);
michael@0 491
michael@0 492 uint32_t eventCount = events.Length();
michael@0 493 #ifdef A11Y_LOG
michael@0 494 if (eventCount > 0 && logging::IsEnabled(logging::eEvents)) {
michael@0 495 logging::MsgBegin("EVENTS", "events processing");
michael@0 496 logging::Address("document", mDocument);
michael@0 497 logging::MsgEnd();
michael@0 498 }
michael@0 499 #endif
michael@0 500
michael@0 501 for (uint32_t idx = 0; idx < eventCount; idx++) {
michael@0 502 AccEvent* event = events[idx];
michael@0 503 if (event->mEventRule != AccEvent::eDoNotEmit) {
michael@0 504 Accessible* target = event->GetAccessible();
michael@0 505 if (!target || target->IsDefunct())
michael@0 506 continue;
michael@0 507
michael@0 508 // Dispatch the focus event if target is still focused.
michael@0 509 if (event->mEventType == nsIAccessibleEvent::EVENT_FOCUS) {
michael@0 510 FocusMgr()->ProcessFocusEvent(event);
michael@0 511 continue;
michael@0 512 }
michael@0 513
michael@0 514 // Dispatch caret moved and text selection change events.
michael@0 515 if (event->mEventType == nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED) {
michael@0 516 SelectionMgr()->ProcessTextSelChangeEvent(event);
michael@0 517 continue;
michael@0 518 }
michael@0 519
michael@0 520 // Fire selected state change events in support to selection events.
michael@0 521 if (event->mEventType == nsIAccessibleEvent::EVENT_SELECTION_ADD) {
michael@0 522 nsEventShell::FireEvent(event->mAccessible, states::SELECTED,
michael@0 523 true, event->mIsFromUserInput);
michael@0 524
michael@0 525 } else if (event->mEventType == nsIAccessibleEvent::EVENT_SELECTION_REMOVE) {
michael@0 526 nsEventShell::FireEvent(event->mAccessible, states::SELECTED,
michael@0 527 false, event->mIsFromUserInput);
michael@0 528
michael@0 529 } else if (event->mEventType == nsIAccessibleEvent::EVENT_SELECTION) {
michael@0 530 AccSelChangeEvent* selChangeEvent = downcast_accEvent(event);
michael@0 531 nsEventShell::FireEvent(event->mAccessible, states::SELECTED,
michael@0 532 (selChangeEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd),
michael@0 533 event->mIsFromUserInput);
michael@0 534
michael@0 535 if (selChangeEvent->mPackedEvent) {
michael@0 536 nsEventShell::FireEvent(selChangeEvent->mPackedEvent->mAccessible,
michael@0 537 states::SELECTED,
michael@0 538 (selChangeEvent->mPackedEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd),
michael@0 539 selChangeEvent->mPackedEvent->mIsFromUserInput);
michael@0 540 }
michael@0 541 }
michael@0 542
michael@0 543 nsEventShell::FireEvent(event);
michael@0 544
michael@0 545 // Fire text change events.
michael@0 546 AccMutationEvent* mutationEvent = downcast_accEvent(event);
michael@0 547 if (mutationEvent) {
michael@0 548 if (mutationEvent->mTextChangeEvent)
michael@0 549 nsEventShell::FireEvent(mutationEvent->mTextChangeEvent);
michael@0 550 }
michael@0 551 }
michael@0 552
michael@0 553 if (event->mEventType == nsIAccessibleEvent::EVENT_HIDE)
michael@0 554 mDocument->ShutdownChildrenInSubtree(event->mAccessible);
michael@0 555
michael@0 556 if (!mDocument)
michael@0 557 return;
michael@0 558 }
michael@0 559 }

mercurial