Index: backend/tiff/tiff-document.c
===================================================================
--- backend/tiff/tiff-document.c	(revision 3216)
+++ backend/tiff/tiff-document.c	(working copy)
@@ -381,6 +381,102 @@
 }
 
 static void
+tiff_document_cairo_print_page (EvDocument      *document,
+				EvRenderContext *rc,
+				cairo_t         *cr)
+{
+	TiffDocument *tiff_document = TIFF_DOCUMENT (document);
+	int width, height;
+	gint rowstride, bytes;
+	guchar *pixels = NULL;
+	guchar *p;
+	int orientation;
+	cairo_surface_t *surface;
+	static const cairo_user_data_key_t key;
+	
+	g_return_if_fail (TIFF_IS_DOCUMENT (document));
+	g_return_if_fail (tiff_document->tiff != NULL);
+  
+	push_handlers ();
+	if (TIFFSetDirectory (tiff_document->tiff, rc->page->index) != 1) {
+		pop_handlers ();
+		return;
+	}
+
+	if (!TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGEWIDTH, &width)) {
+		pop_handlers ();
+		return;
+	}
+
+	if (! TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGELENGTH, &height)) {
+		pop_handlers ();
+		return;
+	}
+
+	if (! TIFFGetField (tiff_document->tiff, TIFFTAG_ORIENTATION, &orientation)) {
+		orientation = ORIENTATION_TOPLEFT;
+	}
+
+	pop_handlers ();
+  
+	/* Sanity check the doc */
+	if (width <= 0 || height <= 0)
+		return;                
+
+#ifdef HAVE_CAIRO_FORMAT_STRIDE_FOR_WIDTH
+	rowstride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
+#else
+	rowstride = width * 4;
+	if (rowstride / 4 != width)
+		/* overflow */
+		return;                
+#endif
+	
+	bytes = height * rowstride;
+	if (bytes / rowstride != height)
+		/* overflow */
+		return;                
+	
+	pixels = g_try_malloc (bytes);
+	if (!pixels)
+		return;
+	
+	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,
+				   orientation, 1);
+	pop_handlers ();
+
+	/* Convert the format returned by libtiff to
+	* what cairo expects
+	*/
+	p = pixels;
+	while (p < pixels + bytes) {
+		uint32 pixel = *(uint32 *)p;
+		int r = TIFFGetR(pixel);
+		int g = TIFFGetG(pixel);
+		int b = TIFFGetB(pixel);
+		int a = TIFFGetA(pixel);
+		
+		*p++ = b;
+		*p++ = g;
+		*p++ = r;
+		*p++ = a;
+	}
+
+	cairo_set_source_surface (cr, surface, 0, 0);
+	cairo_paint (cr);
+	cairo_surface_destroy (surface);
+}
+
+static void
 tiff_document_finalize (GObject *object)
 {
 	TiffDocument *tiff_document = TIFF_DOCUMENT (object);
@@ -437,6 +533,7 @@
 	iface->render = tiff_document_render;
 	iface->get_page_label = tiff_document_get_page_label;
 	iface->get_info = tiff_document_get_info;
+	iface->cairo_print_page = tiff_document_cairo_print_page;
 }
 
 static GdkPixbuf *
Index: backend/pdf/ev-poppler.cc
===================================================================
--- backend/pdf/ev-poppler.cc	(revision 3216)
+++ backend/pdf/ev-poppler.cc	(working copy)
@@ -522,6 +522,19 @@
 				width, height, rc);
 }
 
+static void
+pdf_document_cairo_print_page (EvDocument      *document,
+			       EvRenderContext *rc,
+			       cairo_t         *cr)
+{
+	PdfDocument *pdf_document = PDF_DOCUMENT (document);
+	PopplerPage *poppler_page;
+
+	cairo_scale (cr, rc->scale, rc->scale);
+	poppler_page = POPPLER_PAGE (rc->page->backend_page);
+	poppler_page_render_for_printing (poppler_page, cr);	
+}
+
 /* EvDocumentSecurity */
 
 static gboolean
@@ -707,6 +720,7 @@
 	iface->get_attachments = pdf_document_get_attachments;
 	iface->render = pdf_document_render;
 	iface->get_info = pdf_document_get_info;
+	iface->cairo_print_page = pdf_document_cairo_print_page;
 };
 
 static void
Index: libdocument/ev-document.c
===================================================================
--- libdocument/ev-document.c	(revision 3216)
+++ libdocument/ev-document.c	(working copy)
@@ -243,7 +243,19 @@
 	return retval;
 }
 
+/* Print page to the cairo context "cr". */
 void
+ev_document_cairo_print_page (EvDocument      *document,
+			      EvRenderContext *rc,
+			      cairo_t         *cr)
+{
+	EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
+
+	if (iface->cairo_print_page != NULL)
+		iface->cairo_print_page (document, rc, cr);
+}
+
+void
 ev_document_info_free (EvDocumentInfo *info)
 {
 	if (info == NULL)
Index: libdocument/ev-document.h
===================================================================
--- libdocument/ev-document.h	(revision 3216)
+++ libdocument/ev-document.h	(working copy)
@@ -92,6 +92,9 @@
         cairo_surface_t * (* render)          (EvDocument      *document,
                                                EvRenderContext *rc);
         EvDocumentInfo *  (* get_info)        (EvDocument      *document);
+        void              (* cairo_print_page)(EvDocument      *document,
+					       EvRenderContext *rc,
+					       cairo_t         *cr);
 };
 
 GType            ev_document_get_type         (void) G_GNUC_CONST;
@@ -129,6 +132,9 @@
 GList           *ev_document_get_attachments  (EvDocument      *document);
 cairo_surface_t *ev_document_render           (EvDocument      *document,
                                                EvRenderContext *rc);
+void             ev_document_cairo_print_page (EvDocument      *document,
+					       EvRenderContext *rc,
+					       cairo_t         *cr);
 
 gint            ev_rect_cmp                   (EvRectangle     *a,
                                                EvRectangle     *b);
Index: shell/ev-window.c
===================================================================
--- shell/ev-window.c	(revision 3216)
+++ shell/ev-window.c	(working copy)
@@ -50,6 +50,7 @@
 #include "ephy-zoom.h"
 
 #include "ev-application.h"
+#include "ev-backends-manager.h"
 #include "ev-document-factory.h"
 #include "ev-document-find.h"
 #include "ev-document-fonts.h"
@@ -216,7 +217,8 @@
 	GTK_PRINT_SETTINGS_SCALE,
 	GTK_PRINT_SETTINGS_PRINT_PAGES,
 	GTK_PRINT_SETTINGS_PAGE_RANGES,
-	GTK_PRINT_SETTINGS_PAGE_SET
+	GTK_PRINT_SETTINGS_PAGE_SET,
+	GTK_PRINT_SETTINGS_NUMBER_UP_LAYOUT
 };
 
 static void	ev_window_update_actions	 	(EvWindow         *ev_window);
@@ -2563,7 +2565,128 @@
 	gtk_widget_show (dialog);
 }
 
+/* Initial setting of printing. */
 static void
+ev_begin_print (GtkPrintOperation *operation, 
+		GtkPrintContext   *context,
+		gpointer           user_data)
+{
+	EvWindow      *data = (EvWindow *) user_data;
+	gint           num_pages = 0;
+
+	num_pages = ev_page_cache_get_n_pages (ev_page_cache_get (data->priv->document));
+	gtk_print_operation_set_n_pages (operation, num_pages);
+}
+
+/* Draw page with number "page_nr" to the cairo context provided by the GtkPrintContext "context". */
+static void
+ev_draw_page (GtkPrintOperation *operation,
+	      GtkPrintContext   *context,
+	      gint               page_nr,
+	      gpointer           user_data)
+{
+	EvWindow         *data = (EvWindow *) user_data;
+	EvDocument       *document = data->priv->document;
+	EvRenderContext  *rc;
+	GtkPageSetup     *setup = NULL;
+	cairo_t          *cr;
+	gdouble           paper_width;
+	gdouble           paper_height;
+	gdouble           doc_width;
+	gdouble           doc_height;
+	gdouble           ratio = 1.0;
+	gdouble           ratio1 = 1.0;
+	gdouble           ratio2 = 1.0;
+	EvPage           *ev_page;
+
+	ev_page = ev_document_get_page (document, page_nr);
+	ev_document_get_page_size (document, ev_page, &doc_width, &doc_height);
+
+	setup = gtk_print_context_get_page_setup (context);
+	paper_width = gtk_page_setup_get_paper_width (setup, GTK_UNIT_POINTS);
+	paper_height = gtk_page_setup_get_paper_height (setup, GTK_UNIT_POINTS);
+
+	ratio1 = paper_width / doc_width;
+	ratio2 = paper_height / doc_height;
+
+	ratio = ratio1 < ratio2 ? ratio1 : ratio2;
+
+	rc = ev_render_context_new (ev_page, 0, ratio);
+	cr = gtk_print_context_get_cairo_context (context);
+
+	ev_document_doc_mutex_lock ();
+	ev_document_cairo_print_page (document, rc, cr);
+	ev_document_doc_mutex_unlock ();
+
+	g_object_unref (rc);
+	g_object_unref (ev_page);
+}
+
+/* Run GtkPrintOperation to print the document. */
+void
+ev_window_print_operation (EvWindow *ev_window)
+{
+	GtkPrintOperationResult  result;
+	GtkPrintOperation       *operation = NULL;
+	GtkWidget               *error_dialog = NULL;
+	GError                  *error = NULL;
+	gint                     current_page = -1;
+
+	operation = gtk_print_operation_new ();
+
+	if (ev_window->priv->print_page_setup != NULL)
+		gtk_print_operation_set_default_page_setup (operation, ev_window->priv->print_page_setup);
+
+	if (ev_window->priv->print_settings == NULL) {
+		ev_window->priv->print_settings = gtk_print_settings_copy (ev_application_get_print_settings (EV_APP));
+		ev_window_load_print_settings_from_metadata (ev_window);
+		gtk_print_operation_set_print_settings (operation, ev_window->priv->print_settings);
+	}
+	else {
+		gtk_print_operation_set_print_settings (operation, ev_window->priv->print_settings);
+	}
+
+	current_page = ev_page_cache_get_current_page (ev_window->priv->page_cache);
+	gtk_print_operation_set_current_page (operation, current_page);
+
+	gtk_print_operation_set_use_full_page (operation, TRUE);
+
+	g_signal_connect (G_OBJECT (operation), "begin-print", 
+			  G_CALLBACK (ev_begin_print), ev_window);
+
+	g_signal_connect (G_OBJECT (operation), "draw-page", 
+			  G_CALLBACK (ev_draw_page), ev_window);
+
+	result = gtk_print_operation_run (operation,
+					  GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
+					  GTK_WINDOW (ev_window),
+					  &error);
+
+	if (result == GTK_PRINT_OPERATION_RESULT_ERROR) {
+		error_dialog = gtk_message_dialog_new (GTK_WINDOW (ev_window),
+						       GTK_DIALOG_DESTROY_WITH_PARENT,
+						       GTK_MESSAGE_ERROR,
+						       GTK_BUTTONS_CLOSE,
+						       "Error printing file:\n%s",
+						       error->message);
+
+		g_signal_connect (error_dialog, "response", 
+				  G_CALLBACK (gtk_widget_destroy), NULL);
+		gtk_widget_show (error_dialog);
+		g_error_free (error);
+	}
+	else if (result == GTK_PRINT_OPERATION_RESULT_APPLY) {
+		if (ev_window->priv->print_settings != NULL)
+			g_object_unref (ev_window->priv->print_settings);
+		ev_window->priv->print_settings = g_object_ref (gtk_print_operation_get_print_settings (operation));
+		ev_application_set_print_settings (EV_APP, ev_window->priv->print_settings);
+		ev_window_save_print_settings (ev_window);
+	}
+
+	g_object_unref (operation);
+}
+
+static void
 ev_window_print (EvWindow *window)
 {
 	EvPageCache *page_cache;
@@ -2572,7 +2695,12 @@
 	page_cache = ev_page_cache_get (window->priv->document);
 	last_page = ev_page_cache_get_n_pages (page_cache);
 
-	ev_window_print_range (window, 1, last_page);
+	/* Print the document using full Gtk+ print stack when possible. */
+	if (strcmp (ev_backends_manager_get_document_module_name (window->priv->document), "pdfdocument") == 0 ||
+	    strcmp (ev_backends_manager_get_document_module_name (window->priv->document), "tiffdocument") == 0)
+		ev_window_print_operation (window);
+	else
+		ev_window_print_range (window, 1, last_page);
 }
 
 static void
Index: shell/ev-window.h
===================================================================
--- shell/ev-window.h	(revision 3216)
+++ shell/ev-window.h	(working copy)
@@ -84,6 +84,7 @@
 void		ev_window_print_range     (EvWindow       *ev_window,
 					   int             first_page,
 					   int		   last_page);
+void		ev_window_print_operation (EvWindow       *ev_window);
 
 G_END_DECLS
 
