|
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 "nsIURI.h" |
|
8 #include "nsMaiHyperlink.h" |
|
9 |
|
10 using namespace mozilla::a11y; |
|
11 |
|
12 /* MaiAtkHyperlink */ |
|
13 |
|
14 #define MAI_TYPE_ATK_HYPERLINK (mai_atk_hyperlink_get_type ()) |
|
15 #define MAI_ATK_HYPERLINK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\ |
|
16 MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlink)) |
|
17 #define MAI_ATK_HYPERLINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\ |
|
18 MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlinkClass)) |
|
19 #define MAI_IS_ATK_HYPERLINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\ |
|
20 MAI_TYPE_ATK_HYPERLINK)) |
|
21 #define MAI_IS_ATK_HYPERLINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\ |
|
22 MAI_TYPE_ATK_HYPERLINK)) |
|
23 #define MAI_ATK_HYPERLINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\ |
|
24 MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlinkClass)) |
|
25 |
|
26 /** |
|
27 * This MaiAtkHyperlink is a thin wrapper, in the MAI namespace, |
|
28 * for AtkHyperlink |
|
29 */ |
|
30 |
|
31 struct MaiAtkHyperlink |
|
32 { |
|
33 AtkHyperlink parent; |
|
34 |
|
35 /* |
|
36 * The MaiHyperlink whose properties and features are exported via this |
|
37 * hyperlink instance. |
|
38 */ |
|
39 MaiHyperlink *maiHyperlink; |
|
40 }; |
|
41 |
|
42 struct MaiAtkHyperlinkClass |
|
43 { |
|
44 AtkHyperlinkClass parent_class; |
|
45 }; |
|
46 |
|
47 GType mai_atk_hyperlink_get_type(void); |
|
48 |
|
49 G_BEGIN_DECLS |
|
50 /* callbacks for AtkHyperlink */ |
|
51 static void classInitCB(AtkHyperlinkClass *aClass); |
|
52 static void finalizeCB(GObject *aObj); |
|
53 |
|
54 /* callbacks for AtkHyperlink virtual functions */ |
|
55 static gchar *getUriCB(AtkHyperlink *aLink, gint aLinkIndex); |
|
56 static AtkObject *getObjectCB(AtkHyperlink *aLink, gint aLinkIndex); |
|
57 static gint getEndIndexCB(AtkHyperlink *aLink); |
|
58 static gint getStartIndexCB(AtkHyperlink *aLink); |
|
59 static gboolean isValidCB(AtkHyperlink *aLink); |
|
60 static gint getAnchorCountCB(AtkHyperlink *aLink); |
|
61 G_END_DECLS |
|
62 |
|
63 static gpointer parent_class = nullptr; |
|
64 static Accessible* |
|
65 get_accessible_hyperlink(AtkHyperlink *aHyperlink); |
|
66 |
|
67 GType |
|
68 mai_atk_hyperlink_get_type(void) |
|
69 { |
|
70 static GType type = 0; |
|
71 |
|
72 if (!type) { |
|
73 static const GTypeInfo tinfo = { |
|
74 sizeof(MaiAtkHyperlinkClass), |
|
75 (GBaseInitFunc)nullptr, |
|
76 (GBaseFinalizeFunc)nullptr, |
|
77 (GClassInitFunc)classInitCB, |
|
78 (GClassFinalizeFunc)nullptr, |
|
79 nullptr, /* class data */ |
|
80 sizeof(MaiAtkHyperlink), /* instance size */ |
|
81 0, /* nb preallocs */ |
|
82 (GInstanceInitFunc)nullptr, |
|
83 nullptr /* value table */ |
|
84 }; |
|
85 |
|
86 type = g_type_register_static(ATK_TYPE_HYPERLINK, |
|
87 "MaiAtkHyperlink", |
|
88 &tinfo, GTypeFlags(0)); |
|
89 } |
|
90 return type; |
|
91 } |
|
92 |
|
93 MaiHyperlink::MaiHyperlink(Accessible* aHyperLink) : |
|
94 mHyperlink(aHyperLink), |
|
95 mMaiAtkHyperlink(nullptr) |
|
96 { |
|
97 } |
|
98 |
|
99 MaiHyperlink::~MaiHyperlink() |
|
100 { |
|
101 if (mMaiAtkHyperlink) { |
|
102 MAI_ATK_HYPERLINK(mMaiAtkHyperlink)->maiHyperlink = nullptr; |
|
103 g_object_unref(mMaiAtkHyperlink); |
|
104 } |
|
105 } |
|
106 |
|
107 AtkHyperlink* |
|
108 MaiHyperlink::GetAtkHyperlink(void) |
|
109 { |
|
110 NS_ENSURE_TRUE(mHyperlink, nullptr); |
|
111 |
|
112 if (mMaiAtkHyperlink) |
|
113 return mMaiAtkHyperlink; |
|
114 |
|
115 if (!mHyperlink->IsLink()) |
|
116 return nullptr; |
|
117 |
|
118 mMaiAtkHyperlink = |
|
119 reinterpret_cast<AtkHyperlink *> |
|
120 (g_object_new(mai_atk_hyperlink_get_type(), nullptr)); |
|
121 NS_ASSERTION(mMaiAtkHyperlink, "OUT OF MEMORY"); |
|
122 NS_ENSURE_TRUE(mMaiAtkHyperlink, nullptr); |
|
123 |
|
124 /* be sure to initialize it with "this" */ |
|
125 MaiHyperlink::Initialize(mMaiAtkHyperlink, this); |
|
126 |
|
127 return mMaiAtkHyperlink; |
|
128 } |
|
129 |
|
130 /* static */ |
|
131 |
|
132 /* remember to call this static function when a MaiAtkHyperlink |
|
133 * is created |
|
134 */ |
|
135 |
|
136 nsresult |
|
137 MaiHyperlink::Initialize(AtkHyperlink *aObj, MaiHyperlink *aHyperlink) |
|
138 { |
|
139 NS_ENSURE_ARG(MAI_IS_ATK_HYPERLINK(aObj)); |
|
140 NS_ENSURE_ARG(aHyperlink); |
|
141 |
|
142 /* initialize hyperlink */ |
|
143 MAI_ATK_HYPERLINK(aObj)->maiHyperlink = aHyperlink; |
|
144 return NS_OK; |
|
145 } |
|
146 |
|
147 /* static functions for ATK callbacks */ |
|
148 |
|
149 void |
|
150 classInitCB(AtkHyperlinkClass *aClass) |
|
151 { |
|
152 GObjectClass *gobject_class = G_OBJECT_CLASS(aClass); |
|
153 |
|
154 parent_class = g_type_class_peek_parent(aClass); |
|
155 |
|
156 aClass->get_uri = getUriCB; |
|
157 aClass->get_object = getObjectCB; |
|
158 aClass->get_end_index = getEndIndexCB; |
|
159 aClass->get_start_index = getStartIndexCB; |
|
160 aClass->is_valid = isValidCB; |
|
161 aClass->get_n_anchors = getAnchorCountCB; |
|
162 |
|
163 gobject_class->finalize = finalizeCB; |
|
164 } |
|
165 |
|
166 void |
|
167 finalizeCB(GObject *aObj) |
|
168 { |
|
169 NS_ASSERTION(MAI_IS_ATK_HYPERLINK(aObj), "Invalid MaiAtkHyperlink"); |
|
170 if (!MAI_IS_ATK_HYPERLINK(aObj)) |
|
171 return; |
|
172 |
|
173 MaiAtkHyperlink *maiAtkHyperlink = MAI_ATK_HYPERLINK(aObj); |
|
174 maiAtkHyperlink->maiHyperlink = nullptr; |
|
175 |
|
176 /* call parent finalize function */ |
|
177 if (G_OBJECT_CLASS (parent_class)->finalize) |
|
178 G_OBJECT_CLASS (parent_class)->finalize(aObj); |
|
179 } |
|
180 |
|
181 gchar * |
|
182 getUriCB(AtkHyperlink *aLink, gint aLinkIndex) |
|
183 { |
|
184 Accessible* hyperlink = get_accessible_hyperlink(aLink); |
|
185 NS_ENSURE_TRUE(hyperlink, nullptr); |
|
186 |
|
187 nsCOMPtr<nsIURI> uri = hyperlink->AnchorURIAt(aLinkIndex); |
|
188 if (!uri) |
|
189 return nullptr; |
|
190 |
|
191 nsAutoCString cautoStr; |
|
192 nsresult rv = uri->GetSpec(cautoStr); |
|
193 NS_ENSURE_SUCCESS(rv, nullptr); |
|
194 |
|
195 return g_strdup(cautoStr.get()); |
|
196 } |
|
197 |
|
198 AtkObject * |
|
199 getObjectCB(AtkHyperlink *aLink, gint aLinkIndex) |
|
200 { |
|
201 Accessible* hyperlink = get_accessible_hyperlink(aLink); |
|
202 NS_ENSURE_TRUE(hyperlink, nullptr); |
|
203 |
|
204 Accessible* anchor = hyperlink->AnchorAt(aLinkIndex); |
|
205 NS_ENSURE_TRUE(anchor, nullptr); |
|
206 |
|
207 AtkObject* atkObj = AccessibleWrap::GetAtkObject(anchor); |
|
208 //no need to add ref it, because it is "get" not "ref" |
|
209 return atkObj; |
|
210 } |
|
211 |
|
212 gint |
|
213 getEndIndexCB(AtkHyperlink *aLink) |
|
214 { |
|
215 Accessible* hyperlink = get_accessible_hyperlink(aLink); |
|
216 NS_ENSURE_TRUE(hyperlink, -1); |
|
217 |
|
218 return static_cast<gint>(hyperlink->EndOffset()); |
|
219 } |
|
220 |
|
221 gint |
|
222 getStartIndexCB(AtkHyperlink *aLink) |
|
223 { |
|
224 Accessible* hyperlink = get_accessible_hyperlink(aLink); |
|
225 NS_ENSURE_TRUE(hyperlink, -1); |
|
226 |
|
227 return static_cast<gint>(hyperlink->StartOffset()); |
|
228 } |
|
229 |
|
230 gboolean |
|
231 isValidCB(AtkHyperlink *aLink) |
|
232 { |
|
233 Accessible* hyperlink = get_accessible_hyperlink(aLink); |
|
234 NS_ENSURE_TRUE(hyperlink, FALSE); |
|
235 |
|
236 return static_cast<gboolean>(hyperlink->IsLinkValid()); |
|
237 } |
|
238 |
|
239 gint |
|
240 getAnchorCountCB(AtkHyperlink *aLink) |
|
241 { |
|
242 Accessible* hyperlink = get_accessible_hyperlink(aLink); |
|
243 NS_ENSURE_TRUE(hyperlink, -1); |
|
244 |
|
245 return static_cast<gint>(hyperlink->AnchorCount()); |
|
246 } |
|
247 |
|
248 // Check if aHyperlink is a valid MaiHyperlink, and return the |
|
249 // HyperLinkAccessible related. |
|
250 Accessible* |
|
251 get_accessible_hyperlink(AtkHyperlink *aHyperlink) |
|
252 { |
|
253 NS_ENSURE_TRUE(MAI_IS_ATK_HYPERLINK(aHyperlink), nullptr); |
|
254 MaiHyperlink * maiHyperlink = |
|
255 MAI_ATK_HYPERLINK(aHyperlink)->maiHyperlink; |
|
256 NS_ENSURE_TRUE(maiHyperlink != nullptr, nullptr); |
|
257 NS_ENSURE_TRUE(maiHyperlink->GetAtkHyperlink() == aHyperlink, nullptr); |
|
258 return maiHyperlink->GetAccHyperlink(); |
|
259 } |