diff options
Diffstat (limited to 'libview/ev-page-accessible.c')
-rw-r--r-- | libview/ev-page-accessible.c | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/libview/ev-page-accessible.c b/libview/ev-page-accessible.c index fa1f3e02..60d07e33 100644 --- a/libview/ev-page-accessible.c +++ b/libview/ev-page-accessible.c @@ -24,22 +24,27 @@ #include <glib/gi18n-lib.h> #include "ev-page-accessible.h" +#include "ev-link-accessible.h" #include "ev-view-private.h" struct _EvPageAccessiblePrivate { EvViewAccessible *view_accessible; gint page; + GHashTable *links; }; + enum { PROP_0, PROP_VIEW_ACCESSIBLE, PROP_PAGE, }; +static void ev_page_accessible_hypertext_iface_init (AtkHypertextIface *iface); static void ev_page_accessible_text_iface_init (AtkTextIface *iface); G_DEFINE_TYPE_WITH_CODE (EvPageAccessible, ev_page_accessible, ATK_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (ATK_TYPE_HYPERTEXT, ev_page_accessible_hypertext_iface_init) G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, ev_page_accessible_text_iface_init)) gint @@ -71,6 +76,16 @@ ev_page_accessible_get_parent (AtkObject *obj) } static void +ev_page_accessible_finalize (GObject *object) +{ + EvPageAccessiblePrivate *priv = EV_PAGE_ACCESSIBLE (object)->priv; + + g_clear_pointer (&priv->links, (GDestroyNotify)g_hash_table_destroy); + + G_OBJECT_CLASS (ev_page_accessible_parent_class)->finalize (object); +} + +static void ev_page_accessible_set_property (GObject *object, guint prop_id, const GValue *value, @@ -122,6 +137,7 @@ ev_page_accessible_class_init (EvPageAccessibleClass *klass) g_object_class->get_property = ev_page_accessible_get_property; g_object_class->set_property = ev_page_accessible_set_property; + g_object_class->finalize = ev_page_accessible_finalize; g_object_class_install_property (g_object_class, PROP_VIEW_ACCESSIBLE, @@ -831,6 +847,108 @@ ev_page_accessible_text_iface_init (AtkTextIface *iface) iface->get_offset_at_point = ev_page_accessible_get_offset_at_point; } +static GHashTable * +ev_page_accessible_get_links (EvPageAccessible *accessible) +{ + EvPageAccessiblePrivate* priv = accessible->priv; + + if (priv->links) + return priv->links; + + priv->links = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + (GDestroyNotify)g_object_unref); + return priv->links; +} + +static AtkHyperlink * +ev_page_accessible_get_link (AtkHypertext *hypertext, + gint link_index) +{ + GHashTable *links; + EvMappingList *link_mapping; + gint n_links; + EvMapping *mapping; + EvLinkAccessible *atk_link; + EvPageAccessible *self = EV_PAGE_ACCESSIBLE (hypertext); + EvView *view = ev_page_accessible_get_view (self); + + if (link_index < 0) + return NULL; + + if (!EV_IS_DOCUMENT_LINKS (view->document)) + return NULL; + + links = ev_page_accessible_get_links (EV_PAGE_ACCESSIBLE (hypertext)); + + atk_link = g_hash_table_lookup (links, GINT_TO_POINTER (link_index)); + if (atk_link) + return atk_hyperlink_impl_get_hyperlink (ATK_HYPERLINK_IMPL (atk_link)); + + link_mapping = ev_page_cache_get_link_mapping (view->page_cache, self->priv->page); + if (!link_mapping) + return NULL; + + n_links = ev_mapping_list_length (link_mapping); + if (link_index > n_links - 1) + return NULL; + + mapping = ev_mapping_list_nth (link_mapping, n_links - link_index - 1); + atk_link = ev_link_accessible_new (EV_PAGE_ACCESSIBLE (hypertext), + EV_LINK (mapping->data), + &mapping->area); + g_hash_table_insert (links, GINT_TO_POINTER (link_index), atk_link); + + return atk_hyperlink_impl_get_hyperlink (ATK_HYPERLINK_IMPL (atk_link)); +} + +static gint +ev_page_accessible_get_n_links (AtkHypertext *hypertext) +{ + EvMappingList *link_mapping; + EvPageAccessible *self = EV_PAGE_ACCESSIBLE (hypertext); + EvView *view = ev_page_accessible_get_view (self); + + if (!EV_IS_DOCUMENT_LINKS (view->document)) + return 0; + + link_mapping = ev_page_cache_get_link_mapping (view->page_cache, + self->priv->page); + + return link_mapping ? ev_mapping_list_length (link_mapping) : 0; +} + +static gint +ev_page_accessible_get_link_index (AtkHypertext *hypertext, + gint offset) +{ + guint i; + gint n_links = ev_page_accessible_get_n_links (hypertext); + + for (i = 0; i < n_links; i++) { + AtkHyperlink *hyperlink; + gint start_index, end_index; + + hyperlink = ev_page_accessible_get_link (hypertext, i); + start_index = atk_hyperlink_get_start_index (hyperlink); + end_index = atk_hyperlink_get_end_index (hyperlink); + + if (start_index <= offset && end_index >= offset) + return i; + } + + return -1; +} + +static void +ev_page_accessible_hypertext_iface_init (AtkHypertextIface *iface) +{ + iface->get_link = ev_page_accessible_get_link; + iface->get_n_links = ev_page_accessible_get_n_links; + iface->get_link_index = ev_page_accessible_get_link_index; +} + EvPageAccessible * ev_page_accessible_new (EvViewAccessible *view_accessible, gint page) |