nsMaiHyperlink.cpp (6255B)
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 #include "mozilla/a11y/RemoteAccessible.h" 10 11 using namespace mozilla::a11y; 12 13 /* MaiAtkHyperlink */ 14 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)) 28 29 /** 30 * This MaiAtkHyperlink is a thin wrapper, in the MAI namespace, 31 * for AtkHyperlink 32 */ 33 34 struct MaiAtkHyperlink { 35 AtkHyperlink parent; 36 37 /* 38 * The MaiHyperlink whose properties and features are exported via this 39 * hyperlink instance. 40 */ 41 MaiHyperlink* maiHyperlink; 42 }; 43 44 struct MaiAtkHyperlinkClass { 45 AtkHyperlinkClass parent_class; 46 }; 47 48 GType mai_atk_hyperlink_get_type(void); 49 50 G_BEGIN_DECLS 51 /* callbacks for AtkHyperlink */ 52 static void classInitCB(AtkHyperlinkClass* aClass); 53 static void finalizeCB(GObject* aObj); 54 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); 62 G_END_DECLS 63 64 static gpointer parent_class = nullptr; 65 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); 71 return maiHyperlink; 72 } 73 74 GType mai_atk_hyperlink_get_type(void) { 75 static GType type = 0; 76 77 if (!type) { 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 */ 86 0, /* nb preallocs */ 87 (GInstanceInitFunc) nullptr, 88 nullptr /* value table */ 89 }; 90 91 type = g_type_register_static(ATK_TYPE_HYPERLINK, "MaiAtkHyperlink", &tinfo, 92 GTypeFlags(0)); 93 } 94 return type; 95 } 96 97 MaiHyperlink::MaiHyperlink(Accessible* 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; 103 104 MAI_ATK_HYPERLINK(mMaiAtkHyperlink)->maiHyperlink = this; 105 } 106 107 MaiHyperlink::~MaiHyperlink() { 108 if (mMaiAtkHyperlink) { 109 MAI_ATK_HYPERLINK(mMaiAtkHyperlink)->maiHyperlink = nullptr; 110 g_object_unref(mMaiAtkHyperlink); 111 } 112 } 113 114 /* static functions for ATK callbacks */ 115 116 void classInitCB(AtkHyperlinkClass* aClass) { 117 GObjectClass* gobject_class = G_OBJECT_CLASS(aClass); 118 119 parent_class = g_type_class_peek_parent(aClass); 120 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; 127 128 gobject_class->finalize = finalizeCB; 129 } 130 131 void finalizeCB(GObject* aObj) { 132 NS_ASSERTION(MAI_IS_ATK_HYPERLINK(aObj), "Invalid MaiAtkHyperlink"); 133 if (!MAI_IS_ATK_HYPERLINK(aObj)) return; 134 135 MaiAtkHyperlink* maiAtkHyperlink = MAI_ATK_HYPERLINK(aObj); 136 maiAtkHyperlink->maiHyperlink = nullptr; 137 138 /* call parent finalize function */ 139 if (G_OBJECT_CLASS(parent_class)->finalize) { 140 G_OBJECT_CLASS(parent_class)->finalize(aObj); 141 } 142 } 143 144 gchar* getUriCB(AtkHyperlink* aLink, gint aLinkIndex) { 145 MaiHyperlink* maiLink = GetMaiHyperlink(aLink); 146 if (!maiLink) { 147 return nullptr; 148 } 149 150 Accessible* acc = maiLink->Acc(); 151 if (!acc) { 152 return nullptr; 153 } 154 155 nsAutoCString cautoStr; 156 nsCOMPtr<nsIURI> uri = acc->AnchorURIAt(aLinkIndex); 157 if (!uri) return nullptr; 158 159 nsresult rv = uri->GetSpec(cautoStr); 160 NS_ENSURE_SUCCESS(rv, nullptr); 161 162 return g_strdup(cautoStr.get()); 163 } 164 165 AtkObject* getObjectCB(AtkHyperlink* aLink, gint aLinkIndex) { 166 MaiHyperlink* maiLink = GetMaiHyperlink(aLink); 167 if (!maiLink) { 168 return nullptr; 169 } 170 171 Accessible* acc = maiLink->Acc(); 172 if (!acc) { 173 return nullptr; 174 } 175 176 Accessible* anchor = acc->AnchorAt(aLinkIndex); 177 return anchor ? GetWrapperFor(anchor) : nullptr; 178 } 179 180 gint getEndIndexCB(AtkHyperlink* aLink) { 181 MaiHyperlink* maiLink = GetMaiHyperlink(aLink); 182 if (!maiLink) return false; 183 184 return static_cast<gint>(maiLink->Acc()->EndOffset()); 185 } 186 187 gint getStartIndexCB(AtkHyperlink* aLink) { 188 MaiHyperlink* maiLink = GetMaiHyperlink(aLink); 189 if (!maiLink) return -1; 190 191 return static_cast<gint>(maiLink->Acc()->StartOffset()); 192 } 193 194 gboolean isValidCB(AtkHyperlink* aLink) { 195 MaiHyperlink* maiLink = GetMaiHyperlink(aLink); 196 if (!maiLink) return false; 197 198 Accessible* acc = maiLink->Acc(); 199 if (!acc) { 200 return false; 201 } 202 203 return static_cast<gboolean>(acc->IsLinkValid()); 204 } 205 206 gint getAnchorCountCB(AtkHyperlink* aLink) { 207 MaiHyperlink* maiLink = GetMaiHyperlink(aLink); 208 if (!maiLink) return -1; 209 210 Accessible* acc = maiLink->Acc(); 211 if (!acc) { 212 return -1; 213 } 214 215 return static_cast<gint>(acc->AnchorCount()); 216 }