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 
15 using namespace mozilla::a11y;
16 
17 // IUnknown
18 
19 STDMETHODIMP
QueryInterface(REFIID iid,void ** ppv)20 ia2AccessibleAction::QueryInterface(REFIID iid, void** ppv) {
21   if (!ppv) return E_INVALIDARG;
22 
23   *ppv = nullptr;
24 
25   if (IID_IAccessibleAction == iid &&
26       !static_cast<AccessibleWrap*>(this)->IsProxy()) {
27     *ppv = static_cast<IAccessibleAction*>(this);
28     (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
29     return S_OK;
30   }
31 
32   return E_NOINTERFACE;
33 }
34 
35 // IAccessibleAction
36 
37 STDMETHODIMP
nActions(long * aActionCount)38 ia2AccessibleAction::nActions(long* aActionCount) {
39   if (!aActionCount) return E_INVALIDARG;
40 
41   *aActionCount = 0;
42 
43   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
44   if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
45 
46   *aActionCount = acc->ActionCount();
47   return S_OK;
48 }
49 
50 STDMETHODIMP
doAction(long aActionIndex)51 ia2AccessibleAction::doAction(long aActionIndex) {
52   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
53   if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
54 
55   uint8_t index = static_cast<uint8_t>(aActionIndex);
56   return acc->DoAction(index) ? S_OK : E_INVALIDARG;
57 }
58 
59 STDMETHODIMP
get_description(long aActionIndex,BSTR * aDescription)60 ia2AccessibleAction::get_description(long aActionIndex, BSTR* aDescription) {
61   if (!aDescription) return E_INVALIDARG;
62   *aDescription = nullptr;
63 
64   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
65   if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
66 
67   nsAutoString description;
68   uint8_t index = static_cast<uint8_t>(aActionIndex);
69   acc->ActionDescriptionAt(index, description);
70   if (description.IsEmpty()) return S_FALSE;
71 
72   *aDescription = ::SysAllocStringLen(description.get(), description.Length());
73   return *aDescription ? S_OK : E_OUTOFMEMORY;
74 }
75 
76 STDMETHODIMP
get_keyBinding(long aActionIndex,long aNumMaxBinding,BSTR ** aKeyBinding,long * aNumBinding)77 ia2AccessibleAction::get_keyBinding(long aActionIndex, long aNumMaxBinding,
78                                     BSTR** aKeyBinding, long* aNumBinding) {
79   if (!aKeyBinding) return E_INVALIDARG;
80   *aKeyBinding = nullptr;
81 
82   if (!aNumBinding) return E_INVALIDARG;
83   *aNumBinding = 0;
84 
85   if (aActionIndex != 0 || aNumMaxBinding < 1) return E_INVALIDARG;
86 
87   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
88   if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
89 
90   // Expose keyboard shortcut if it's not exposed via MSAA keyboard shortcut.
91   KeyBinding keyBinding = acc->AccessKey();
92   if (keyBinding.IsEmpty()) return S_FALSE;
93 
94   keyBinding = acc->KeyboardShortcut();
95   if (keyBinding.IsEmpty()) return S_FALSE;
96 
97   nsAutoString keyStr;
98   keyBinding.ToString(keyStr);
99 
100   *aKeyBinding = static_cast<BSTR*>(::CoTaskMemAlloc(sizeof(BSTR*)));
101   if (!*aKeyBinding) return E_OUTOFMEMORY;
102 
103   *(aKeyBinding[0]) = ::SysAllocStringLen(keyStr.get(), keyStr.Length());
104   if (!*(aKeyBinding[0])) {
105     ::CoTaskMemFree(*aKeyBinding);
106     return E_OUTOFMEMORY;
107   }
108 
109   *aNumBinding = 1;
110   return S_OK;
111 }
112 
113 STDMETHODIMP
get_name(long aActionIndex,BSTR * aName)114 ia2AccessibleAction::get_name(long aActionIndex, BSTR* aName) {
115   if (!aName) return E_INVALIDARG;
116 
117   *aName = nullptr;
118 
119   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
120   if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
121 
122   nsAutoString name;
123   uint8_t index = static_cast<uint8_t>(aActionIndex);
124   acc->ActionNameAt(index, name);
125   if (name.IsEmpty()) return E_INVALIDARG;
126 
127   *aName = ::SysAllocStringLen(name.get(), name.Length());
128   return *aName ? S_OK : E_OUTOFMEMORY;
129 }
130 
131 STDMETHODIMP
get_localizedName(long aActionIndex,BSTR * aLocalizedName)132 ia2AccessibleAction::get_localizedName(long aActionIndex,
133                                        BSTR* aLocalizedName) {
134   if (!aLocalizedName) return E_INVALIDARG;
135 
136   *aLocalizedName = nullptr;
137   return E_NOTIMPL;
138 }
139