LCOV - code coverage report
Current view: top level - accessible/base - EventQueue.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 158 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 5 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 "EventQueue.h"
       7             : 
       8             : #include "Accessible-inl.h"
       9             : #include "nsEventShell.h"
      10             : #include "DocAccessible.h"
      11             : #include "DocAccessibleChild.h"
      12             : #include "nsAccessibilityService.h"
      13             : #include "nsTextEquivUtils.h"
      14             : #ifdef A11Y_LOG
      15             : #include "Logging.h"
      16             : #endif
      17             : 
      18             : using namespace mozilla;
      19             : using namespace mozilla::a11y;
      20             : 
      21             : // Defines the number of selection add/remove events in the queue when they
      22             : // aren't packed into single selection within event.
      23             : const unsigned int kSelChangeCountToPack = 5;
      24             : 
      25             : ////////////////////////////////////////////////////////////////////////////////
      26             : // EventQueue
      27             : ////////////////////////////////////////////////////////////////////////////////
      28             : 
      29             : bool
      30           0 : EventQueue::PushEvent(AccEvent* aEvent)
      31             : {
      32           0 :   NS_ASSERTION((aEvent->mAccessible && aEvent->mAccessible->IsApplication()) ||
      33             :                aEvent->Document() == mDocument,
      34             :                "Queued event belongs to another document!");
      35             : 
      36           0 :   if (!mEvents.AppendElement(aEvent))
      37           0 :     return false;
      38             : 
      39             :   // Filter events.
      40           0 :   CoalesceEvents();
      41             : 
      42           0 :   if (aEvent->mEventRule != AccEvent::eDoNotEmit &&
      43           0 :       (aEvent->mEventType == nsIAccessibleEvent::EVENT_NAME_CHANGE ||
      44           0 :        aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_REMOVED ||
      45           0 :        aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_INSERTED)) {
      46           0 :     PushNameChange(aEvent->mAccessible);
      47             :   }
      48           0 :   return true;
      49             : }
      50             : 
      51             : bool
      52           0 : EventQueue::PushNameChange(Accessible* aTarget)
      53             : {
      54             :   // Fire name change event on parent given that this event hasn't been
      55             :   // coalesced, the parent's name was calculated from its subtree, and the
      56             :   // subtree was changed.
      57           0 :   if (aTarget->HasNameDependentParent()) {
      58             :     // Only continue traversing up the tree if it's possible that the parent
      59             :     // accessible's name can depend on this accessible's name.
      60           0 :     Accessible* parent = aTarget->Parent();
      61           0 :     while (parent &&
      62           0 :            nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeIfReqRule)) {
      63             :       // Test possible name dependent parent.
      64           0 :       if (nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeRule)) {
      65           0 :         nsAutoString name;
      66           0 :         ENameValueFlag nameFlag = parent->Name(name);
      67             :         // If name is obtained from subtree, fire name change event.
      68           0 :         if (nameFlag == eNameFromSubtree) {
      69             :           RefPtr<AccEvent> nameChangeEvent =
      70           0 :             new AccEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, parent);
      71           0 :           return PushEvent(nameChangeEvent);
      72             :         }
      73           0 :         break;
      74             :       }
      75           0 :       parent = parent->Parent();
      76             :     }
      77             :   }
      78           0 :   return false;
      79             : }
      80             : 
      81             : ////////////////////////////////////////////////////////////////////////////////
      82             : // EventQueue: private
      83             : 
      84             : void
      85           0 : EventQueue::CoalesceEvents()
      86             : {
      87           0 :   NS_ASSERTION(mEvents.Length(), "There should be at least one pending event!");
      88           0 :   uint32_t tail = mEvents.Length() - 1;
      89           0 :   AccEvent* tailEvent = mEvents[tail];
      90             : 
      91           0 :   switch(tailEvent->mEventRule) {
      92             :     case AccEvent::eCoalesceReorder:
      93             :     {
      94           0 :       DebugOnly<Accessible*> target = tailEvent->mAccessible.get();
      95           0 :       MOZ_ASSERT(target->IsApplication() ||
      96             :                  target->IsOuterDoc() ||
      97             :                  target->IsXULTree(),
      98             :                  "Only app or outerdoc accessible reorder events are in the queue");
      99           0 :       MOZ_ASSERT(tailEvent->GetEventType() == nsIAccessibleEvent::EVENT_REORDER, "only reorder events should be queued");
     100           0 :       break; // case eCoalesceReorder
     101             :     }
     102             : 
     103             :     case AccEvent::eCoalesceOfSameType:
     104             :     {
     105             :       // Coalesce old events by newer event.
     106           0 :       for (uint32_t index = tail - 1; index < tail; index--) {
     107           0 :         AccEvent* accEvent = mEvents[index];
     108           0 :         if (accEvent->mEventType == tailEvent->mEventType &&
     109           0 :           accEvent->mEventRule == tailEvent->mEventRule) {
     110           0 :           accEvent->mEventRule = AccEvent::eDoNotEmit;
     111           0 :           return;
     112             :         }
     113             :       }
     114           0 :     } break; // case eCoalesceOfSameType
     115             : 
     116             :     case AccEvent::eCoalesceSelectionChange:
     117             :     {
     118           0 :       AccSelChangeEvent* tailSelChangeEvent = downcast_accEvent(tailEvent);
     119           0 :       for (uint32_t index = tail - 1; index < tail; index--) {
     120           0 :         AccEvent* thisEvent = mEvents[index];
     121           0 :         if (thisEvent->mEventRule == tailEvent->mEventRule) {
     122             :           AccSelChangeEvent* thisSelChangeEvent =
     123           0 :             downcast_accEvent(thisEvent);
     124             : 
     125             :           // Coalesce selection change events within same control.
     126           0 :           if (tailSelChangeEvent->mWidget == thisSelChangeEvent->mWidget) {
     127           0 :             CoalesceSelChangeEvents(tailSelChangeEvent, thisSelChangeEvent, index);
     128           0 :             return;
     129             :           }
     130             :         }
     131             :       }
     132             : 
     133           0 :     } break; // eCoalesceSelectionChange
     134             : 
     135             :     case AccEvent::eCoalesceStateChange:
     136             :     {
     137             :       // If state change event is duped then ignore previous event. If state
     138             :       // change event is opposite to previous event then no event is emitted
     139             :       // (accessible state wasn't changed).
     140           0 :       for (uint32_t index = tail - 1; index < tail; index--) {
     141           0 :         AccEvent* thisEvent = mEvents[index];
     142           0 :         if (thisEvent->mEventRule != AccEvent::eDoNotEmit &&
     143           0 :             thisEvent->mEventType == tailEvent->mEventType &&
     144           0 :             thisEvent->mAccessible == tailEvent->mAccessible) {
     145           0 :           AccStateChangeEvent* thisSCEvent = downcast_accEvent(thisEvent);
     146           0 :           AccStateChangeEvent* tailSCEvent = downcast_accEvent(tailEvent);
     147           0 :           if (thisSCEvent->mState == tailSCEvent->mState) {
     148           0 :             thisEvent->mEventRule = AccEvent::eDoNotEmit;
     149           0 :             if (thisSCEvent->mIsEnabled != tailSCEvent->mIsEnabled)
     150           0 :               tailEvent->mEventRule = AccEvent::eDoNotEmit;
     151             :           }
     152             :         }
     153             :       }
     154           0 :       break; // eCoalesceStateChange
     155             :     }
     156             : 
     157             :     case AccEvent::eCoalesceTextSelChange:
     158             :     {
     159             :       // Coalesce older event by newer event for the same selection or target.
     160             :       // Events for same selection may have different targets and vice versa one
     161             :       // target may be pointed by different selections (for latter see
     162             :       // bug 927159).
     163           0 :       for (uint32_t index = tail - 1; index < tail; index--) {
     164           0 :         AccEvent* thisEvent = mEvents[index];
     165           0 :         if (thisEvent->mEventRule != AccEvent::eDoNotEmit &&
     166           0 :             thisEvent->mEventType == tailEvent->mEventType) {
     167           0 :           AccTextSelChangeEvent* thisTSCEvent = downcast_accEvent(thisEvent);
     168           0 :           AccTextSelChangeEvent* tailTSCEvent = downcast_accEvent(tailEvent);
     169           0 :           if (thisTSCEvent->mSel == tailTSCEvent->mSel ||
     170           0 :               thisEvent->mAccessible == tailEvent->mAccessible)
     171           0 :             thisEvent->mEventRule = AccEvent::eDoNotEmit;
     172             :         }
     173             : 
     174             :       }
     175           0 :     } break; // eCoalesceTextSelChange
     176             : 
     177             :     case AccEvent::eRemoveDupes:
     178             :     {
     179             :       // Check for repeat events, coalesce newly appended event by more older
     180             :       // event.
     181           0 :       for (uint32_t index = tail - 1; index < tail; index--) {
     182           0 :         AccEvent* accEvent = mEvents[index];
     183           0 :         if (accEvent->mEventType == tailEvent->mEventType &&
     184           0 :           accEvent->mEventRule == tailEvent->mEventRule &&
     185           0 :           accEvent->mAccessible == tailEvent->mAccessible) {
     186           0 :           tailEvent->mEventRule = AccEvent::eDoNotEmit;
     187           0 :           return;
     188             :         }
     189             :       }
     190           0 :     } break; // case eRemoveDupes
     191             : 
     192             :     default:
     193           0 :       break; // case eAllowDupes, eDoNotEmit
     194             :   } // switch
     195             : }
     196             : 
     197             : void
     198           0 : EventQueue::CoalesceSelChangeEvents(AccSelChangeEvent* aTailEvent,
     199             :                                     AccSelChangeEvent* aThisEvent,
     200             :                                     uint32_t aThisIndex)
     201             : {
     202           0 :   aTailEvent->mPreceedingCount = aThisEvent->mPreceedingCount + 1;
     203             : 
     204             :   // Pack all preceding events into single selection within event
     205             :   // when we receive too much selection add/remove events.
     206           0 :   if (aTailEvent->mPreceedingCount >= kSelChangeCountToPack) {
     207           0 :     aTailEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION_WITHIN;
     208           0 :     aTailEvent->mAccessible = aTailEvent->mWidget;
     209           0 :     aThisEvent->mEventRule = AccEvent::eDoNotEmit;
     210             : 
     211             :     // Do not emit any preceding selection events for same widget if they
     212             :     // weren't coalesced yet.
     213           0 :     if (aThisEvent->mEventType != nsIAccessibleEvent::EVENT_SELECTION_WITHIN) {
     214           0 :       for (uint32_t jdx = aThisIndex - 1; jdx < aThisIndex; jdx--) {
     215           0 :         AccEvent* prevEvent = mEvents[jdx];
     216           0 :         if (prevEvent->mEventRule == aTailEvent->mEventRule) {
     217             :           AccSelChangeEvent* prevSelChangeEvent =
     218           0 :             downcast_accEvent(prevEvent);
     219           0 :           if (prevSelChangeEvent->mWidget == aTailEvent->mWidget)
     220           0 :             prevSelChangeEvent->mEventRule = AccEvent::eDoNotEmit;
     221             :         }
     222             :       }
     223             :     }
     224           0 :     return;
     225             :   }
     226             : 
     227             :   // Pack sequential selection remove and selection add events into
     228             :   // single selection change event.
     229           0 :   if (aTailEvent->mPreceedingCount == 1 &&
     230           0 :       aTailEvent->mItem != aThisEvent->mItem) {
     231           0 :     if (aTailEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd &&
     232           0 :         aThisEvent->mSelChangeType == AccSelChangeEvent::eSelectionRemove) {
     233           0 :       aThisEvent->mEventRule = AccEvent::eDoNotEmit;
     234           0 :       aTailEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION;
     235           0 :       aTailEvent->mPackedEvent = aThisEvent;
     236           0 :       return;
     237             :     }
     238             : 
     239           0 :     if (aThisEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd &&
     240           0 :         aTailEvent->mSelChangeType == AccSelChangeEvent::eSelectionRemove) {
     241           0 :       aTailEvent->mEventRule = AccEvent::eDoNotEmit;
     242           0 :       aThisEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION;
     243           0 :       aThisEvent->mPackedEvent = aTailEvent;
     244           0 :       return;
     245             :     }
     246             :   }
     247             : 
     248             :   // Unpack the packed selection change event because we've got one
     249             :   // more selection add/remove.
     250           0 :   if (aThisEvent->mEventType == nsIAccessibleEvent::EVENT_SELECTION) {
     251           0 :     if (aThisEvent->mPackedEvent) {
     252           0 :       aThisEvent->mPackedEvent->mEventType =
     253           0 :         aThisEvent->mPackedEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd ?
     254             :           nsIAccessibleEvent::EVENT_SELECTION_ADD :
     255             :           nsIAccessibleEvent::EVENT_SELECTION_REMOVE;
     256             : 
     257           0 :       aThisEvent->mPackedEvent->mEventRule =
     258             :         AccEvent::eCoalesceSelectionChange;
     259             : 
     260           0 :       aThisEvent->mPackedEvent = nullptr;
     261             :     }
     262             : 
     263           0 :     aThisEvent->mEventType =
     264           0 :       aThisEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd ?
     265             :         nsIAccessibleEvent::EVENT_SELECTION_ADD :
     266             :         nsIAccessibleEvent::EVENT_SELECTION_REMOVE;
     267             : 
     268           0 :     return;
     269             :   }
     270             : 
     271             :   // Convert into selection add since control has single selection but other
     272             :   // selection events for this control are queued.
     273           0 :   if (aTailEvent->mEventType == nsIAccessibleEvent::EVENT_SELECTION)
     274           0 :     aTailEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION_ADD;
     275             : }
     276             : 
     277             : ////////////////////////////////////////////////////////////////////////////////
     278             : // EventQueue: event queue
     279             : 
     280             : void
     281           0 : EventQueue::ProcessEventQueue()
     282             : {
     283             :   // Process only currently queued events.
     284           0 :   nsTArray<RefPtr<AccEvent> > events;
     285           0 :   events.SwapElements(mEvents);
     286             : 
     287           0 :   uint32_t eventCount = events.Length();
     288             : #ifdef A11Y_LOG
     289           0 :   if (eventCount > 0 && logging::IsEnabled(logging::eEvents)) {
     290           0 :     logging::MsgBegin("EVENTS", "events processing");
     291           0 :     logging::Address("document", mDocument);
     292           0 :     logging::MsgEnd();
     293             :   }
     294             : #endif
     295             : 
     296           0 :   for (uint32_t idx = 0; idx < eventCount; idx++) {
     297           0 :     AccEvent* event = events[idx];
     298           0 :     if (event->mEventRule != AccEvent::eDoNotEmit) {
     299           0 :       Accessible* target = event->GetAccessible();
     300           0 :       if (!target || target->IsDefunct())
     301           0 :         continue;
     302             : 
     303             :       // Dispatch the focus event if target is still focused.
     304           0 :       if (event->mEventType == nsIAccessibleEvent::EVENT_FOCUS) {
     305           0 :         FocusMgr()->ProcessFocusEvent(event);
     306           0 :         continue;
     307             :       }
     308             : 
     309             :       // Dispatch caret moved and text selection change events.
     310           0 :       if (event->mEventType == nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED) {
     311           0 :         SelectionMgr()->ProcessTextSelChangeEvent(event);
     312           0 :         continue;
     313             :       }
     314             : 
     315             :       // Fire selected state change events in support to selection events.
     316           0 :       if (event->mEventType == nsIAccessibleEvent::EVENT_SELECTION_ADD) {
     317           0 :         nsEventShell::FireEvent(event->mAccessible, states::SELECTED,
     318           0 :                                 true, event->mIsFromUserInput);
     319             : 
     320           0 :       } else if (event->mEventType == nsIAccessibleEvent::EVENT_SELECTION_REMOVE) {
     321           0 :         nsEventShell::FireEvent(event->mAccessible, states::SELECTED,
     322           0 :                                 false, event->mIsFromUserInput);
     323             : 
     324           0 :       } else if (event->mEventType == nsIAccessibleEvent::EVENT_SELECTION) {
     325           0 :         AccSelChangeEvent* selChangeEvent = downcast_accEvent(event);
     326           0 :         nsEventShell::FireEvent(event->mAccessible, states::SELECTED,
     327           0 :                                 (selChangeEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd),
     328           0 :                                 event->mIsFromUserInput);
     329             : 
     330           0 :         if (selChangeEvent->mPackedEvent) {
     331           0 :           nsEventShell::FireEvent(selChangeEvent->mPackedEvent->mAccessible,
     332             :                                   states::SELECTED,
     333           0 :                                   (selChangeEvent->mPackedEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd),
     334           0 :                                   selChangeEvent->mPackedEvent->mIsFromUserInput);
     335             :         }
     336             :       }
     337             : 
     338           0 :       nsEventShell::FireEvent(event);
     339             :     }
     340             : 
     341           0 :     if (!mDocument)
     342           0 :       return;
     343             :   }
     344             : }

Generated by: LCOV version 1.13