michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsIURI.h" michael@0: #include "nsMaiHyperlink.h" michael@0: michael@0: using namespace mozilla::a11y; michael@0: michael@0: /* MaiAtkHyperlink */ michael@0: michael@0: #define MAI_TYPE_ATK_HYPERLINK (mai_atk_hyperlink_get_type ()) michael@0: #define MAI_ATK_HYPERLINK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\ michael@0: MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlink)) michael@0: #define MAI_ATK_HYPERLINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\ michael@0: MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlinkClass)) michael@0: #define MAI_IS_ATK_HYPERLINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\ michael@0: MAI_TYPE_ATK_HYPERLINK)) michael@0: #define MAI_IS_ATK_HYPERLINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\ michael@0: MAI_TYPE_ATK_HYPERLINK)) michael@0: #define MAI_ATK_HYPERLINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\ michael@0: MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlinkClass)) michael@0: michael@0: /** michael@0: * This MaiAtkHyperlink is a thin wrapper, in the MAI namespace, michael@0: * for AtkHyperlink michael@0: */ michael@0: michael@0: struct MaiAtkHyperlink michael@0: { michael@0: AtkHyperlink parent; michael@0: michael@0: /* michael@0: * The MaiHyperlink whose properties and features are exported via this michael@0: * hyperlink instance. michael@0: */ michael@0: MaiHyperlink *maiHyperlink; michael@0: }; michael@0: michael@0: struct MaiAtkHyperlinkClass michael@0: { michael@0: AtkHyperlinkClass parent_class; michael@0: }; michael@0: michael@0: GType mai_atk_hyperlink_get_type(void); michael@0: michael@0: G_BEGIN_DECLS michael@0: /* callbacks for AtkHyperlink */ michael@0: static void classInitCB(AtkHyperlinkClass *aClass); michael@0: static void finalizeCB(GObject *aObj); michael@0: michael@0: /* callbacks for AtkHyperlink virtual functions */ michael@0: static gchar *getUriCB(AtkHyperlink *aLink, gint aLinkIndex); michael@0: static AtkObject *getObjectCB(AtkHyperlink *aLink, gint aLinkIndex); michael@0: static gint getEndIndexCB(AtkHyperlink *aLink); michael@0: static gint getStartIndexCB(AtkHyperlink *aLink); michael@0: static gboolean isValidCB(AtkHyperlink *aLink); michael@0: static gint getAnchorCountCB(AtkHyperlink *aLink); michael@0: G_END_DECLS michael@0: michael@0: static gpointer parent_class = nullptr; michael@0: static Accessible* michael@0: get_accessible_hyperlink(AtkHyperlink *aHyperlink); michael@0: michael@0: GType michael@0: mai_atk_hyperlink_get_type(void) michael@0: { michael@0: static GType type = 0; michael@0: michael@0: if (!type) { michael@0: static const GTypeInfo tinfo = { michael@0: sizeof(MaiAtkHyperlinkClass), michael@0: (GBaseInitFunc)nullptr, michael@0: (GBaseFinalizeFunc)nullptr, michael@0: (GClassInitFunc)classInitCB, michael@0: (GClassFinalizeFunc)nullptr, michael@0: nullptr, /* class data */ michael@0: sizeof(MaiAtkHyperlink), /* instance size */ michael@0: 0, /* nb preallocs */ michael@0: (GInstanceInitFunc)nullptr, michael@0: nullptr /* value table */ michael@0: }; michael@0: michael@0: type = g_type_register_static(ATK_TYPE_HYPERLINK, michael@0: "MaiAtkHyperlink", michael@0: &tinfo, GTypeFlags(0)); michael@0: } michael@0: return type; michael@0: } michael@0: michael@0: MaiHyperlink::MaiHyperlink(Accessible* aHyperLink) : michael@0: mHyperlink(aHyperLink), michael@0: mMaiAtkHyperlink(nullptr) michael@0: { michael@0: } michael@0: michael@0: MaiHyperlink::~MaiHyperlink() michael@0: { michael@0: if (mMaiAtkHyperlink) { michael@0: MAI_ATK_HYPERLINK(mMaiAtkHyperlink)->maiHyperlink = nullptr; michael@0: g_object_unref(mMaiAtkHyperlink); michael@0: } michael@0: } michael@0: michael@0: AtkHyperlink* michael@0: MaiHyperlink::GetAtkHyperlink(void) michael@0: { michael@0: NS_ENSURE_TRUE(mHyperlink, nullptr); michael@0: michael@0: if (mMaiAtkHyperlink) michael@0: return mMaiAtkHyperlink; michael@0: michael@0: if (!mHyperlink->IsLink()) michael@0: return nullptr; michael@0: michael@0: mMaiAtkHyperlink = michael@0: reinterpret_cast michael@0: (g_object_new(mai_atk_hyperlink_get_type(), nullptr)); michael@0: NS_ASSERTION(mMaiAtkHyperlink, "OUT OF MEMORY"); michael@0: NS_ENSURE_TRUE(mMaiAtkHyperlink, nullptr); michael@0: michael@0: /* be sure to initialize it with "this" */ michael@0: MaiHyperlink::Initialize(mMaiAtkHyperlink, this); michael@0: michael@0: return mMaiAtkHyperlink; michael@0: } michael@0: michael@0: /* static */ michael@0: michael@0: /* remember to call this static function when a MaiAtkHyperlink michael@0: * is created michael@0: */ michael@0: michael@0: nsresult michael@0: MaiHyperlink::Initialize(AtkHyperlink *aObj, MaiHyperlink *aHyperlink) michael@0: { michael@0: NS_ENSURE_ARG(MAI_IS_ATK_HYPERLINK(aObj)); michael@0: NS_ENSURE_ARG(aHyperlink); michael@0: michael@0: /* initialize hyperlink */ michael@0: MAI_ATK_HYPERLINK(aObj)->maiHyperlink = aHyperlink; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* static functions for ATK callbacks */ michael@0: michael@0: void michael@0: classInitCB(AtkHyperlinkClass *aClass) michael@0: { michael@0: GObjectClass *gobject_class = G_OBJECT_CLASS(aClass); michael@0: michael@0: parent_class = g_type_class_peek_parent(aClass); michael@0: michael@0: aClass->get_uri = getUriCB; michael@0: aClass->get_object = getObjectCB; michael@0: aClass->get_end_index = getEndIndexCB; michael@0: aClass->get_start_index = getStartIndexCB; michael@0: aClass->is_valid = isValidCB; michael@0: aClass->get_n_anchors = getAnchorCountCB; michael@0: michael@0: gobject_class->finalize = finalizeCB; michael@0: } michael@0: michael@0: void michael@0: finalizeCB(GObject *aObj) michael@0: { michael@0: NS_ASSERTION(MAI_IS_ATK_HYPERLINK(aObj), "Invalid MaiAtkHyperlink"); michael@0: if (!MAI_IS_ATK_HYPERLINK(aObj)) michael@0: return; michael@0: michael@0: MaiAtkHyperlink *maiAtkHyperlink = MAI_ATK_HYPERLINK(aObj); michael@0: maiAtkHyperlink->maiHyperlink = nullptr; michael@0: michael@0: /* call parent finalize function */ michael@0: if (G_OBJECT_CLASS (parent_class)->finalize) michael@0: G_OBJECT_CLASS (parent_class)->finalize(aObj); michael@0: } michael@0: michael@0: gchar * michael@0: getUriCB(AtkHyperlink *aLink, gint aLinkIndex) michael@0: { michael@0: Accessible* hyperlink = get_accessible_hyperlink(aLink); michael@0: NS_ENSURE_TRUE(hyperlink, nullptr); michael@0: michael@0: nsCOMPtr uri = hyperlink->AnchorURIAt(aLinkIndex); michael@0: if (!uri) michael@0: return nullptr; michael@0: michael@0: nsAutoCString cautoStr; michael@0: nsresult rv = uri->GetSpec(cautoStr); michael@0: NS_ENSURE_SUCCESS(rv, nullptr); michael@0: michael@0: return g_strdup(cautoStr.get()); michael@0: } michael@0: michael@0: AtkObject * michael@0: getObjectCB(AtkHyperlink *aLink, gint aLinkIndex) michael@0: { michael@0: Accessible* hyperlink = get_accessible_hyperlink(aLink); michael@0: NS_ENSURE_TRUE(hyperlink, nullptr); michael@0: michael@0: Accessible* anchor = hyperlink->AnchorAt(aLinkIndex); michael@0: NS_ENSURE_TRUE(anchor, nullptr); michael@0: michael@0: AtkObject* atkObj = AccessibleWrap::GetAtkObject(anchor); michael@0: //no need to add ref it, because it is "get" not "ref" michael@0: return atkObj; michael@0: } michael@0: michael@0: gint michael@0: getEndIndexCB(AtkHyperlink *aLink) michael@0: { michael@0: Accessible* hyperlink = get_accessible_hyperlink(aLink); michael@0: NS_ENSURE_TRUE(hyperlink, -1); michael@0: michael@0: return static_cast(hyperlink->EndOffset()); michael@0: } michael@0: michael@0: gint michael@0: getStartIndexCB(AtkHyperlink *aLink) michael@0: { michael@0: Accessible* hyperlink = get_accessible_hyperlink(aLink); michael@0: NS_ENSURE_TRUE(hyperlink, -1); michael@0: michael@0: return static_cast(hyperlink->StartOffset()); michael@0: } michael@0: michael@0: gboolean michael@0: isValidCB(AtkHyperlink *aLink) michael@0: { michael@0: Accessible* hyperlink = get_accessible_hyperlink(aLink); michael@0: NS_ENSURE_TRUE(hyperlink, FALSE); michael@0: michael@0: return static_cast(hyperlink->IsLinkValid()); michael@0: } michael@0: michael@0: gint michael@0: getAnchorCountCB(AtkHyperlink *aLink) michael@0: { michael@0: Accessible* hyperlink = get_accessible_hyperlink(aLink); michael@0: NS_ENSURE_TRUE(hyperlink, -1); michael@0: michael@0: return static_cast(hyperlink->AnchorCount()); michael@0: } michael@0: michael@0: // Check if aHyperlink is a valid MaiHyperlink, and return the michael@0: // HyperLinkAccessible related. michael@0: Accessible* michael@0: get_accessible_hyperlink(AtkHyperlink *aHyperlink) michael@0: { michael@0: NS_ENSURE_TRUE(MAI_IS_ATK_HYPERLINK(aHyperlink), nullptr); michael@0: MaiHyperlink * maiHyperlink = michael@0: MAI_ATK_HYPERLINK(aHyperlink)->maiHyperlink; michael@0: NS_ENSURE_TRUE(maiHyperlink != nullptr, nullptr); michael@0: NS_ENSURE_TRUE(maiHyperlink->GetAtkHyperlink() == aHyperlink, nullptr); michael@0: return maiHyperlink->GetAccHyperlink(); michael@0: }