[yelp/yelp-3-0] [libyelp] Look up resources (e.g. images) from URI search path



commit ddc7de372fa2865b34ec08168a5e3087b79861fb
Author: Shaun McCance <shaunm gnome org>
Date:   Wed Oct 21 17:15:15 2009 -0500

    [libyelp] Look up resources (e.g. images) from URI search path
    
    Especially for Mallard documents, the files included in a document can be
    placed anywhere within a search path.  With this change, not only can pages
    come from the search path, but also images or other resources.
    
    FIXME: We should make XInclude work on the path as well.

 libyelp/yelp-uri.c  |   50 +++++++++++++++++++++++++++---
 libyelp/yelp-uri.h  |    3 ++
 libyelp/yelp-view.c |   83 +++++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 125 insertions(+), 11 deletions(-)
---
diff --git a/libyelp/yelp-uri.c b/libyelp/yelp-uri.c
index 3edd748..a81a459 100644
--- a/libyelp/yelp-uri.c
+++ b/libyelp/yelp-uri.c
@@ -405,6 +405,34 @@ yelp_uri_get_frag_id (YelpUri *uri)
 
 /******************************************************************************/
 
+gchar *
+yelp_uri_locate_file_uri (YelpUri     *uri,
+                          const gchar *filename)
+{
+    YelpUriPrivate *priv = GET_PRIV (uri);
+    GFile *gfile;
+    gchar *fullpath;
+    gchar *returi = NULL;
+    gint i;
+    for (i = 0; priv->search_path[i] != NULL; i++) {
+        fullpath = g_strconcat (priv->search_path[i],
+                                G_DIR_SEPARATOR_S,
+                                filename,
+                                NULL);
+        if (g_file_test (fullpath, G_FILE_TEST_EXISTS)) {
+            gfile = g_file_new_for_path (fullpath);
+            returi = g_file_get_uri (gfile);
+            g_object_unref (gfile);
+        }
+        g_free (fullpath);
+        if (returi)
+            break;
+    }
+    return returi;
+}
+
+/******************************************************************************/
+
 static void
 resolve_file_uri (YelpUri *uri)
 {
@@ -467,14 +495,21 @@ resolve_data_dirs (YelpUri      *ret,
                    const gchar  *docid,
                    const gchar  *pageid)
 {
-    YelpUriPrivate *priv = GET_PRIV (ret);
-    const gchar * const *datadirs = g_get_system_data_dirs ();
+    const gchar * const *sdatadirs = g_get_system_data_dirs ();
     const gchar * const *langs = g_get_language_names ();
+    /* The strings are still owned by GLib; we just own the array. */
+    const gchar **datadirs;
+    YelpUriPrivate *priv = GET_PRIV (ret);
     gchar *filename = NULL;
     gchar **searchpath = NULL;
     gint searchi, searchmax;
     gint datadir_i, subdir_i, lang_i;
 
+    datadirs = g_new0 (gchar *, g_strv_length (sdatadirs) + 2);
+    datadirs[0] = g_get_user_data_dir ();
+    for (datadir_i = 0; sdatadirs[datadir_i]; datadir_i++)
+        datadirs[datadir_i + 1] = sdatadirs[datadir_i];
+
     searchi = 0;
     searchmax = 10;
     searchpath = g_new0 (gchar *, 10);
@@ -482,8 +517,12 @@ resolve_data_dirs (YelpUri      *ret,
     for (datadir_i = 0; datadirs[datadir_i]; datadir_i++) {
         for (subdir_i = 0; subdirs[subdir_i]; subdir_i++) {
             for (lang_i = 0; langs[lang_i]; lang_i++) {
-                gchar *helpdir = g_strdup_printf ("%s%s/%s/%s",
-                                                  datadirs[datadir_i], subdirs[subdir_i], docid, langs[lang_i]);
+                gchar *helpdir = g_strdup_printf ("%s%s%s/%s/%s",
+                                                  datadirs[datadir_i],
+                                                  (datadirs[datadir_i][strlen(datadirs[datadir_i]) - 1] == '/' ? "" : "/"),
+                                                  subdirs[subdir_i],
+                                                  docid,
+                                                  langs[lang_i]);
                 if (!g_file_test (helpdir, G_FILE_TEST_IS_DIR)) {
                     g_free (helpdir);
                     continue;
@@ -526,6 +565,7 @@ resolve_data_dirs (YelpUri      *ret,
         } /* end for subdirs */
     } /* end for datadirs */
 
+    g_free (datadirs);
     if (priv->tmptype == YELP_URI_DOCUMENT_TYPE_UNRESOLVED) {
         g_strfreev (searchpath);
         priv->tmptype = YELP_URI_DOCUMENT_TYPE_NOT_FOUND;
@@ -793,7 +833,7 @@ resolve_xref_uri (YelpUri *uri)
     priv->search_path = g_strdupv (base_priv->search_path);
     priv->docuri = g_strdup (base_priv->docuri);
 
-    if (arg == '#') {
+    if (arg[0] == '#') {
         priv->page_id = g_strdup (base_priv->page_id);
         priv->frag_id = g_strdup (arg + 1);
     }
diff --git a/libyelp/yelp-uri.h b/libyelp/yelp-uri.h
index 09bf40d..8161261 100644
--- a/libyelp/yelp-uri.h
+++ b/libyelp/yelp-uri.h
@@ -82,6 +82,9 @@ gchar **             yelp_uri_get_search_path    (YelpUri      *uri);
 gchar *              yelp_uri_get_page_id        (YelpUri      *uri);
 gchar *              yelp_uri_get_frag_id        (YelpUri      *uri);
 
+gchar *              yelp_uri_locate_file_uri    (YelpUri      *uri,
+                                                  const gchar  *filename);
+
 G_END_DECLS
 
 #endif /* __YELP_URI_H__ */
diff --git a/libyelp/yelp-view.c b/libyelp/yelp-view.c
index 1410cc7..98ccba9 100644
--- a/libyelp/yelp-view.c
+++ b/libyelp/yelp-view.c
@@ -28,12 +28,16 @@
 #include <gio/gio.h>
 #include <gtk/gtk.h>
 #include <webkit/webkit.h>
+#include <webkit/webkitwebresource.h>
 
 #include "yelp-debug.h"
 #include "yelp-error.h"
 #include "yelp-types.h"
 #include "yelp-view.h"
 
+#define BOGUS_URI "file:///bogus/"
+#define BOGUS_URI_LEN 14
+
 static void        yelp_view_init                 (YelpView           *view);
 static void        yelp_view_class_init           (YelpViewClass      *klass);
 static void        yelp_view_dispose              (GObject            *object);
@@ -53,6 +57,12 @@ static gboolean    view_navigation_requested      (WebKitWebView             *vi
                                                    WebKitWebNavigationAction *action,
                                                    WebKitWebPolicyDecision   *decision,
                                                    gpointer                   user_data);
+static void        view_resource_request          (WebKitWebView             *view,
+                                                   WebKitWebFrame            *frame,
+                                                   WebKitWebResource         *resource,
+                                                   WebKitNetworkRequest      *request,
+                                                   WebKitNetworkResponse     *response,
+                                                   gpointer                   user_data);
 
 static void        view_clear_load                (YelpView           *view);
 static void        view_load_page                 (YelpView           *view);
@@ -84,10 +94,13 @@ typedef struct _YelpViewPrivate YelpViewPrivate;
 struct _YelpViewPrivate {
     YelpUri       *uri;
     gulong         uri_resolved;
+    gchar         *bogus_uri;
     YelpDocument  *document;
     GCancellable  *cancellable;
 
     YelpViewState  state;
+
+    gint           navigation_requested;
 };
 
 #define TARGET_TYPE_URI_LIST     "text/uri-list"
@@ -104,8 +117,11 @@ yelp_view_init (YelpView *view)
 
     priv->state = YELP_VIEW_STATE_BLANK;
 
-    g_signal_connect (view, "navigation-policy-decision-requested",
-                      G_CALLBACK (view_navigation_requested), NULL);
+    priv->navigation_requested =
+        g_signal_connect (view, "navigation-policy-decision-requested",
+                          G_CALLBACK (view_navigation_requested), NULL);
+    g_signal_connect (view, "resource-request-starting",
+                      G_CALLBACK (view_resource_request), NULL);
 }
 
 static void
@@ -135,6 +151,10 @@ yelp_view_dispose (GObject *object)
 static void
 yelp_view_finalize (GObject *object)
 {
+    YelpViewPrivate *priv = GET_PRIV (object);
+
+    g_free (priv->bogus_uri);
+
     G_OBJECT_CLASS (yelp_view_parent_class)->finalize (object);
 }
 
@@ -292,6 +312,39 @@ view_navigation_requested (WebKitWebView             *view,
 }
 
 static void
+view_resource_request (WebKitWebView         *view,
+                       WebKitWebFrame        *frame,
+                       WebKitWebResource     *resource,
+                       WebKitNetworkRequest  *request,
+                       WebKitNetworkResponse *response,
+                       gpointer               user_data)
+{
+    YelpViewPrivate *priv = GET_PRIV (view);
+    const gchar *requri = webkit_network_request_get_uri (request);
+    gchar last;
+    gchar *newpath;
+
+    debug_print (DB_FUNCTION, "entering\n");
+    debug_print (DB_ARG, "    uri=\"%s\"\n", requri);
+
+    if (!g_str_has_prefix (requri, BOGUS_URI))
+        return;
+
+    /* We get this signal for the page itself.  Ignore. */
+    if (g_str_equal (requri, priv->bogus_uri))
+        return;
+
+    newpath = yelp_uri_locate_file_uri (priv->uri, requri + BOGUS_URI_LEN);
+    if (newpath != NULL) {
+        webkit_network_request_set_uri (request, newpath);
+        g_free (newpath);
+    }
+    else {
+        webkit_network_request_set_uri (request, "about:blank");
+    }
+}
+
+static void
 view_clear_load (YelpView *view)
 {
     YelpViewPrivate *priv = GET_PRIV (view);
@@ -356,6 +409,7 @@ static void
 view_show_error_page (YelpView *view,
                       GError   *error)
 {
+    YelpViewPrivate *priv = GET_PRIV (view);
     static const gchar *errorpage =
         "<html><head>"
         "<style type='text/css'>"
@@ -393,11 +447,13 @@ view_show_error_page (YelpView *view,
         title = _("Unknown Error");
     page = g_strdup_printf (errorpage, title, error->message);
     g_object_set (view, "state", YELP_VIEW_STATE_ERROR, NULL);
+    g_signal_handler_block (view, priv->navigation_requested);
     webkit_web_view_load_string (WEBKIT_WEB_VIEW (view),
                                  page,
                                  "text/html",
                                  "UTF-8",
                                  "about:error");
+    g_signal_handler_unblock (view, priv->navigation_requested);
     g_error_free (error);
     g_free (page);
 }
@@ -436,21 +492,36 @@ document_callback (YelpDocument       *document,
     }
     else if (signal == YELP_DOCUMENT_SIGNAL_CONTENTS) {
 	const gchar *contents;
-        gchar *real_uri, *mime_type, *page_id;
-        real_uri = yelp_uri_get_canonical_uri (priv->uri);
+        gchar *mime_type, *page_id, *frag_id;
         page_id = yelp_uri_get_page_id (priv->uri);
         debug_print (DB_ARG, "    document.uri.page_id=\"%s\"\n", page_id);
         mime_type = yelp_document_get_mime_type (document, page_id);
         contents = yelp_document_read_contents (document, page_id);
+        frag_id = yelp_uri_get_frag_id (priv->uri);
+        g_free (priv->bogus_uri);
+        /* We have to give WebKit a URI in a scheme it understands, otherwise we
+           won't get the resource-request-starting signal.  So we can't use the
+           canonical URI, because it might be something like ghelp.  We also have
+           to give it something unique, because WebKit ignores our load_string
+           call if the URI isn't different.  We could try to construct something
+           based on actual file locations, but in fact it doesn't matter.  So
+           we just make a bogus URI that's easy to process later.
+         */
+        if (frag_id != NULL)
+            priv->bogus_uri = g_strdup_printf ("%s%p#%s", BOGUS_URI, priv->uri, frag_id);
+        else
+            priv->bogus_uri = g_strdup_printf ("%s%p", BOGUS_URI, priv->uri);
+        g_signal_handler_block (view, priv->navigation_requested);
         webkit_web_view_load_string (WEBKIT_WEB_VIEW (view),
                                      contents,
                                      mime_type,
                                      "UTF-8",
-                                     real_uri);
+                                     priv->bogus_uri);
+        g_signal_handler_unblock (view, priv->navigation_requested);
         g_object_set (view, "state", YELP_VIEW_STATE_LOADED, NULL);
+        g_free (frag_id);
         g_free (page_id);
         g_free (mime_type);
-        g_free (real_uri);
 	yelp_document_finish_read (document, contents);
     }
     else if (signal == YELP_DOCUMENT_SIGNAL_ERROR) {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]