LCOV - code coverage report
Current view: top level - accessible/base - EventTree.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 316 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 14 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       5             : 
       6             : #include "EventTree.h"
       7             : 
       8             : #include "Accessible-inl.h"
       9             : #include "nsEventShell.h"
      10             : #include "DocAccessible.h"
      11             : #ifdef A11Y_LOG
      12             : #include "Logging.h"
      13             : #endif
      14             : 
      15             : #include "mozilla/UniquePtr.h"
      16             : 
      17             : using namespace mozilla;
      18             : using namespace mozilla::a11y;
      19             : 
      20             : ////////////////////////////////////////////////////////////////////////////////
      21             : // TreeMutation class
      22             : 
      23             : EventTree* const TreeMutation::kNoEventTree = reinterpret_cast<EventTree*>(-1);
      24             : 
      25           0 : TreeMutation::TreeMutation(Accessible* aParent, bool aNoEvents) :
      26             :   mParent(aParent), mStartIdx(UINT32_MAX),
      27           0 :   mStateFlagsCopy(mParent->mStateFlags),
      28           0 :   mQueueEvents(!aNoEvents)
      29             : {
      30             : #ifdef DEBUG
      31           0 :   mIsDone = false;
      32             : #endif
      33             : 
      34             : #ifdef A11Y_LOG
      35           0 :   if (mQueueEvents && logging::IsEnabled(logging::eEventTree)) {
      36           0 :     logging::MsgBegin("EVENTS_TREE", "reordering tree before");
      37           0 :     logging::AccessibleInfo("reordering for", mParent);
      38           0 :     Controller()->RootEventTree().Log();
      39           0 :     logging::MsgEnd();
      40             : 
      41           0 :     if (logging::IsEnabled(logging::eVerbose)) {
      42           0 :       logging::Tree("EVENTS_TREE", "Container tree", mParent->Document(),
      43           0 :                     PrefixLog, static_cast<void*>(this));
      44             :     }
      45             :   }
      46             : #endif
      47             : 
      48           0 :   mParent->mStateFlags |= Accessible::eKidsMutating;
      49           0 : }
      50             : 
      51           0 : TreeMutation::~TreeMutation()
      52             : {
      53           0 :   MOZ_ASSERT(mIsDone, "Done() must be called explicitly");
      54           0 : }
      55             : 
      56             : void
      57           0 : TreeMutation::AfterInsertion(Accessible* aChild)
      58             : {
      59           0 :   MOZ_ASSERT(aChild->Parent() == mParent);
      60             : 
      61           0 :   if (static_cast<uint32_t>(aChild->mIndexInParent) < mStartIdx) {
      62           0 :     mStartIdx = aChild->mIndexInParent + 1;
      63             :   }
      64             : 
      65           0 :   if (!mQueueEvents) {
      66           0 :     return;
      67             :   }
      68             : 
      69           0 :   RefPtr<AccShowEvent> ev = new AccShowEvent(aChild);
      70           0 :   DebugOnly<bool> added = Controller()->QueueMutationEvent(ev);
      71           0 :   MOZ_ASSERT(added);
      72           0 :   aChild->SetShowEventTarget(true);
      73             : }
      74             : 
      75             : void
      76           0 : TreeMutation::BeforeRemoval(Accessible* aChild, bool aNoShutdown)
      77             : {
      78           0 :   MOZ_ASSERT(aChild->Parent() == mParent);
      79             : 
      80           0 :   if (static_cast<uint32_t>(aChild->mIndexInParent) < mStartIdx) {
      81           0 :     mStartIdx = aChild->mIndexInParent;
      82             :   }
      83             : 
      84           0 :   if (!mQueueEvents) {
      85           0 :     return;
      86             :   }
      87             : 
      88           0 :   RefPtr<AccHideEvent> ev = new AccHideEvent(aChild, !aNoShutdown);
      89           0 :   if (Controller()->QueueMutationEvent(ev)) {
      90           0 :     aChild->SetHideEventTarget(true);
      91             :   }
      92             : }
      93             : 
      94             : void
      95           0 : TreeMutation::Done()
      96             : {
      97           0 :   MOZ_ASSERT(mParent->mStateFlags & Accessible::eKidsMutating);
      98           0 :   mParent->mStateFlags &= ~Accessible::eKidsMutating;
      99             : 
     100           0 :   uint32_t length = mParent->mChildren.Length();
     101             : #ifdef DEBUG
     102           0 :   for (uint32_t idx = 0; idx < mStartIdx && idx < length; idx++) {
     103           0 :     MOZ_ASSERT(mParent->mChildren[idx]->mIndexInParent == static_cast<int32_t>(idx),
     104             :                "Wrong index detected");
     105             :   }
     106             : #endif
     107             : 
     108           0 :   for (uint32_t idx = mStartIdx; idx < length; idx++) {
     109           0 :     mParent->mChildren[idx]->mInt.mIndexOfEmbeddedChild = -1;
     110           0 :     mParent->mChildren[idx]->mStateFlags |= Accessible::eGroupInfoDirty;
     111             :   }
     112             : 
     113           0 :   mParent->mEmbeddedObjCollector = nullptr;
     114           0 :   mParent->mStateFlags |= mStateFlagsCopy & Accessible::eKidsMutating;
     115             : 
     116             : #ifdef DEBUG
     117           0 :   mIsDone = true;
     118             : #endif
     119             : 
     120             : #ifdef A11Y_LOG
     121           0 :   if (mQueueEvents && logging::IsEnabled(logging::eEventTree)) {
     122           0 :     logging::MsgBegin("EVENTS_TREE", "reordering tree after");
     123           0 :     logging::AccessibleInfo("reordering for", mParent);
     124           0 :     Controller()->RootEventTree().Log();
     125           0 :     logging::MsgEnd();
     126             :   }
     127             : #endif
     128           0 : }
     129             : 
     130             : #ifdef A11Y_LOG
     131             : const char*
     132           0 : TreeMutation::PrefixLog(void* aData, Accessible* aAcc)
     133             : {
     134           0 :   TreeMutation* thisObj = reinterpret_cast<TreeMutation*>(aData);
     135           0 :   if (thisObj->mParent == aAcc) {
     136           0 :     return "_X_";
     137             :   }
     138           0 :   const EventTree& ret = thisObj->Controller()->RootEventTree();
     139           0 :   if (ret.Find(aAcc)) {
     140           0 :     return "_с_";
     141             :   }
     142           0 :   return "";
     143             : }
     144             : #endif
     145             : 
     146             : 
     147             : ////////////////////////////////////////////////////////////////////////////////
     148             : // EventTree
     149             : 
     150             : void
     151           0 : EventTree::Shown(Accessible* aChild)
     152             : {
     153           0 :   RefPtr<AccShowEvent> ev = new AccShowEvent(aChild);
     154           0 :   Controller(aChild)->WithdrawPrecedingEvents(&ev->mPrecedingEvents);
     155           0 :   Mutated(ev);
     156           0 : }
     157             : 
     158             : void
     159           0 : EventTree::Hidden(Accessible* aChild, bool aNeedsShutdown)
     160             : {
     161           0 :   RefPtr<AccHideEvent> ev = new AccHideEvent(aChild, aNeedsShutdown);
     162           0 :   if (!aNeedsShutdown) {
     163           0 :     Controller(aChild)->StorePrecedingEvent(ev);
     164             :   }
     165           0 :   Mutated(ev);
     166           0 : }
     167             : 
     168             : void
     169           0 : EventTree::Process(const RefPtr<DocAccessible>& aDeathGrip)
     170             : {
     171           0 :   while (mFirst) {
     172             :     // Skip a node and its subtree if its container is not in the document.
     173           0 :     if (mFirst->mContainer->IsInDocument()) {
     174           0 :       mFirst->Process(aDeathGrip);
     175           0 :       if (aDeathGrip->IsDefunct()) {
     176           0 :         return;
     177             :       }
     178             :     }
     179           0 :     mFirst = Move(mFirst->mNext);
     180             :   }
     181             : 
     182           0 :   MOZ_ASSERT(mContainer || mDependentEvents.IsEmpty(),
     183             :              "No container, no events");
     184           0 :   MOZ_ASSERT(!mContainer || !mContainer->IsDefunct(),
     185             :              "Processing events for defunct container");
     186           0 :   MOZ_ASSERT(!mFireReorder || mContainer, "No target for reorder event");
     187             : 
     188             :   // Fire mutation events.
     189           0 :   uint32_t eventsCount = mDependentEvents.Length();
     190           0 :   for (uint32_t jdx = 0; jdx < eventsCount; jdx++) {
     191           0 :     AccMutationEvent* mtEvent = mDependentEvents[jdx];
     192           0 :     MOZ_ASSERT(mtEvent->Document(), "No document for event target");
     193             : 
     194             :     // Fire all hide events that has to be fired before this show event.
     195           0 :     if (mtEvent->IsShow()) {
     196           0 :       AccShowEvent* showEv = downcast_accEvent(mtEvent);
     197           0 :       for (uint32_t i = 0; i < showEv->mPrecedingEvents.Length(); i++) {
     198           0 :         nsEventShell::FireEvent(showEv->mPrecedingEvents[i]);
     199           0 :         if (aDeathGrip->IsDefunct()) {
     200           0 :           return;
     201             :         }
     202             :       }
     203             :     }
     204             : 
     205           0 :     nsEventShell::FireEvent(mtEvent);
     206           0 :     if (aDeathGrip->IsDefunct()) {
     207           0 :       return;
     208             :     }
     209             : 
     210           0 :     if (mtEvent->mTextChangeEvent) {
     211           0 :       nsEventShell::FireEvent(mtEvent->mTextChangeEvent);
     212           0 :       if (aDeathGrip->IsDefunct()) {
     213           0 :         return;
     214             :       }
     215             :     }
     216             : 
     217           0 :     if (mtEvent->IsHide()) {
     218             :       // Fire menupopup end event before a hide event if a menu goes away.
     219             : 
     220             :       // XXX: We don't look into children of hidden subtree to find hiding
     221             :       // menupopup (as we did prior bug 570275) because we don't do that when
     222             :       // menu is showing (and that's impossible until bug 606924 is fixed).
     223             :       // Nevertheless we should do this at least because layout coalesces
     224             :       // the changes before our processing and we may miss some menupopup
     225             :       // events. Now we just want to be consistent in content insertion/removal
     226             :       // handling.
     227           0 :       if (mtEvent->mAccessible->ARIARole() == roles::MENUPOPUP) {
     228           0 :         nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
     229           0 :                                 mtEvent->mAccessible);
     230           0 :         if (aDeathGrip->IsDefunct()) {
     231           0 :           return;
     232             :         }
     233             :       }
     234             : 
     235           0 :       AccHideEvent* hideEvent = downcast_accEvent(mtEvent);
     236           0 :       if (hideEvent->NeedsShutdown()) {
     237           0 :         aDeathGrip->ShutdownChildrenInSubtree(mtEvent->mAccessible);
     238             :       }
     239             :     }
     240             :   }
     241             : 
     242             :   // Fire reorder event at last.
     243           0 :   if (mFireReorder) {
     244           0 :     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_REORDER, mContainer);
     245           0 :     mContainer->Document()->MaybeNotifyOfValueChange(mContainer);
     246             :   }
     247             : 
     248           0 :   mDependentEvents.Clear();
     249             : }
     250             : 
     251             : EventTree*
     252           0 : EventTree::FindOrInsert(Accessible* aContainer)
     253             : {
     254           0 :   if (!mFirst) {
     255           0 :     mFirst.reset(new EventTree(aContainer, mDependentEvents.IsEmpty()));
     256           0 :     return mFirst.get();
     257             :   }
     258             : 
     259           0 :   EventTree* prevNode = nullptr;
     260           0 :   EventTree* node = mFirst.get();
     261           0 :   do {
     262           0 :     MOZ_ASSERT(!node->mContainer->IsApplication(),
     263             :                "No event for application accessible is expected here");
     264           0 :     MOZ_ASSERT(!node->mContainer->IsDefunct(), "An event target has to be alive");
     265             : 
     266             :     // Case of same target.
     267           0 :     if (node->mContainer == aContainer) {
     268           0 :       return node;
     269             :     }
     270             : 
     271             :     // Check if the given container is contained by a current node
     272           0 :     Accessible* top = mContainer ? mContainer : aContainer->Document();
     273           0 :     Accessible* parent = aContainer;
     274           0 :     while (parent) {
     275             :       // Reached a top, no match for a current event.
     276           0 :       if (parent == top) {
     277           0 :         break;
     278             :       }
     279             : 
     280             :       // We got a match.
     281           0 :       if (parent->Parent() == node->mContainer) {
     282             :         // Reject the node if it's contained by a show/hide event target
     283           0 :         uint32_t evCount = node->mDependentEvents.Length();
     284           0 :         for (uint32_t idx = 0; idx < evCount; idx++) {
     285           0 :           AccMutationEvent* ev = node->mDependentEvents[idx];
     286           0 :           if (ev->GetAccessible() == parent) {
     287             : #ifdef A11Y_LOG
     288           0 :             if (logging::IsEnabled(logging::eEventTree)) {
     289             :               logging::MsgBegin("EVENTS_TREE",
     290           0 :                 "Rejecting node contained by show/hide");
     291           0 :               logging::AccessibleInfo("Node", aContainer);
     292           0 :               logging::MsgEnd();
     293             :             }
     294             : #endif
     295             :             // If the node is rejected, then check if it has related hide event
     296             :             // on stack, and if so, then connect it to the parent show event.
     297           0 :             if (ev->IsShow()) {
     298           0 :               AccShowEvent* showEv = downcast_accEvent(ev);
     299             :               Controller(aContainer)->
     300           0 :                 WithdrawPrecedingEvents(&showEv->mPrecedingEvents);
     301             :             }
     302           0 :             return nullptr;
     303             :           }
     304             :         }
     305             : 
     306           0 :         return node->FindOrInsert(aContainer);
     307             :       }
     308             : 
     309           0 :       parent = parent->Parent();
     310           0 :       MOZ_ASSERT(parent, "Wrong tree");
     311             :     }
     312             : 
     313             :     // If the given container contains a current node
     314             :     // then
     315             :     //   if show or hide of the given node contains a grand parent of the current node
     316             :     //   then ignore the current node and its show and hide events
     317             :     //   otherwise ignore the current node, but not its show and hide events
     318           0 :     Accessible* curParent = node->mContainer;
     319           0 :     while (curParent && !curParent->IsDoc()) {
     320           0 :       if (curParent->Parent() != aContainer) {
     321           0 :         curParent = curParent->Parent();
     322           0 :         continue;
     323             :       }
     324             : 
     325             :       // Insert the tail node into the hierarchy between the current node and
     326             :       // its parent.
     327           0 :       node->mFireReorder = false;
     328           0 :       UniquePtr<EventTree>& nodeOwnerRef = prevNode ? prevNode->mNext : mFirst;
     329           0 :       UniquePtr<EventTree> newNode(new EventTree(aContainer, mDependentEvents.IsEmpty()));
     330           0 :       newNode->mFirst = Move(nodeOwnerRef);
     331           0 :       nodeOwnerRef = Move(newNode);
     332           0 :       nodeOwnerRef->mNext = Move(node->mNext);
     333             : 
     334             :       // Check if a next node is contained by the given node too, and move them
     335             :       // under the given node if so.
     336           0 :       prevNode = nodeOwnerRef.get();
     337           0 :       node = nodeOwnerRef->mNext.get();
     338           0 :       UniquePtr<EventTree>* nodeRef = &nodeOwnerRef->mNext;
     339           0 :       EventTree* insNode = nodeOwnerRef->mFirst.get();
     340           0 :       while (node) {
     341           0 :         Accessible* curParent = node->mContainer;
     342           0 :         while (curParent && !curParent->IsDoc()) {
     343           0 :           if (curParent->Parent() != aContainer) {
     344           0 :             curParent = curParent->Parent();
     345           0 :             continue;
     346             :           }
     347             : 
     348           0 :           MOZ_ASSERT(!insNode->mNext);
     349             : 
     350           0 :           node->mFireReorder = false;
     351           0 :           insNode->mNext = Move(*nodeRef);
     352           0 :           insNode = insNode->mNext.get();
     353             : 
     354           0 :           prevNode->mNext = Move(node->mNext);
     355           0 :           node = prevNode;
     356           0 :           break;
     357             :         }
     358             : 
     359           0 :         prevNode = node;
     360           0 :         nodeRef = &node->mNext;
     361           0 :         node = node->mNext.get();
     362             :       }
     363             : 
     364           0 :       return nodeOwnerRef.get();
     365             :     }
     366             : 
     367           0 :     prevNode = node;
     368           0 :   } while ((node = node->mNext.get()));
     369             : 
     370           0 :   MOZ_ASSERT(prevNode, "Nowhere to insert");
     371           0 :   MOZ_ASSERT(!prevNode->mNext, "Taken by another node");
     372             : 
     373             :   // If 'this' node contains the given container accessible, then
     374             :   //   do not emit a reorder event for the container
     375             :   //   if a dependent show event target contains the given container then do not
     376             :   //   emit show / hide events (see Process() method)
     377             : 
     378           0 :   prevNode->mNext.reset(new EventTree(aContainer, mDependentEvents.IsEmpty()));
     379           0 :   return prevNode->mNext.get();
     380             : }
     381             : 
     382             : void
     383           0 : EventTree::Clear()
     384             : {
     385           0 :   mFirst = nullptr;
     386           0 :   mNext = nullptr;
     387           0 :   mContainer = nullptr;
     388             : 
     389           0 :   uint32_t eventsCount = mDependentEvents.Length();
     390           0 :   for (uint32_t jdx = 0; jdx < eventsCount; jdx++) {
     391           0 :     mDependentEvents[jdx]->mEventType = AccEvent::eDoNotEmit;
     392           0 :     AccHideEvent* ev = downcast_accEvent(mDependentEvents[jdx]);
     393           0 :     if (ev && ev->NeedsShutdown()) {
     394           0 :       ev->Document()->ShutdownChildrenInSubtree(ev->mAccessible);
     395             :     }
     396             :   }
     397           0 :   mDependentEvents.Clear();
     398           0 : }
     399             : 
     400             : const EventTree*
     401           0 : EventTree::Find(const Accessible* aContainer) const
     402             : {
     403           0 :   const EventTree* et = this;
     404           0 :   while (et) {
     405           0 :     if (et->mContainer == aContainer) {
     406           0 :       return et;
     407             :     }
     408             : 
     409           0 :     if (et->mFirst) {
     410           0 :       et = et->mFirst.get();
     411           0 :       const EventTree* cet = et->Find(aContainer);
     412           0 :       if (cet) {
     413           0 :         return cet;
     414             :       }
     415             :     }
     416             : 
     417           0 :     et = et->mNext.get();
     418           0 :     const EventTree* cet = et->Find(aContainer);
     419           0 :     if (cet) {
     420           0 :       return cet;
     421             :     }
     422             :   }
     423             : 
     424           0 :   return nullptr;
     425             : }
     426             : 
     427             : #ifdef A11Y_LOG
     428             : void
     429           0 : EventTree::Log(uint32_t aLevel) const
     430             : {
     431           0 :   if (aLevel == UINT32_MAX) {
     432           0 :     if (mFirst) {
     433           0 :       mFirst->Log(0);
     434             :     }
     435           0 :     return;
     436             :   }
     437             : 
     438           0 :   for (uint32_t i = 0; i < aLevel; i++) {
     439           0 :     printf("  ");
     440             :   }
     441           0 :   logging::AccessibleInfo("container", mContainer);
     442             : 
     443           0 :   for (uint32_t i = 0; i < mDependentEvents.Length(); i++) {
     444           0 :     AccMutationEvent* ev = mDependentEvents[i];
     445           0 :     if (ev->IsShow()) {
     446           0 :       for (uint32_t i = 0; i < aLevel + 1; i++) {
     447           0 :         printf("  ");
     448             :       }
     449           0 :       logging::AccessibleInfo("shown", ev->mAccessible);
     450             : 
     451           0 :       AccShowEvent* showEv = downcast_accEvent(ev);
     452           0 :       for (uint32_t i = 0; i < showEv->mPrecedingEvents.Length(); i++) {
     453           0 :         for (uint32_t j = 0; j < aLevel + 1; j++) {
     454           0 :           printf("  ");
     455             :         }
     456           0 :         logging::AccessibleInfo("preceding",
     457           0 :                                 showEv->mPrecedingEvents[i]->mAccessible);
     458             :       }
     459             :     }
     460             :     else {
     461           0 :       for (uint32_t i = 0; i < aLevel + 1; i++) {
     462           0 :         printf("  ");
     463             :       }
     464           0 :       logging::AccessibleInfo("hidden", ev->mAccessible);
     465             :     }
     466             :   }
     467             : 
     468           0 :   if (mFirst) {
     469           0 :     mFirst->Log(aLevel + 1);
     470             :   }
     471             : 
     472           0 :   if (mNext) {
     473           0 :     mNext->Log(aLevel);
     474             :   }
     475             : }
     476             : #endif
     477             : 
     478             : void
     479           0 : EventTree::Mutated(AccMutationEvent* aEv)
     480             : {
     481             :   // If shown or hidden node is a root of previously mutated subtree, then
     482             :   // discard those subtree mutations as we are no longer interested in them.
     483           0 :   UniquePtr<EventTree>* node = &mFirst;
     484           0 :   while (*node) {
     485           0 :     Accessible* cntr = (*node)->mContainer;
     486           0 :     while (cntr != mContainer) {
     487           0 :       if (cntr == aEv->mAccessible) {
     488             : #ifdef A11Y_LOG
     489           0 :         if (logging::IsEnabled(logging::eEventTree)) {
     490           0 :           logging::MsgBegin("EVENTS_TREE", "Trim subtree");
     491           0 :           logging::AccessibleInfo("Show/hide container", aEv->mAccessible);
     492           0 :           logging::AccessibleInfo("Trimmed subtree root", (*node)->mContainer);
     493           0 :           logging::MsgEnd();
     494             :         }
     495             : #endif
     496             : 
     497             :         // If the new hide is part of a move and it contains existing child
     498             :         // shows, then move preceding events from the child shows to the buffer,
     499             :         // so the ongoing show event will pick them up.
     500           0 :         if (aEv->IsHide()) {
     501           0 :           AccHideEvent* hideEv = downcast_accEvent(aEv);
     502           0 :           if (!hideEv->mNeedsShutdown) {
     503           0 :             for (uint32_t i = 0; i < (*node)->mDependentEvents.Length(); i++) {
     504           0 :               AccMutationEvent* childEv = (*node)->mDependentEvents[i];
     505           0 :               if (childEv->IsShow()) {
     506           0 :                 AccShowEvent* childShowEv = downcast_accEvent(childEv);
     507           0 :                 if (childShowEv->mPrecedingEvents.Length() > 0) {
     508           0 :                   Controller(mContainer)->StorePrecedingEvents(
     509           0 :                     mozilla::Move(childShowEv->mPrecedingEvents));
     510             :                 }
     511             :               }
     512             :             }
     513             :           }
     514             :         }
     515             :         // If the new show contains existing child shows, then move preceding
     516             :         // events from the child shows to the new show.
     517           0 :         else if (aEv->IsShow()) {
     518           0 :           AccShowEvent* showEv = downcast_accEvent(aEv);
     519           0 :           for (uint32_t i = 0; (*node)->mDependentEvents.Length(); i++) {
     520           0 :             AccMutationEvent* childEv = (*node)->mDependentEvents[i];
     521           0 :             if (childEv->IsShow()) {
     522           0 :               AccShowEvent* showChildEv = downcast_accEvent(childEv);
     523           0 :               if (showChildEv->mPrecedingEvents.Length() > 0) {
     524             : #ifdef A11Y_LOG
     525           0 :                 if (logging::IsEnabled(logging::eEventTree)) {
     526           0 :                   logging::MsgBegin("EVENTS_TREE", "Adopt preceding events");
     527           0 :                   logging::AccessibleInfo("Parent", aEv->mAccessible);
     528           0 :                   for (uint32_t j = 0; j < showChildEv->mPrecedingEvents.Length(); j++) {
     529           0 :                     logging::AccessibleInfo("Adoptee",
     530           0 :                       showChildEv->mPrecedingEvents[i]->mAccessible);
     531             :                   }
     532           0 :                   logging::MsgEnd();
     533             :                 }
     534             : #endif
     535           0 :                 showEv->mPrecedingEvents.AppendElements(showChildEv->mPrecedingEvents);
     536             :               }
     537             :             }
     538             :           }
     539             :         }
     540             : 
     541           0 :         *node = Move((*node)->mNext);
     542           0 :         break;
     543             :       }
     544           0 :       cntr = cntr->Parent();
     545             :     }
     546           0 :     if (cntr == aEv->mAccessible) {
     547           0 :       continue;
     548             :     }
     549           0 :     node = &(*node)->mNext;
     550             :   }
     551             : 
     552           0 :   AccMutationEvent* prevEvent = mDependentEvents.SafeLastElement(nullptr);
     553           0 :   mDependentEvents.AppendElement(aEv);
     554             : 
     555             :   // Coalesce text change events from this hide/show event and the previous one.
     556           0 :   if (prevEvent && aEv->mEventType == prevEvent->mEventType) {
     557           0 :     if (aEv->IsHide()) {
     558             :       // XXX: we need a way to ignore SplitNode and JoinNode() when they do not
     559             :       // affect the text within the hypertext.
     560           0 :       AccTextChangeEvent* prevTextEvent = prevEvent->mTextChangeEvent;
     561           0 :       if (prevTextEvent) {
     562           0 :         AccHideEvent* hideEvent = downcast_accEvent(aEv);
     563           0 :         AccHideEvent* prevHideEvent = downcast_accEvent(prevEvent);
     564             : 
     565           0 :         if (prevHideEvent->mNextSibling == hideEvent->mAccessible) {
     566           0 :           hideEvent->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
     567             :         }
     568           0 :         else if (prevHideEvent->mPrevSibling == hideEvent->mAccessible) {
     569           0 :           uint32_t oldLen = prevTextEvent->GetLength();
     570           0 :           hideEvent->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
     571           0 :           prevTextEvent->mStart -= prevTextEvent->GetLength() - oldLen;
     572             :         }
     573             : 
     574           0 :         hideEvent->mTextChangeEvent.swap(prevEvent->mTextChangeEvent);
     575             :       }
     576             :     }
     577             :     else {
     578           0 :       AccTextChangeEvent* prevTextEvent = prevEvent->mTextChangeEvent;
     579           0 :       if (prevTextEvent) {
     580           0 :         if (aEv->mAccessible->IndexInParent() ==
     581           0 :             prevEvent->mAccessible->IndexInParent() + 1) {
     582             :           // If tail target was inserted after this target, i.e. tail target is next
     583             :           // sibling of this target.
     584           0 :           aEv->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
     585             :         }
     586           0 :         else if (aEv->mAccessible->IndexInParent() ==
     587           0 :                  prevEvent->mAccessible->IndexInParent() - 1) {
     588             :           // If tail target was inserted before this target, i.e. tail target is
     589             :           // previous sibling of this target.
     590           0 :           nsAutoString startText;
     591           0 :           aEv->mAccessible->AppendTextTo(startText);
     592           0 :           prevTextEvent->mModifiedText = startText + prevTextEvent->mModifiedText;
     593           0 :           prevTextEvent->mStart -= startText.Length();
     594             :         }
     595             : 
     596           0 :         aEv->mTextChangeEvent.swap(prevEvent->mTextChangeEvent);
     597             :       }
     598             :     }
     599             :   }
     600             : 
     601             :   // Create a text change event caused by this hide/show event. When a node is
     602             :   // hidden/removed or shown/appended, the text in an ancestor hyper text will
     603             :   // lose or get new characters.
     604           0 :   if (aEv->mTextChangeEvent || !mContainer->IsHyperText()) {
     605           0 :     return;
     606             :   }
     607             : 
     608           0 :   nsAutoString text;
     609           0 :   aEv->mAccessible->AppendTextTo(text);
     610           0 :   if (text.IsEmpty()) {
     611           0 :     return;
     612             :   }
     613             : 
     614           0 :   int32_t offset = mContainer->AsHyperText()->GetChildOffset(aEv->mAccessible);
     615           0 :   aEv->mTextChangeEvent =
     616           0 :     new AccTextChangeEvent(mContainer, offset, text, aEv->IsShow(),
     617           0 :                            aEv->mIsFromUserInput ? eFromUserInput : eNoUserInput);
     618             : }

Generated by: LCOV version 1.13