accessible/src/base/EventQueue.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial