File cairo-print.patch of Package mingw32-evince
diff --git a/backend/tiff/tiff-document.c b/backend/tiff/tiff-document.c
index 9c113b4..90747fb 100644
--- a/backend/tiff/tiff-document.c
+++ b/backend/tiff/tiff-document.c
@@ -33,8 +33,68 @@
#include "ev-document-misc.h"
#include "ev-document-thumbnails.h"
#include "ev-file-exporter.h"
+#include "ev-document-print.h"
#include "ev-file-helpers.h"
+static gpointer pool = NULL;
+static gsize poolsize = 0;
+static gboolean poolfree = TRUE;
+
+static gpointer
+try_malloc_from_pool (gsize n_bytes)
+{
+ if (!poolfree)
+ return NULL;
+
+ if (poolsize > n_bytes) {
+ poolfree = FALSE;
+ return pool;
+ }
+
+ gpointer newpool = g_try_realloc (pool, n_bytes);
+ if (newpool != NULL) {
+ pool = newpool;
+ poolsize = n_bytes;
+ poolfree = FALSE;
+ }
+ return newpool;
+}
+
+static void
+free_from_pool (gpointer mem)
+{
+ poolfree = TRUE;
+}
+
+static int
+in_pool (gpointer mem)
+{
+ return (mem == pool);
+}
+
+static gpointer
+tiff_document_data_malloc (gsize n_bytes) {
+
+ gpointer mem;
+ mem = try_malloc_from_pool (n_bytes);
+
+ if (!mem)
+ mem = g_try_malloc (n_bytes);
+
+ return mem;
+}
+
+static void
+tiff_document_data_free (gpointer mem)
+{
+ if (in_pool (mem))
+ free_from_pool (mem);
+ else
+ g_free (mem);
+
+ return;
+}
+
struct _TiffDocumentClass
{
EvDocumentClass parent_class;
@@ -55,6 +115,7 @@ typedef struct _TiffDocumentClass TiffDocumentClass;
static void tiff_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface);
static void tiff_document_document_file_exporter_iface_init (EvFileExporterInterface *iface);
+static void tiff_document_document_print_iface_init (EvDocumentPrintInterface *iface);
EV_BACKEND_REGISTER_WITH_CODE (TiffDocument, tiff_document,
{
@@ -62,6 +123,9 @@ EV_BACKEND_REGISTER_WITH_CODE (TiffDocument, tiff_document,
tiff_document_document_thumbnails_iface_init);
EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_FILE_EXPORTER,
tiff_document_document_file_exporter_iface_init);
+ EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_PRINT,
+ tiff_document_document_print_iface_init);
+
});
static TIFFErrorHandler orig_error_handler = NULL;
@@ -209,9 +273,13 @@ tiff_document_get_page_size (EvDocument *document,
pop_handlers ();
}
-static cairo_surface_t *
-tiff_document_render (EvDocument *document,
- EvRenderContext *rc)
+static guchar*
+tiff_document_read_data (EvDocument *document,
+ int index,
+ int *pwidth,
+ int *pheight,
+ float *pscale,
+ gint *prowstride)
{
TiffDocument *tiff_document = TIFF_DOCUMENT (document);
int width, height;
@@ -220,26 +288,26 @@ tiff_document_render (EvDocument *document,
guchar *pixels = NULL;
guchar *p;
int orientation;
- cairo_surface_t *surface;
- cairo_surface_t *rotated_surface;
- static const cairo_user_data_key_t key;
g_return_val_if_fail (TIFF_IS_DOCUMENT (document), NULL);
g_return_val_if_fail (tiff_document->tiff != NULL, NULL);
push_handlers ();
- if (TIFFSetDirectory (tiff_document->tiff, rc->page->index) != 1) {
+ if (TIFFSetDirectory (tiff_document->tiff, index) != 1) {
pop_handlers ();
+ g_warning("Failed to select page %d", index);
return NULL;
}
if (!TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGEWIDTH, &width)) {
pop_handlers ();
+ g_warning("Failed to read image width");
return NULL;
}
if (! TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGELENGTH, &height)) {
pop_handlers ();
+ g_warning("Failed to read image height");
return NULL;
}
@@ -249,37 +317,36 @@ tiff_document_render (EvDocument *document,
tiff_document_get_resolution (tiff_document, &x_res, &y_res);
- pop_handlers ();
-
/* Sanity check the doc */
- if (width <= 0 || height <= 0)
- return NULL;
+ if (width <= 0 || height <= 0) {
+ g_warning("Invalid width or height.");
+ return NULL;
+ }
#ifdef HAVE_CAIRO_FORMAT_STRIDE_FOR_WIDTH
rowstride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
#else
rowstride = width * 4;
#endif
- if (rowstride / 4 != width)
+ if (rowstride / 4 != width) {
+ g_warning("Overflow while rendering document.");
/* overflow, or cairo was changed in an unsupported way */
return NULL;
+ }
bytes = height * rowstride;
- if (bytes / rowstride != height)
+ if (bytes / rowstride != height) {
+ g_warning("Overflow while rendering document.");
/* overflow */
- return NULL;
+ return NULL;
+ }
- pixels = g_try_malloc (bytes);
- if (!pixels)
+ pixels = tiff_document_data_malloc (bytes);
+ if (!pixels) {
+ g_warning("Failed to allocate memory for rendering.");
return NULL;
+ }
- surface = cairo_image_surface_create_for_data (pixels,
- CAIRO_FORMAT_RGB24,
- width, height,
- rowstride);
- cairo_surface_set_user_data (surface, &key,
- pixels, (cairo_destroy_func_t)g_free);
-
TIFFReadRGBAImageOriented (tiff_document->tiff,
width, height,
(uint32 *)pixels,
@@ -302,9 +369,47 @@ tiff_document_render (EvDocument *document,
p += 4;
}
+ *pscale = x_res/y_res;
+ *pwidth = width;
+ *pheight = height;
+ *prowstride = rowstride;
+
+ return pixels;
+}
+
+static cairo_surface_t *
+tiff_document_render (EvDocument *document,
+ EvRenderContext *rc)
+{
+ int width, height;
+ float scale;
+ gint rowstride;
+ guchar *pixels = NULL;
+ cairo_surface_t *surface;
+ cairo_surface_t *rotated_surface;
+ static const cairo_user_data_key_t key;
+
+ pixels = tiff_document_read_data (document, rc->page->index, &width, &height, &scale, &rowstride);
+ if (!pixels) {
+ g_warning("Failed to read data for rendering.");
+ return NULL;
+ }
+
+ surface = cairo_image_surface_create_for_data (pixels,
+ CAIRO_FORMAT_RGB24,
+ width, height,
+ rowstride);
+ if (!surface) {
+ tiff_document_data_free (pixels);
+ g_warning("Failed to create surface for rendering.");
+ return NULL;
+ }
+ cairo_surface_set_user_data (surface, &key,
+ pixels, (cairo_destroy_func_t)tiff_document_data_free);
+
rotated_surface = ev_document_misc_surface_rotate_and_scale (surface,
(width * rc->scale) + 0.5,
- (height * rc->scale * (x_res / y_res)) + 0.5,
+ (height * rc->scale * scale) + 0.5,
rc->rotation);
cairo_surface_destroy (surface);
@@ -435,6 +540,10 @@ tiff_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
GdkPixbuf *pixbuf;
pixbuf = tiff_document_render_pixbuf (EV_DOCUMENT (document), rc);
+ if (!pixbuf) {
+ g_warning("Failed to render thumbnail pixbuf.");
+ return NULL;
+ }
if (border) {
GdkPixbuf *tmp_pixbuf = pixbuf;
@@ -526,6 +635,61 @@ tiff_document_document_file_exporter_iface_init (EvFileExporterInterface *iface)
iface->get_capabilities = tiff_document_file_exporter_get_capabilities;
}
+/* EvDocumentPrint */
+static void
+tiff_document_print_print_page (EvDocumentPrint *document,
+ EvPage *page,
+ cairo_t *cr)
+{
+ int width, height;
+ float scale;
+ gint rowstride;
+ static const cairo_user_data_key_t key;
+ guchar *pixels = NULL;
+ cairo_surface_t *surface;
+
+ pixels = tiff_document_read_data (EV_DOCUMENT (document), page->index, &width, &height, &scale, &rowstride);
+ if (!pixels) {
+ g_warning("Failed to read data for printing.");
+ return;
+ }
+
+ surface = cairo_image_surface_create_for_data (pixels,
+ CAIRO_FORMAT_RGB24,
+ width, height,
+ rowstride);
+ if (!surface) {
+ tiff_document_data_free (pixels);
+ g_warning("Failed to create image surface for printing.");
+ return;
+ }
+ cairo_surface_set_user_data (surface, &key,
+ pixels, (cairo_destroy_func_t)tiff_document_data_free);
+
+ cairo_save (cr);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+ cairo_restore (cr);
+
+ // Hib Eris; 15/07/2011
+ // I think we should destroy 'surface' here, but it seems
+ // cairo does not handle this well:
+ // Destroying 'surface' will cause the detachment of snapshots by
+ // cairo. This will cause a _cairo_surface_snapshot_copy_on_write
+ // which can fail with an out-of-memory error for large images.
+ // The failure is not handled by cairo and not returned by
+ // cairo_surface_destroy.
+ // For now, we uncomment it and attach the surface to the cr, deferring destruction.
+ //cairo_surface_destroy (surface);
+ cairo_set_user_data (cr, &key, surface, (cairo_destroy_func_t)cairo_surface_destroy);
+}
+
+static void
+tiff_document_document_print_iface_init (EvDocumentPrintInterface *iface)
+{
+ iface->print_page = tiff_document_print_print_page;
+}
+
static void
tiff_document_init (TiffDocument *tiff_document)
{