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