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/. */
8 #include "nsMaiHyperlink.h"
9 #include "mozilla/a11y/RemoteAccessible.h"
11 using namespace mozilla::a11y
;
15 #define MAI_TYPE_ATK_HYPERLINK (mai_atk_hyperlink_get_type())
16 #define MAI_ATK_HYPERLINK(obj) \
17 (G_TYPE_CHECK_INSTANCE_CAST((obj), MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlink))
18 #define MAI_ATK_HYPERLINK_CLASS(klass) \
19 (G_TYPE_CHECK_CLASS_CAST((klass), MAI_TYPE_ATK_HYPERLINK, \
20 MaiAtkHyperlinkClass))
21 #define MAI_IS_ATK_HYPERLINK(obj) \
22 (G_TYPE_CHECK_INSTANCE_TYPE((obj), MAI_TYPE_ATK_HYPERLINK))
23 #define MAI_IS_ATK_HYPERLINK_CLASS(klass) \
24 (G_TYPE_CHECK_CLASS_TYPE((klass), MAI_TYPE_ATK_HYPERLINK))
25 #define MAI_ATK_HYPERLINK_GET_CLASS(obj) \
26 (G_TYPE_INSTANCE_GET_CLASS((obj), MAI_TYPE_ATK_HYPERLINK, \
27 MaiAtkHyperlinkClass))
30 * This MaiAtkHyperlink is a thin wrapper, in the MAI namespace,
34 struct MaiAtkHyperlink
{
38 * The MaiHyperlink whose properties and features are exported via this
41 MaiHyperlink
* maiHyperlink
;
44 struct MaiAtkHyperlinkClass
{
45 AtkHyperlinkClass parent_class
;
48 GType
mai_atk_hyperlink_get_type(void);
51 /* callbacks for AtkHyperlink */
52 static void classInitCB(AtkHyperlinkClass
* aClass
);
53 static void finalizeCB(GObject
* aObj
);
55 /* callbacks for AtkHyperlink virtual functions */
56 static gchar
* getUriCB(AtkHyperlink
* aLink
, gint aLinkIndex
);
57 static AtkObject
* getObjectCB(AtkHyperlink
* aLink
, gint aLinkIndex
);
58 static gint
getEndIndexCB(AtkHyperlink
* aLink
);
59 static gint
getStartIndexCB(AtkHyperlink
* aLink
);
60 static gboolean
isValidCB(AtkHyperlink
* aLink
);
61 static gint
getAnchorCountCB(AtkHyperlink
* aLink
);
64 static gpointer parent_class
= nullptr;
66 static MaiHyperlink
* GetMaiHyperlink(AtkHyperlink
* aHyperlink
) {
67 NS_ENSURE_TRUE(MAI_IS_ATK_HYPERLINK(aHyperlink
), nullptr);
68 MaiHyperlink
* maiHyperlink
= MAI_ATK_HYPERLINK(aHyperlink
)->maiHyperlink
;
69 NS_ENSURE_TRUE(maiHyperlink
!= nullptr, nullptr);
70 NS_ENSURE_TRUE(maiHyperlink
->GetAtkHyperlink() == aHyperlink
, nullptr);
74 GType
mai_atk_hyperlink_get_type(void) {
75 static GType type
= 0;
78 static const GTypeInfo tinfo
= {
79 sizeof(MaiAtkHyperlinkClass
),
80 (GBaseInitFunc
) nullptr,
81 (GBaseFinalizeFunc
) nullptr,
82 (GClassInitFunc
)classInitCB
,
83 (GClassFinalizeFunc
) nullptr,
84 nullptr, /* class data */
85 sizeof(MaiAtkHyperlink
), /* instance size */
87 (GInstanceInitFunc
) nullptr,
88 nullptr /* value table */
91 type
= g_type_register_static(ATK_TYPE_HYPERLINK
, "MaiAtkHyperlink", &tinfo
,
97 MaiHyperlink::MaiHyperlink(AccessibleOrProxy aHyperLink
)
98 : mHyperlink(aHyperLink
), mMaiAtkHyperlink(nullptr) {
99 mMaiAtkHyperlink
= reinterpret_cast<AtkHyperlink
*>(
100 g_object_new(mai_atk_hyperlink_get_type(), nullptr));
101 NS_ASSERTION(mMaiAtkHyperlink
, "OUT OF MEMORY");
102 if (!mMaiAtkHyperlink
) return;
104 MAI_ATK_HYPERLINK(mMaiAtkHyperlink
)->maiHyperlink
= this;
107 MaiHyperlink::~MaiHyperlink() {
108 if (mMaiAtkHyperlink
) {
109 MAI_ATK_HYPERLINK(mMaiAtkHyperlink
)->maiHyperlink
= nullptr;
110 g_object_unref(mMaiAtkHyperlink
);
114 /* static functions for ATK callbacks */
116 void classInitCB(AtkHyperlinkClass
* aClass
) {
117 GObjectClass
* gobject_class
= G_OBJECT_CLASS(aClass
);
119 parent_class
= g_type_class_peek_parent(aClass
);
121 aClass
->get_uri
= getUriCB
;
122 aClass
->get_object
= getObjectCB
;
123 aClass
->get_end_index
= getEndIndexCB
;
124 aClass
->get_start_index
= getStartIndexCB
;
125 aClass
->is_valid
= isValidCB
;
126 aClass
->get_n_anchors
= getAnchorCountCB
;
128 gobject_class
->finalize
= finalizeCB
;
131 void finalizeCB(GObject
* aObj
) {
132 NS_ASSERTION(MAI_IS_ATK_HYPERLINK(aObj
), "Invalid MaiAtkHyperlink");
133 if (!MAI_IS_ATK_HYPERLINK(aObj
)) return;
135 MaiAtkHyperlink
* maiAtkHyperlink
= MAI_ATK_HYPERLINK(aObj
);
136 maiAtkHyperlink
->maiHyperlink
= nullptr;
138 /* call parent finalize function */
139 if (G_OBJECT_CLASS(parent_class
)->finalize
) {
140 G_OBJECT_CLASS(parent_class
)->finalize(aObj
);
144 gchar
* getUriCB(AtkHyperlink
* aLink
, gint aLinkIndex
) {
145 MaiHyperlink
* maiLink
= GetMaiHyperlink(aLink
);
146 if (!maiLink
) return nullptr;
148 nsAutoCString cautoStr
;
149 if (LocalAccessible
* hyperlink
= maiLink
->GetAccHyperlink()) {
150 nsCOMPtr
<nsIURI
> uri
= hyperlink
->AnchorURIAt(aLinkIndex
);
151 if (!uri
) return nullptr;
153 nsresult rv
= uri
->GetSpec(cautoStr
);
154 NS_ENSURE_SUCCESS(rv
, nullptr);
156 return g_strdup(cautoStr
.get());
160 maiLink
->Proxy()->AnchorURIAt(aLinkIndex
, cautoStr
, &valid
);
161 if (!valid
) return nullptr;
163 return g_strdup(cautoStr
.get());
166 AtkObject
* getObjectCB(AtkHyperlink
* aLink
, gint aLinkIndex
) {
167 MaiHyperlink
* maiLink
= GetMaiHyperlink(aLink
);
172 if (LocalAccessible
* hyperlink
= maiLink
->GetAccHyperlink()) {
173 LocalAccessible
* anchor
= hyperlink
->AnchorAt(aLinkIndex
);
174 NS_ENSURE_TRUE(anchor
, nullptr);
176 return AccessibleWrap::GetAtkObject(anchor
);
179 RemoteAccessible
* anchor
= maiLink
->Proxy()->AnchorAt(aLinkIndex
);
180 return anchor
? GetWrapperFor(anchor
) : nullptr;
183 gint
getEndIndexCB(AtkHyperlink
* aLink
) {
184 MaiHyperlink
* maiLink
= GetMaiHyperlink(aLink
);
185 if (!maiLink
) return false;
187 if (LocalAccessible
* hyperlink
= maiLink
->GetAccHyperlink()) {
188 return static_cast<gint
>(hyperlink
->EndOffset());
192 uint32_t endIdx
= maiLink
->Proxy()->EndOffset(&valid
);
193 return valid
? static_cast<gint
>(endIdx
) : -1;
196 gint
getStartIndexCB(AtkHyperlink
* aLink
) {
197 MaiHyperlink
* maiLink
= GetMaiHyperlink(aLink
);
198 if (!maiLink
) return -1;
200 if (LocalAccessible
* hyperlink
= maiLink
->GetAccHyperlink()) {
201 return static_cast<gint
>(hyperlink
->StartOffset());
205 uint32_t startIdx
= maiLink
->Proxy()->StartOffset(&valid
);
206 return valid
? static_cast<gint
>(startIdx
) : -1;
209 gboolean
isValidCB(AtkHyperlink
* aLink
) {
210 MaiHyperlink
* maiLink
= GetMaiHyperlink(aLink
);
211 if (!maiLink
) return false;
213 if (LocalAccessible
* hyperlink
= maiLink
->GetAccHyperlink()) {
214 return static_cast<gboolean
>(hyperlink
->IsLinkValid());
217 return static_cast<gboolean
>(maiLink
->Proxy()->IsLinkValid());
220 gint
getAnchorCountCB(AtkHyperlink
* aLink
) {
221 MaiHyperlink
* maiLink
= GetMaiHyperlink(aLink
);
222 if (!maiLink
) return -1;
224 if (LocalAccessible
* hyperlink
= maiLink
->GetAccHyperlink()) {
225 return static_cast<gint
>(hyperlink
->AnchorCount());
229 uint32_t anchorCount
= maiLink
->Proxy()->AnchorCount(&valid
);
230 return valid
? static_cast<gint
>(anchorCount
) : -1;