diff options
Diffstat (limited to 'accessible/atk/nsMaiHyperlink.cpp')
-rw-r--r-- | accessible/atk/nsMaiHyperlink.cpp | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/accessible/atk/nsMaiHyperlink.cpp b/accessible/atk/nsMaiHyperlink.cpp new file mode 100644 index 0000000000..3e10ed189d --- /dev/null +++ b/accessible/atk/nsMaiHyperlink.cpp @@ -0,0 +1,226 @@ +/* -*- 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; +} |