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)
 {
openSUSE Build Service is sponsored by