tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

AccEvent.cpp (10504B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "AccEvent.h"
      8 
      9 #include "nsAccUtils.h"
     10 #include "xpcAccEvents.h"
     11 #include "States.h"
     12 #include "TextRange.h"
     13 #include "xpcAccessibleDocument.h"
     14 #include "xpcAccessibleTextRange.h"
     15 
     16 #include "mozilla/dom/Selection.h"
     17 #include "mozilla/dom/UserActivation.h"
     18 
     19 #include "nsComponentManagerUtils.h"
     20 #include "nsIMutableArray.h"
     21 
     22 using namespace mozilla;
     23 using namespace mozilla::a11y;
     24 
     25 static_assert(static_cast<bool>(eNoUserInput) == false &&
     26                  static_cast<bool>(eFromUserInput) == true,
     27              "EIsFromUserInput cannot be casted to bool");
     28 
     29 ////////////////////////////////////////////////////////////////////////////////
     30 // AccEvent
     31 ////////////////////////////////////////////////////////////////////////////////
     32 
     33 ////////////////////////////////////////////////////////////////////////////////
     34 // AccEvent constructors
     35 
     36 AccEvent::AccEvent(uint32_t aEventType, LocalAccessible* aAccessible,
     37                   EIsFromUserInput aIsFromUserInput, EEventRule aEventRule)
     38    : mEventType(aEventType), mEventRule(aEventRule), mAccessible(aAccessible) {
     39  if (aIsFromUserInput == eAutoDetect) {
     40    mIsFromUserInput = dom::UserActivation::IsHandlingUserInput();
     41  } else {
     42    mIsFromUserInput = aIsFromUserInput == eFromUserInput ? true : false;
     43  }
     44 }
     45 
     46 ////////////////////////////////////////////////////////////////////////////////
     47 // AccEvent cycle collection
     48 
     49 NS_IMPL_CYCLE_COLLECTION_CLASS(AccEvent)
     50 
     51 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AccEvent)
     52  NS_IMPL_CYCLE_COLLECTION_UNLINK(mAccessible)
     53  if (AccTreeMutationEvent* tmEvent = downcast_accEvent(tmp)) {
     54    tmEvent->SetNextEvent(nullptr);
     55    tmEvent->SetPrevEvent(nullptr);
     56  }
     57 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     58 
     59 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AccEvent)
     60  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAccessible)
     61  if (AccTreeMutationEvent* tmEvent = downcast_accEvent(tmp)) {
     62    CycleCollectionNoteChild(cb, tmEvent->NextEvent(), "mNext");
     63    CycleCollectionNoteChild(cb, tmEvent->PrevEvent(), "mPrevEvent");
     64  }
     65 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     66 
     67 ////////////////////////////////////////////////////////////////////////////////
     68 ////////////////////////////////////////////////////////////////////////////////
     69 // AccTextChangeEvent
     70 ////////////////////////////////////////////////////////////////////////////////
     71 
     72 // Note: we pass in eAllowDupes to the base class because we don't support text
     73 // events coalescence. We fire delayed text change events in DocAccessible but
     74 // we continue to base the event off the accessible object rather than just the
     75 // node. This means we won't try to create an accessible based on the node when
     76 // we are ready to fire the event and so we will no longer assert at that point
     77 // if the node was removed from the document. Either way, the AT won't work with
     78 // a defunct accessible so the behaviour should be equivalent.
     79 AccTextChangeEvent::AccTextChangeEvent(LocalAccessible* aAccessible,
     80                                       int32_t aStart,
     81                                       const nsAString& aModifiedText,
     82                                       bool aIsInserted,
     83                                       EIsFromUserInput aIsFromUserInput)
     84    : AccEvent(
     85          aIsInserted
     86              ? static_cast<uint32_t>(nsIAccessibleEvent::EVENT_TEXT_INSERTED)
     87              : static_cast<uint32_t>(nsIAccessibleEvent::EVENT_TEXT_REMOVED),
     88          aAccessible, aIsFromUserInput, eAllowDupes),
     89      mStart(aStart),
     90      mIsInserted(aIsInserted),
     91      mModifiedText(aModifiedText) {
     92  // XXX We should use IsFromUserInput here, but that isn't always correct
     93  // when the text change isn't related to content insertion or removal.
     94  mIsFromUserInput =
     95      mAccessible->State() & (states::FOCUSED | states::EDITABLE);
     96 }
     97 
     98 ////////////////////////////////////////////////////////////////////////////////
     99 // AccHideEvent
    100 ////////////////////////////////////////////////////////////////////////////////
    101 
    102 AccHideEvent::AccHideEvent(LocalAccessible* aTarget, bool aNeedsShutdown)
    103    : AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget),
    104      mNeedsShutdown(aNeedsShutdown) {
    105  mNextSibling = mAccessible->LocalNextSibling();
    106  mPrevSibling = mAccessible->LocalPrevSibling();
    107 }
    108 
    109 ////////////////////////////////////////////////////////////////////////////////
    110 // AccShowEvent
    111 ////////////////////////////////////////////////////////////////////////////////
    112 
    113 ////////////////////////////////////////////////////////////////////////////////
    114 // AccTextSelChangeEvent
    115 ////////////////////////////////////////////////////////////////////////////////
    116 
    117 AccTextSelChangeEvent::AccTextSelChangeEvent(HyperTextAccessible* aTarget,
    118                                             dom::Selection* aSelection,
    119                                             int32_t aReason,
    120                                             int32_t aGranularity)
    121    : AccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED, aTarget,
    122               eAutoDetect, eCoalesceTextSelChange),
    123      mSel(aSelection),
    124      mReason(aReason),
    125      mGranularity(aGranularity) {}
    126 
    127 AccTextSelChangeEvent::~AccTextSelChangeEvent() {}
    128 
    129 bool AccTextSelChangeEvent::IsCaretMoveOnly() const {
    130  return mSel->RangeCount() == 1 && mSel->IsCollapsed() &&
    131         ((mReason & (nsISelectionListener::COLLAPSETOSTART_REASON |
    132                      nsISelectionListener::COLLAPSETOEND_REASON)) == 0);
    133 }
    134 
    135 void AccTextSelChangeEvent::SelectionRanges(
    136    nsTArray<TextRange>* aRanges) const {
    137  TextRange::TextRangesFromSelection(mSel, aRanges);
    138 }
    139 
    140 ////////////////////////////////////////////////////////////////////////////////
    141 // AccSelChangeEvent
    142 ////////////////////////////////////////////////////////////////////////////////
    143 
    144 AccSelChangeEvent::AccSelChangeEvent(LocalAccessible* aWidget,
    145                                     LocalAccessible* aItem,
    146                                     SelChangeType aSelChangeType)
    147    : AccEvent(0, aItem, eAutoDetect, eCoalesceSelectionChange),
    148      mWidget(aWidget),
    149      mItem(aItem),
    150      mSelChangeType(aSelChangeType),
    151      mPreceedingCount(0),
    152      mPackedEvent(nullptr) {
    153  if (aSelChangeType == eSelectionAdd) {
    154    if (mWidget->GetSelectedItem(1)) {
    155      mEventType = nsIAccessibleEvent::EVENT_SELECTION_ADD;
    156    } else {
    157      mEventType = nsIAccessibleEvent::EVENT_SELECTION;
    158    }
    159  } else {
    160    mEventType = nsIAccessibleEvent::EVENT_SELECTION_REMOVE;
    161  }
    162 }
    163 
    164 already_AddRefed<nsIAccessibleEvent> a11y::MakeXPCEvent(AccEvent* aEvent) {
    165  DocAccessible* doc = aEvent->Document();
    166  LocalAccessible* acc = aEvent->GetAccessible();
    167  nsINode* node = acc->GetNode();
    168  bool fromUser = aEvent->IsFromUserInput();
    169  uint32_t type = aEvent->GetEventType();
    170  uint32_t eventGroup = aEvent->GetEventGroups();
    171  nsCOMPtr<nsIAccessibleEvent> xpEvent;
    172 
    173  if (eventGroup & (1 << AccEvent::eStateChangeEvent)) {
    174    AccStateChangeEvent* sc = downcast_accEvent(aEvent);
    175    bool extra = false;
    176    uint32_t state = nsAccUtils::To32States(sc->GetState(), &extra);
    177    xpEvent = new xpcAccStateChangeEvent(type, ToXPC(acc), ToXPCDocument(doc),
    178                                         node, fromUser, state, extra,
    179                                         sc->IsStateEnabled());
    180    return xpEvent.forget();
    181  }
    182 
    183  if (eventGroup & (1 << AccEvent::eTextChangeEvent)) {
    184    AccTextChangeEvent* tc = downcast_accEvent(aEvent);
    185    nsString text;
    186    tc->GetModifiedText(text);
    187    xpEvent = new xpcAccTextChangeEvent(
    188        type, ToXPC(acc), ToXPCDocument(doc), node, fromUser,
    189        tc->GetStartOffset(), tc->GetLength(), tc->IsTextInserted(), text);
    190    return xpEvent.forget();
    191  }
    192 
    193  if (eventGroup & (1 << AccEvent::eHideEvent)) {
    194    AccHideEvent* hideEvent = downcast_accEvent(aEvent);
    195    xpEvent = new xpcAccHideEvent(type, ToXPC(acc), ToXPCDocument(doc), node,
    196                                  fromUser, ToXPC(hideEvent->TargetParent()),
    197                                  ToXPC(hideEvent->TargetNextSibling()),
    198                                  ToXPC(hideEvent->TargetPrevSibling()));
    199    return xpEvent.forget();
    200  }
    201 
    202  if (eventGroup & (1 << AccEvent::eCaretMoveEvent)) {
    203    AccCaretMoveEvent* cm = downcast_accEvent(aEvent);
    204    xpEvent = new xpcAccCaretMoveEvent(
    205        type, ToXPC(acc), ToXPCDocument(doc), node, fromUser,
    206        cm->GetCaretOffset(), cm->IsSelectionCollapsed(), cm->IsAtEndOfLine(),
    207        cm->GetGranularity());
    208    return xpEvent.forget();
    209  }
    210 
    211  if (eventGroup & (1 << AccEvent::eTextSelChangeEvent)) {
    212    AccTextSelChangeEvent* tsc = downcast_accEvent(aEvent);
    213    AutoTArray<TextRange, 1> ranges;
    214    tsc->SelectionRanges(&ranges);
    215 
    216    nsCOMPtr<nsIMutableArray> xpcRanges =
    217        do_CreateInstance(NS_ARRAY_CONTRACTID);
    218    uint32_t len = ranges.Length();
    219    for (uint32_t idx = 0; idx < len; idx++) {
    220      xpcRanges->AppendElement(new xpcAccessibleTextRange(ranges[idx]));
    221    }
    222 
    223    xpEvent = new xpcAccTextSelectionChangeEvent(
    224        type, ToXPC(acc), ToXPCDocument(doc), node, fromUser, xpcRanges);
    225    return xpEvent.forget();
    226  }
    227 
    228  if (eventGroup & (1 << AccEvent::eObjectAttrChangedEvent)) {
    229    AccObjectAttrChangedEvent* oac = downcast_accEvent(aEvent);
    230    nsString attribute;
    231    oac->GetAttribute()->ToString(attribute);
    232    xpEvent = new xpcAccObjectAttributeChangedEvent(
    233        type, ToXPC(acc), ToXPCDocument(doc), node, fromUser, attribute);
    234    return xpEvent.forget();
    235  }
    236 
    237  if (eventGroup & (1 << AccEvent::eScrollingEvent)) {
    238    AccScrollingEvent* sa = downcast_accEvent(aEvent);
    239    xpEvent = new xpcAccScrollingEvent(
    240        type, ToXPC(acc), ToXPCDocument(doc), node, fromUser, sa->ScrollX(),
    241        sa->ScrollY(), sa->MaxScrollX(), sa->MaxScrollY());
    242    return xpEvent.forget();
    243  }
    244 
    245  if (eventGroup & (1 << AccEvent::eAnnouncementEvent)) {
    246    AccAnnouncementEvent* aa = downcast_accEvent(aEvent);
    247    xpEvent = new xpcAccAnnouncementEvent(type, ToXPC(acc), ToXPCDocument(doc),
    248                                          node, fromUser, aa->Announcement(),
    249                                          aa->Priority());
    250    return xpEvent.forget();
    251  }
    252 
    253  xpEvent =
    254      new xpcAccEvent(type, ToXPC(acc), ToXPCDocument(doc), node, fromUser);
    255  return xpEvent.forget();
    256 }