tor-browser

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

ia2AccessibleAction.cpp (6061B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:expandtab:shiftwidth=2:tabstop=2:
      3 */
      4 /* This Source Code Form is subject to the terms of the Mozilla Public
      5 * License, v. 2.0. If a copy of the MPL was not distributed with this
      6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      7 
      8 #include "ia2AccessibleAction.h"
      9 
     10 #include "AccessibleAction_i.c"
     11 
     12 #include "AccessibleWrap.h"
     13 #include "IUnknownImpl.h"
     14 #include "MsaaAccessible.h"
     15 #include "Relation.h"
     16 
     17 using namespace mozilla::a11y;
     18 
     19 Accessible* ia2AccessibleAction::Acc() {
     20  return static_cast<MsaaAccessible*>(this)->Acc();
     21 }
     22 
     23 // IUnknown
     24 
     25 STDMETHODIMP
     26 ia2AccessibleAction::QueryInterface(REFIID iid, void** ppv) {
     27  if (!ppv) return E_INVALIDARG;
     28 
     29  *ppv = nullptr;
     30 
     31  if (IID_IAccessibleAction == iid) {
     32    *ppv = static_cast<IAccessibleAction*>(this);
     33    (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
     34    return S_OK;
     35  }
     36 
     37  return E_NOINTERFACE;
     38 }
     39 
     40 // IAccessibleAction
     41 
     42 STDMETHODIMP
     43 ia2AccessibleAction::nActions(long* aActionCount) {
     44  if (!aActionCount) return E_INVALIDARG;
     45 
     46  *aActionCount = 0;
     47 
     48  Accessible* acc = Acc();
     49  if (!acc) return CO_E_OBJNOTCONNECTED;
     50 
     51  *aActionCount = acc->ActionCount();
     52  Relation customActions(acc->RelationByType(RelationType::ACTION));
     53  while (Accessible* target = customActions.Next()) {
     54    if (target->HasPrimaryAction()) {
     55      (*aActionCount)++;
     56    }
     57  }
     58 
     59  return S_OK;
     60 }
     61 
     62 STDMETHODIMP
     63 ia2AccessibleAction::doAction(long aActionIndex) {
     64  Accessible* acc = Acc();
     65  if (!acc) return CO_E_OBJNOTCONNECTED;
     66 
     67  uint8_t index = static_cast<uint8_t>(aActionIndex);
     68 
     69  if (index < acc->ActionCount()) {
     70    DebugOnly<bool> success = acc->DoAction(aActionIndex);
     71    MOZ_ASSERT(success, "Failed to perform action");
     72    return S_OK;
     73  }
     74 
     75  // Check for custom actions.
     76  Relation customActions(acc->RelationByType(RelationType::ACTION));
     77  uint8_t actionIndex = acc->ActionCount();
     78  while (Accessible* target = customActions.Next()) {
     79    if (target->HasPrimaryAction()) {
     80      MOZ_ASSERT(target->ActionCount() > 0);
     81      if (actionIndex == index) {
     82        DebugOnly<bool> success = target->DoAction(0);
     83        MOZ_ASSERT(success, "Failed to perform action");
     84        return S_OK;
     85      }
     86      actionIndex++;
     87    }
     88  }
     89 
     90  return E_INVALIDARG;
     91 }
     92 
     93 STDMETHODIMP
     94 ia2AccessibleAction::get_description(long aActionIndex, BSTR* aDescription) {
     95  return get_localizedName(aActionIndex, aDescription);
     96 }
     97 
     98 STDMETHODIMP
     99 ia2AccessibleAction::get_keyBinding(long aActionIndex, long aNumMaxBinding,
    100                                    BSTR** aKeyBinding, long* aNumBinding) {
    101  if (!aKeyBinding) return E_INVALIDARG;
    102  *aKeyBinding = nullptr;
    103 
    104  if (!aNumBinding) return E_INVALIDARG;
    105  *aNumBinding = 0;
    106 
    107  if (aActionIndex != 0 || aNumMaxBinding < 1) return E_INVALIDARG;
    108 
    109  Accessible* acc = Acc();
    110  if (!acc) return CO_E_OBJNOTCONNECTED;
    111 
    112  // Expose KeyboardShortcut if it's not exposed via MSAA accKeyboardShortcut.
    113  LocalAccessible* localAcc = acc->AsLocal();
    114  if (!localAcc) {
    115    // RemoteAccessibles can't have a KeyboardShortcut.
    116    return S_FALSE;
    117  }
    118 
    119  KeyBinding keyBinding = acc->AccessKey();
    120  if (keyBinding.IsEmpty()) {
    121    // In this case, KeyboardShortcut will be exposed via MSAA
    122    // accKeyboardShortcut.
    123    return S_FALSE;
    124  }
    125 
    126  // MSAA accKeyboardShortcut will expose AccessKey.
    127  keyBinding = localAcc->KeyboardShortcut();
    128  if (keyBinding.IsEmpty()) return S_FALSE;
    129 
    130  nsAutoString keyStr;
    131  keyBinding.ToString(keyStr);
    132 
    133  *aKeyBinding = static_cast<BSTR*>(::CoTaskMemAlloc(sizeof(BSTR*)));
    134  if (!*aKeyBinding) return E_OUTOFMEMORY;
    135 
    136  *(aKeyBinding[0]) = ::SysAllocStringLen(keyStr.get(), keyStr.Length());
    137  if (!*(aKeyBinding[0])) {
    138    ::CoTaskMemFree(*aKeyBinding);
    139    return E_OUTOFMEMORY;
    140  }
    141 
    142  *aNumBinding = 1;
    143  return S_OK;
    144 }
    145 
    146 STDMETHODIMP
    147 ia2AccessibleAction::get_name(long aActionIndex, BSTR* aName) {
    148  if (!aName) return E_INVALIDARG;
    149 
    150  *aName = nullptr;
    151 
    152  Accessible* acc = Acc();
    153  if (!acc) return CO_E_OBJNOTCONNECTED;
    154 
    155  nsAutoString name;
    156  uint8_t index = static_cast<uint8_t>(aActionIndex);
    157  if (index < acc->ActionCount()) {
    158    acc->ActionNameAt(aActionIndex, name);
    159  } else {
    160    // Check for custom actions.
    161    Relation customActions(acc->RelationByType(RelationType::ACTION));
    162    uint8_t actionIndex = acc->ActionCount();
    163    while (Accessible* target = customActions.Next()) {
    164      if (target->HasPrimaryAction()) {
    165        MOZ_ASSERT(target->ActionCount() > 0);
    166        if (actionIndex == index) {
    167          name.AssignLiteral("custom");
    168          nsAutoString domNodeId;
    169          target->DOMNodeID(domNodeId);
    170          if (!domNodeId.IsEmpty()) {
    171            name.AppendPrintf("_%s", NS_ConvertUTF16toUTF8(domNodeId).get());
    172          }
    173          break;
    174        }
    175        actionIndex++;
    176      }
    177    }
    178  }
    179 
    180  if (name.IsEmpty()) return E_INVALIDARG;
    181 
    182  *aName = ::SysAllocStringLen(name.get(), name.Length());
    183  return *aName ? S_OK : E_OUTOFMEMORY;
    184 }
    185 
    186 STDMETHODIMP
    187 ia2AccessibleAction::get_localizedName(long aActionIndex,
    188                                       BSTR* aLocalizedName) {
    189  if (!aLocalizedName) return E_INVALIDARG;
    190  *aLocalizedName = nullptr;
    191 
    192  Accessible* acc = Acc();
    193  if (!acc) return CO_E_OBJNOTCONNECTED;
    194 
    195  nsAutoString description;
    196  uint8_t index = static_cast<uint8_t>(aActionIndex);
    197 
    198  if (aActionIndex < acc->ActionCount()) {
    199    acc->ActionDescriptionAt(index, description);
    200  } else {
    201    // Check for custom actions.
    202    Relation customActions(acc->RelationByType(RelationType::ACTION));
    203    uint8_t actionIndex = acc->ActionCount();
    204    while (Accessible* target = customActions.Next()) {
    205      if (target->HasPrimaryAction()) {
    206        MOZ_ASSERT(target->ActionCount() > 0);
    207        if (actionIndex == index) {
    208          target->Name(description);
    209          break;
    210        }
    211        actionIndex++;
    212      }
    213    }
    214  }
    215 
    216  if (description.IsEmpty()) return S_FALSE;
    217 
    218  *aLocalizedName =
    219      ::SysAllocStringLen(description.get(), description.Length());
    220  return *aLocalizedName ? S_OK : E_OUTOFMEMORY;
    221 }