[evince/wip/bug654832: 10/13] libdocument: Add API to load EvDocument from GIO stream and file



commit 4d9b997c2575c0e671bdc3cf1c753eff613c1f9d
Author: Christian Persch <chpe gnome org>
Date:   Wed May 9 19:22:47 2012 +0200

    libdocument: Add API to load EvDocument from GIO stream and file
    
    Part of bug #654832.

 .../libdocument/libevdocument-sections.txt         |    4 +
 libdocument/ev-document-factory.c                  |  134 ++++++++++
 libdocument/ev-document-factory.h                  |   10 +
 libdocument/ev-document.c                          |  256 ++++++++++++++------
 libdocument/ev-document.h                          |   27 ++
 5 files changed, 351 insertions(+), 80 deletions(-)
---
diff --git a/help/reference/libdocument/libevdocument-sections.txt b/help/reference/libdocument/libevdocument-sections.txt
index ad72e04..14626b7 100644
--- a/help/reference/libdocument/libevdocument-sections.txt
+++ b/help/reference/libdocument/libevdocument-sections.txt
@@ -343,6 +343,8 @@ ev_document_fc_mutex_trylock
 ev_document_get_info
 ev_document_get_backend_info
 ev_document_load
+ev_document_load_stream
+ev_document_load_gfile
 ev_document_save
 ev_document_get_n_pages
 ev_document_get_page
@@ -659,6 +661,8 @@ EV_DOCUMENT_FONTS_GET_IFACE
 <SECTION>
 <FILE>ev-document-factory</FILE>
 ev_document_factory_get_document
+ev_document_factory_get_document_for_gfile
+ev_document_factory_get_document_for_stream
 ev_document_factory_add_filters
 </SECTION>
 
diff --git a/libdocument/ev-document-factory.c b/libdocument/ev-document-factory.c
index 954b525..1df8154 100644
--- a/libdocument/ev-document-factory.c
+++ b/libdocument/ev-document-factory.c
@@ -376,6 +376,140 @@ ev_document_factory_get_document (const char *uri, GError **error)
 	return document;
 }
 
+/**
+ * ev_document_factory_get_document_for_gfile:
+ * @file: a #GFile
+ * @flags: flags from #EvDocumentLoadFlags
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @error: (allow-none): a #GError location to store an error, or %NULL
+ *
+ * Synchronously creates a #EvDocument for the document at @file; or, if no
+ * backend handling the document's type is found, or an error occurred on
+ * opening the document, returns %NULL and fills in @error.
+ * If the document is encrypted, it is returned but also @error is set to
+ * %EV_DOCUMENT_ERROR_ENCRYPTED.
+ *
+ * Returns: a new #EvDocument, or %NULL
+ * 
+ * Since: 3.6
+ */
+EvDocument*
+ev_document_factory_get_document_for_gfile (GFile *file,
+                                            EvDocumentLoadFlags flags,
+                                            GCancellable *cancellable,
+                                            GError **error)
+{
+        EvDocument *document;
+        GFileInfo *file_info;
+        const char *content_type;
+        char *mime_type = NULL;
+
+        g_return_val_if_fail (G_IS_FILE (file), NULL);
+        g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+
+        file_info = g_file_query_info (file,
+                                       G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+                                       G_FILE_QUERY_INFO_NONE,
+                                       cancellable,
+                                       error);
+        if (file_info == NULL)
+                return NULL;
+
+        content_type = g_file_info_get_content_type (file_info);
+        if (content_type == NULL) {
+                g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                                     "Failed to query file mime type");
+                return NULL;
+        }
+
+        mime_type = g_content_type_get_mime_type (content_type);
+        g_object_unref (file_info);
+
+        document = ev_document_factory_new_document_for_mime_type (mime_type, error);
+        g_free (mime_type);
+        if (document == NULL)
+                return NULL;
+
+        if (!ev_document_load_gfile (document, file, flags, cancellable, error)) {
+                g_object_unref (document);
+                return NULL;
+        }
+
+        return document;
+}
+
+/**
+ * ev_document_factory_get_document_for_stream:
+ * @stream: a #GInputStream
+ * @mime_type: (allow-none): a mime type hint
+ * @flags: flags from #EvDocumentLoadFlags
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @error: (allow-none): a #GError location to store an error, or %NULL
+ *
+ * Synchronously creates a #EvDocument for the document from @stream; or, if no
+ * backend handling the document's type is found, or an error occurred
+ * on opening the document, returns %NULL and fills in @error.
+ * If the document is encrypted, it is returned but also @error is set to
+ * %EV_DOCUMENT_ERROR_ENCRYPTED.
+ *
+ * If @mime_type is non-%NULL, this overrides any type inferred from the stream.
+ * If the mime type cannot be inferred from the stream, and @mime_type is %NULL,
+ * an error is returned.
+ *
+ * Returns: a new #EvDocument, or %NULL
+ * 
+ * Since: 3.6
+ */
+EvDocument* 
+ev_document_factory_get_document_for_stream (GInputStream *stream,
+                                             const char *mime_type,
+                                             EvDocumentLoadFlags flags,
+                                             GCancellable *cancellable,
+                                             GError **error)
+{
+        EvDocument *document;
+        char *mime = NULL;
+
+        g_return_val_if_fail (G_IS_INPUT_STREAM (stream), NULL);
+        g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+        if (mime_type == NULL && G_IS_FILE_INPUT_STREAM (stream)) {
+                GFileInfo *file_info;
+                const char *content_type;
+
+                file_info = g_file_input_stream_query_info (G_FILE_INPUT_STREAM (stream),
+                                                            G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+                                                            cancellable,
+                                                            error);
+                if (file_info != NULL) {
+                        content_type = g_file_info_get_content_type (file_info);
+                        if (content_type)
+                                mime_type = mime = g_content_type_get_mime_type (content_type);
+                        g_object_unref (file_info);
+                }
+        }
+
+        if (mime_type == NULL) {
+                g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                                     "Cannot query mime type from stream");
+                return NULL;
+        }
+
+        document = ev_document_factory_new_document_for_mime_type (mime_type, error);
+        g_free (mime);
+
+        if (document == NULL)
+                return NULL;
+
+        if (!ev_document_load_stream (document, stream, flags, cancellable, error)) {
+                g_object_unref (document);
+                return NULL;
+        }
+
+        return document;
+}
+
 static void
 file_filter_add_mime_types (EvBackendInfo *info, GtkFileFilter *filter)
 {
diff --git a/libdocument/ev-document-factory.h b/libdocument/ev-document-factory.h
index b06b11d..b0e6d23 100644
--- a/libdocument/ev-document-factory.h
+++ b/libdocument/ev-document-factory.h
@@ -35,6 +35,16 @@ gboolean   _ev_document_factory_init         (void);
 void       _ev_document_factory_shutdown     (void);
 
 EvDocument* ev_document_factory_get_document (const char *uri, GError **error);
+EvDocument* ev_document_factory_get_document_for_gfile (GFile *file,
+                                                        EvDocumentLoadFlags flags,
+                                                        GCancellable *cancellable,
+                                                        GError **error);
+EvDocument* ev_document_factory_get_document_for_stream (GInputStream *stream,
+                                                         const char *mime_type,
+                                                         EvDocumentLoadFlags flags,
+                                                         GCancellable *cancellable,
+                                                         GError **error);
+
 void 	    ev_document_factory_add_filters  (GtkWidget *chooser, EvDocument *document);
 
 G_END_DECLS
diff --git a/libdocument/ev-document.c b/libdocument/ev-document.c
index a75862c..0596a88 100644
--- a/libdocument/ev-document.c
+++ b/libdocument/ev-document.c
@@ -208,6 +208,79 @@ ev_document_fc_mutex_trylock (void)
 	return g_mutex_trylock (p_ev_fc_mutex);
 }
 
+static void
+ev_document_setup_cache (EvDocument *document)
+{
+        EvDocumentPrivate *priv = document->priv;
+        gint i;
+
+        /* Cache some info about the document to avoid
+         * going to the backends since it requires locks
+         */
+        priv->n_pages = _ev_document_get_n_pages (document);
+
+        for (i = 0; i < priv->n_pages; i++) {
+                EvPage     *page = ev_document_get_page (document, i);
+                gdouble     page_width = 0;
+                gdouble     page_height = 0;
+                EvPageSize *page_size;
+                gchar      *page_label;
+
+                _ev_document_get_page_size (document, page, &page_width, &page_height);
+
+                if (i == 0) {
+                        priv->uniform_width = page_width;
+                        priv->uniform_height = page_height;
+                        priv->max_width = priv->uniform_width;
+                        priv->max_height = priv->uniform_height;
+                        priv->min_width = priv->uniform_width;
+                        priv->min_height = priv->uniform_height;
+                } else if (priv->uniform &&
+                            (priv->uniform_width != page_width ||
+                            priv->uniform_height != page_height)) {
+                        /* It's a different page size.  Backfill the array. */
+                        int j;
+
+                        priv->page_sizes = g_new0 (EvPageSize, priv->n_pages);
+
+                        for (j = 0; j < i; j++) {
+                                page_size = &(priv->page_sizes[j]);
+                                page_size->width = priv->uniform_width;
+                                page_size->height = priv->uniform_height;
+                        }
+                        priv->uniform = FALSE;
+                }
+                if (!priv->uniform) {
+                        page_size = &(priv->page_sizes[i]);
+
+                        page_size->width = page_width;
+                        page_size->height = page_height;
+
+                        if (page_width > priv->max_width)
+                                priv->max_width = page_width;
+                        if (page_width < priv->min_width)
+                                priv->min_width = page_width;
+
+                        if (page_height > priv->max_height)
+                                priv->max_height = page_height;
+                        if (page_height < priv->min_height)
+                                priv->min_height = page_height;
+                }
+
+                page_label = _ev_document_get_page_label (document, page);
+                if (page_label) {
+                        if (!priv->page_labels)
+                                priv->page_labels = g_new0 (gchar *, priv->n_pages);
+
+                        priv->page_labels[i] = page_label;
+                        priv->max_label = MAX (priv->max_label,
+                                                g_utf8_strlen (page_label, 256));
+                }
+
+                g_object_unref (page);
+        }
+}
+
 /**
  * ev_document_load:
  * @document: a #EvDocument
@@ -249,90 +322,113 @@ ev_document_load (EvDocument  *document,
 					     "Internal error in backend");
 		}
 	} else {
-		gint i;
-		EvDocumentPrivate *priv = document->priv;
-
-		/* Cache some info about the document to avoid
-		 * going to the backends since it requires locks
-		 */
-		priv->uri = g_strdup (uri);
-		priv->n_pages = _ev_document_get_n_pages (document);
-
-		for (i = 0; i < priv->n_pages; i++) {
-			EvPage     *page = ev_document_get_page (document, i);
-			gdouble     page_width = 0;
-			gdouble     page_height = 0;
-			EvPageSize *page_size;
-			gchar      *page_label;
-
-			_ev_document_get_page_size (document, page, &page_width, &page_height);
-
-			if (i == 0) {
-				priv->uniform_width = page_width;
-				priv->uniform_height = page_height;
-				priv->max_width = priv->uniform_width;
-				priv->max_height = priv->uniform_height;
-				priv->min_width = priv->uniform_width;
-				priv->min_height = priv->uniform_height;
-			} else if (priv->uniform &&
-				   (priv->uniform_width != page_width ||
-				    priv->uniform_height != page_height)) {
-				/* It's a different page size.  Backfill the array. */
-				int j;
-
-				priv->page_sizes = g_new0 (EvPageSize, priv->n_pages);
-
-				for (j = 0; j < i; j++) {
-					page_size = &(priv->page_sizes[j]);
-					page_size->width = priv->uniform_width;
-					page_size->height = priv->uniform_height;
-				}
-				priv->uniform = FALSE;
-			}
-			if (!priv->uniform) {
-				page_size = &(priv->page_sizes[i]);
+                EvDocumentPrivate *priv = document->priv;
 
-				page_size->width = page_width;
-				page_size->height = page_height;
+                ev_document_setup_cache (document);
 
-				if (page_width > priv->max_width)
-					priv->max_width = page_width;
-				if (page_width < priv->min_width)
-					priv->min_width = page_width;
+                priv->uri = g_strdup (uri);
+                priv->info = _ev_document_get_info (document);
+                if (_ev_document_support_synctex (document)) {
+                        gchar *filename;
 
-				if (page_height > priv->max_height)
-					priv->max_height = page_height;
-				if (page_height < priv->min_height)
-					priv->min_height = page_height;
-			}
+                        filename = g_filename_from_uri (uri, NULL, NULL);
+                        if (filename != NULL) {
+                                priv->synctex_scanner =
+                                        synctex_scanner_new_with_output_file (filename, NULL, 1);
+                                g_free (filename);
+                        }
+                }
+        }
 
-			page_label = _ev_document_get_page_label (document, page);
-			if (page_label) {
-				if (!priv->page_labels)
-					priv->page_labels = g_new0 (gchar *, priv->n_pages);
+	return retval;
+}
 
-				priv->page_labels[i] = page_label;
-				priv->max_label = MAX (priv->max_label,
-						       g_utf8_strlen (page_label, 256));
-			}
+/**
+ * ev_document_load_stream:
+ * @document: a #EvDocument
+ * @stream: a #GInputStream
+ * @flags: flags from #EvDocumentLoadFlags
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @error: (allow-none): a #GError location to store an error, or %NULL
+ *
+ * Synchronously loads the document from @stream. 
+ * See ev_document_load() for more information.
+ *
+ * Returns: %TRUE if loading succeeded, or %FALSE on error with @error filled in
+ *
+ * Since: 3.6
+ */
+gboolean
+ev_document_load_stream (EvDocument         *document,
+                         GInputStream       *stream,
+                         EvDocumentLoadFlags flags,
+                         GCancellable       *cancellable,
+                         GError            **error)
+{
+        EvDocumentClass *klass;
+
+        g_return_val_if_fail (EV_IS_DOCUMENT (document), FALSE);
+        g_return_val_if_fail (G_IS_INPUT_STREAM (stream), FALSE);
+        g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+        klass = EV_DOCUMENT_GET_CLASS (document);
+        if (!klass->load_stream) {
+                g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                                     "Backend does not support loading from stream");
+                return FALSE;
+        }
 
-			g_object_unref (page);
-		}
+        if (!klass->load_stream (document, stream, flags, cancellable, error))
+                return FALSE;
 
-		priv->info = _ev_document_get_info (document);
-		if (_ev_document_support_synctex (document)) {
-			gchar *filename;
+        ev_document_setup_cache (document);
 
-			filename = g_filename_from_uri (uri, NULL, NULL);
-			if (filename != NULL) {
-				priv->synctex_scanner =
-					synctex_scanner_new_with_output_file (filename, NULL, 1);
-				g_free (filename);
-			}
-		}
-	}
+        return TRUE;
+}
 
-	return retval;
+/**
+ * ev_document_load_gfile:
+ * @document: a #EvDocument
+ * @file: a #GFile
+ * @flags: flags from #EvDocumentLoadFlags
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @error: (allow-none): a #GError location to store an error, or %NULL
+ *
+ * Synchronously loads the document from @file. 
+ * See ev_document_load() for more information.
+ *
+ * Returns: %TRUE if loading succeeded, or %FALSE on error with @error filled in
+ *
+ * Since: 3.6
+ */
+gboolean
+ev_document_load_gfile (EvDocument         *document,
+                        GFile              *file,
+                        EvDocumentLoadFlags flags,
+                        GCancellable       *cancellable,
+                        GError            **error)
+{
+        EvDocumentClass *klass;
+
+        g_return_val_if_fail (EV_IS_DOCUMENT (document), FALSE);
+        g_return_val_if_fail (G_IS_FILE (file), FALSE);
+        g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+        klass = EV_DOCUMENT_GET_CLASS (document);
+        if (!klass->load_gfile) {
+                g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                                     "Backend does not support loading from GFile");
+                return FALSE;
+        }
+
+        if (!klass->load_gfile (document, file, flags, cancellable, error))
+                return FALSE;
+
+        ev_document_setup_cache (document);
+
+        return TRUE;
 }
 
 /**
diff --git a/libdocument/ev-document.h b/libdocument/ev-document.h
index e1e01c0..ba3520f 100644
--- a/libdocument/ev-document.h
+++ b/libdocument/ev-document.h
@@ -29,6 +29,7 @@
 
 #include <glib-object.h>
 #include <glib.h>
+#include <gio/gio.h>
 #include <gdk/gdk.h>
 #include <cairo.h>
 
@@ -53,6 +54,10 @@ typedef struct _EvDocumentPrivate EvDocumentPrivate;
 #define EV_DOC_MUTEX_LOCK (ev_document_doc_mutex_lock ())
 #define EV_DOC_MUTEX_UNLOCK (ev_document_doc_mutex_unlock ())
 
+typedef enum /*< flags >*/ {
+        EV_DOCUMENT_LOAD_FLAG_NONE = 0
+} EvDocumentLoadFlags;
+
 typedef enum
 {
         EV_DOCUMENT_ERROR_INVALID,
@@ -110,6 +115,18 @@ struct _EvDocumentClass
         gboolean          (* get_backend_info)(EvDocument      *document,
                                                EvDocumentBackendInfo *info);
         gboolean	  (* support_synctex) (EvDocument      *document);
+
+        /* GIO streams */
+        gboolean          (* load_stream)     (EvDocument          *document,
+                                               GInputStream        *stream,
+                                               EvDocumentLoadFlags  flags,
+                                               GCancellable        *cancellable,
+                                               GError             **error);
+        gboolean          (* load_gfile)      (EvDocument          *document,
+                                               GFile               *file,
+                                               EvDocumentLoadFlags  flags,
+                                               GCancellable        *cancellable,
+                                               GError             **error);
 };
 
 GType            ev_document_get_type             (void) G_GNUC_CONST;
@@ -133,6 +150,16 @@ gboolean         ev_document_get_backend_info     (EvDocument      *document,
 gboolean         ev_document_load                 (EvDocument      *document,
 						   const char      *uri,
 						   GError         **error);
+gboolean         ev_document_load_stream          (EvDocument         *document,
+                                                   GInputStream       *stream,
+                                                   EvDocumentLoadFlags flags,
+                                                   GCancellable       *cancellable,
+                                                   GError            **error);
+gboolean         ev_document_load_gfile           (EvDocument         *document,
+                                                   GFile              *file,
+                                                   EvDocumentLoadFlags flags,
+                                                   GCancellable       *cancellable,
+                                                   GError            **error);
 gboolean         ev_document_save                 (EvDocument      *document,
 						   const char      *uri,
 						   GError         **error);



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