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 "AccessibleHyperlink.h"
9 #include "AccessibleHyperlink_i.c"
10 
11 #include "AccessibleWrap.h"
12 #include "IUnknownImpl.h"
13 #include "nsIURI.h"
14 
15 using namespace mozilla::a11y;
16 
Acc()17 Accessible* ia2AccessibleHyperlink::Acc() {
18   return static_cast<MsaaAccessible*>(this)->Acc();
19 }
20 
LocalAcc()21 AccessibleWrap* ia2AccessibleHyperlink::LocalAcc() {
22   return static_cast<MsaaAccessible*>(this)->LocalAcc();
23 }
24 
25 // IUnknown
26 
27 STDMETHODIMP
QueryInterface(REFIID iid,void ** ppv)28 ia2AccessibleHyperlink::QueryInterface(REFIID iid, void** ppv) {
29   if (!ppv) return E_INVALIDARG;
30 
31   *ppv = nullptr;
32 
33   if (IID_IAccessibleHyperlink == iid) {
34     Accessible* acc = Acc();
35     if (!acc || !acc->IsLink()) {
36       return E_NOINTERFACE;
37     }
38 
39     *ppv = static_cast<IAccessibleHyperlink*>(this);
40     (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
41     return S_OK;
42   }
43 
44   return ia2AccessibleAction::QueryInterface(iid, ppv);
45 }
46 
47 // IAccessibleHyperlink
48 
49 STDMETHODIMP
get_anchor(long aIndex,VARIANT * aAnchor)50 ia2AccessibleHyperlink::get_anchor(long aIndex, VARIANT* aAnchor) {
51   if (!aAnchor) return E_INVALIDARG;
52 
53   VariantInit(aAnchor);
54 
55   LocalAccessible* thisObj = LocalAcc();
56   if (!thisObj) {
57     return CO_E_OBJNOTCONNECTED;
58   }
59 
60   if (aIndex < 0 || aIndex >= static_cast<long>(thisObj->AnchorCount()))
61     return E_INVALIDARG;
62 
63   if (!thisObj->IsLink()) return S_FALSE;
64 
65   AccessibleWrap* anchor =
66       static_cast<AccessibleWrap*>(thisObj->AnchorAt(aIndex));
67   if (!anchor) return S_FALSE;
68 
69   RefPtr<IAccessible> result;
70   anchor->GetNativeInterface(getter_AddRefs(result));
71   result.forget(&aAnchor->punkVal);
72   aAnchor->vt = VT_UNKNOWN;
73   return S_OK;
74 }
75 
76 STDMETHODIMP
get_anchorTarget(long aIndex,VARIANT * aAnchorTarget)77 ia2AccessibleHyperlink::get_anchorTarget(long aIndex, VARIANT* aAnchorTarget) {
78   if (!aAnchorTarget) {
79     return E_INVALIDARG;
80   }
81 
82   VariantInit(aAnchorTarget);
83 
84   LocalAccessible* thisObj = LocalAcc();
85   if (!thisObj) {
86     return CO_E_OBJNOTCONNECTED;
87   }
88   nsAutoCString uriStr;
89 
90   if (aIndex < 0 || aIndex >= static_cast<long>(thisObj->AnchorCount())) {
91     return E_INVALIDARG;
92   }
93 
94   if (!thisObj->IsLink()) {
95     return S_FALSE;
96   }
97 
98   nsCOMPtr<nsIURI> uri = thisObj->AnchorURIAt(aIndex);
99   if (!uri) {
100     return S_FALSE;
101   }
102 
103   nsresult rv = uri->GetSpec(uriStr);
104   if (NS_FAILED(rv)) {
105     return GetHRESULT(rv);
106   }
107 
108   nsAutoString stringURI;
109   AppendUTF8toUTF16(uriStr, stringURI);
110 
111   aAnchorTarget->vt = VT_BSTR;
112   aAnchorTarget->bstrVal =
113       ::SysAllocStringLen(stringURI.get(), stringURI.Length());
114   return aAnchorTarget->bstrVal ? S_OK : E_OUTOFMEMORY;
115 }
116 
117 STDMETHODIMP
get_startIndex(long * aIndex)118 ia2AccessibleHyperlink::get_startIndex(long* aIndex) {
119   if (!aIndex) return E_INVALIDARG;
120 
121   *aIndex = 0;
122 
123   Accessible* thisObj = Acc();
124   if (!thisObj) {
125     return CO_E_OBJNOTCONNECTED;
126   }
127 
128   if (!thisObj->IsLink()) return S_FALSE;
129 
130   *aIndex = thisObj->StartOffset();
131   return S_OK;
132 }
133 
134 STDMETHODIMP
get_endIndex(long * aIndex)135 ia2AccessibleHyperlink::get_endIndex(long* aIndex) {
136   if (!aIndex) return E_INVALIDARG;
137 
138   *aIndex = 0;
139 
140   Accessible* thisObj = Acc();
141   if (!thisObj) {
142     return CO_E_OBJNOTCONNECTED;
143   }
144 
145   if (!thisObj->IsLink()) return S_FALSE;
146 
147   *aIndex = thisObj->EndOffset();
148   return S_OK;
149 }
150 
151 STDMETHODIMP
get_valid(boolean * aValid)152 ia2AccessibleHyperlink::get_valid(boolean* aValid) {
153   if (!aValid) return E_INVALIDARG;
154 
155   *aValid = false;
156 
157   LocalAccessible* thisObj = LocalAcc();
158   if (!thisObj) {
159     return CO_E_OBJNOTCONNECTED;
160   }
161 
162   if (!thisObj->IsLink()) return S_FALSE;
163 
164   *aValid = thisObj->IsLinkValid();
165   return S_OK;
166 }
167