From 217797d63b2d3b1c9a7a0511af1bbf3d99f0d482 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Campos Date: Wed, 13 Jun 2007 08:54:53 +0000 Subject: [PATCH] Use cairo image surfaces instead of GDK pixbufs for drawing pages and 2007-06-13 Carlos Garcia Campos * backend/dvi/dvi-document.c: (dvi_document_render), (dvi_document_render_pixbuf), (dvi_document_document_iface_init): * backend/impress/impress-document.c: (imp_render_get_from_drawable), (impress_document_render_pixbuf), (impress_document_render), (impress_document_document_iface_init), (impress_document_thumbnails_get_thumbnail): * backend/djvu/djvu-document-private.h: * backend/djvu/djvu-document.c: (djvu_document_render), (djvu_document_finalize), (djvu_document_document_iface_init), (djvu_document_thumbnails_get_thumbnail), (djvu_document_init): * backend/tiff/tiff-document.c: (tiff_document_render), (tiff_document_render_pixbuf), (tiff_document_document_iface_init): * backend/pdf/ev-poppler.cc: (pdf_document_render), (pdf_document_render_pixbuf), (pdf_document_document_iface_init), (pdf_selection_render_selection): * backend/comics/comics-document.c: (comics_document_render_pixbuf), (comics_document_render), (comics_document_document_iface_init): * backend/pixbuf/pixbuf-document.c: (pixbuf_document_render), (pixbuf_document_document_iface_init): * libdocument/ev-document-misc.[ch]: (ev_document_misc_surface_from_pixbuf), (ev_document_misc_surface_rotate_and_scale): * libdocument/ev-document.[ch]: (ev_document_render): * libdocument/ev-selection.[ch]: (ev_selection_render_selection): * shell/ev-pixbuf-cache.[ch]: (dispose_cache_job_info), (move_one_job), (copy_job_to_job_info), (add_job_if_needed), (ev_pixbuf_cache_get_surface), (new_selection_surface_needed), (clear_selection_if_needed), (ev_pixbuf_cache_style_changed), (ev_pixbuf_cache_get_selection_surface), (clear_job_selection): * shell/ev-jobs.[ch]: (ev_job_render_dispose), (render_finished_cb), (ev_job_render_run): * shell/ev-view.c: (draw_loading_text), (draw_one_page), (merge_selection_region): Use cairo image surfaces instead of GDK pixbufs for drawing pages and selections. svn path=/trunk/; revision=2499 --- ChangeLog | 41 +++++ backend/comics/comics-document.c | 29 +++- backend/djvu/djvu-document-private.h | 1 + backend/djvu/djvu-document.c | 95 +++++++----- backend/dvi/dvi-document.c | 28 ++-- backend/impress/impress-document.c | 62 +++++--- backend/pdf/ev-poppler.cc | 104 ++++++++++--- backend/pixbuf/pixbuf-document.c | 25 ++-- backend/tiff/tiff-document.c | 93 ++++++++++-- libdocument/ev-document-misc.c | 93 +++++++++++- libdocument/ev-document-misc.h | 6 + libdocument/ev-document.c | 12 +- libdocument/ev-document.h | 149 +++++++++--------- libdocument/ev-selection.c | 4 +- libdocument/ev-selection.h | 4 +- shell/ev-jobs.c | 18 ++- shell/ev-jobs.h | 4 +- shell/ev-pixbuf-cache.c | 86 ++++++----- shell/ev-pixbuf-cache.h | 10 +- shell/ev-view.c | 216 ++++++++++++++------------- 20 files changed, 728 insertions(+), 352 deletions(-) diff --git a/ChangeLog b/ChangeLog index 35fa4305..ce3adcbc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,44 @@ +2007-06-13 Carlos Garcia Campos + + * backend/dvi/dvi-document.c: (dvi_document_render), + (dvi_document_render_pixbuf), (dvi_document_document_iface_init): + * backend/impress/impress-document.c: + (imp_render_get_from_drawable), (impress_document_render_pixbuf), + (impress_document_render), (impress_document_document_iface_init), + (impress_document_thumbnails_get_thumbnail): + * backend/djvu/djvu-document-private.h: + * backend/djvu/djvu-document.c: (djvu_document_render), + (djvu_document_finalize), (djvu_document_document_iface_init), + (djvu_document_thumbnails_get_thumbnail), (djvu_document_init): + * backend/tiff/tiff-document.c: (tiff_document_render), + (tiff_document_render_pixbuf), + (tiff_document_document_iface_init): + * backend/pdf/ev-poppler.cc: (pdf_document_render), + (pdf_document_render_pixbuf), (pdf_document_document_iface_init), + (pdf_selection_render_selection): + * backend/comics/comics-document.c: + (comics_document_render_pixbuf), (comics_document_render), + (comics_document_document_iface_init): + * backend/pixbuf/pixbuf-document.c: (pixbuf_document_render), + (pixbuf_document_document_iface_init): + * libdocument/ev-document-misc.[ch]: + (ev_document_misc_surface_from_pixbuf), + (ev_document_misc_surface_rotate_and_scale): + * libdocument/ev-document.[ch]: (ev_document_render): + * libdocument/ev-selection.[ch]: (ev_selection_render_selection): + * shell/ev-pixbuf-cache.[ch]: (dispose_cache_job_info), + (move_one_job), (copy_job_to_job_info), (add_job_if_needed), + (ev_pixbuf_cache_get_surface), (new_selection_surface_needed), + (clear_selection_if_needed), (ev_pixbuf_cache_style_changed), + (ev_pixbuf_cache_get_selection_surface), (clear_job_selection): + * shell/ev-jobs.[ch]: (ev_job_render_dispose), + (render_finished_cb), (ev_job_render_run): + * shell/ev-view.c: (draw_loading_text), (draw_one_page), + (merge_selection_region): + + Use cairo image surfaces instead of GDK pixbufs for drawing pages + and selections. + 2007-06-12 Carlos Garcia Campos * shell/ev-window-title.c: (ev_window_title_update): diff --git a/backend/comics/comics-document.c b/backend/comics/comics-document.c index 64bd2b75..092d8c2b 100644 --- a/backend/comics/comics-document.c +++ b/backend/comics/comics-document.c @@ -268,7 +268,7 @@ get_page_size_area_prepared_cb (GdkPixbufLoader *loader, } static GdkPixbuf * -comics_document_render_pixbuf (EvDocument *document, +comics_document_render_pixbuf (EvDocument *document, EvRenderContext *rc) { GdkPixbufLoader *loader; @@ -309,9 +309,24 @@ comics_document_render_pixbuf (EvDocument *document, 360 - rc->rotation); g_spawn_close_pid (child_pid); g_object_unref (loader); + return rotated_pixbuf; } +static cairo_surface_t * +comics_document_render (EvDocument *document, + EvRenderContext *rc) +{ + GdkPixbuf *pixbuf; + cairo_surface_t *surface; + + pixbuf = comics_document_render_pixbuf (document, rc); + surface = ev_document_misc_surface_from_pixbuf (pixbuf); + g_object_unref (pixbuf); + + return surface; +} + static void render_pixbuf_size_prepared_cb (GdkPixbufLoader *loader, gint width, @@ -319,8 +334,8 @@ render_pixbuf_size_prepared_cb (GdkPixbufLoader *loader, gpointer data) { double *scale = data; - int w = width * (*scale); - int h = height * (*scale); + int w = (width * (*scale) + 0.5); + int h = (height * (*scale) + 0.5); gdk_pixbuf_loader_set_size (loader, w, h); } @@ -371,11 +386,11 @@ comics_document_document_iface_init (EvDocumentIface *iface) { iface->load = comics_document_load; iface->save = comics_document_save; - iface->can_get_text = comics_document_can_get_text; - iface->get_n_pages = comics_document_get_n_pages; + iface->can_get_text = comics_document_can_get_text; + iface->get_n_pages = comics_document_get_n_pages; iface->get_page_size = comics_document_get_page_size; - iface->render_pixbuf = comics_document_render_pixbuf; - iface->get_info = comics_document_get_info; + iface->render = comics_document_render; + iface->get_info = comics_document_get_info; } static void diff --git a/backend/djvu/djvu-document-private.h b/backend/djvu/djvu-document-private.h index 37651ef7..3e7deedf 100644 --- a/backend/djvu/djvu-document-private.h +++ b/backend/djvu/djvu-document-private.h @@ -32,6 +32,7 @@ struct _DjvuDocument { ddjvu_context_t *d_context; ddjvu_document_t *d_document; ddjvu_format_t *d_format; + ddjvu_format_t *thumbs_format; gchar *uri; diff --git a/backend/djvu/djvu-document.c b/backend/djvu/djvu-document.c index fc1ccaac..a8f04254 100644 --- a/backend/djvu/djvu-document.c +++ b/backend/djvu/djvu-document.c @@ -203,7 +203,7 @@ djvu_document_get_page_size (EvDocument *document, while ((r = ddjvu_document_get_pageinfo(djvu_document->d_document, page, &info)) < DDJVU_JOB_OK) djvu_handle_events(djvu_document, TRUE); - + if (r >= DDJVU_JOB_FAILED) djvu_handle_events(djvu_document, TRUE); @@ -211,45 +211,57 @@ djvu_document_get_page_size (EvDocument *document, *height = info.height * SCALE_FACTOR; } -static GdkPixbuf * -djvu_document_render_pixbuf (EvDocument *document, - EvRenderContext *rc) +static cairo_surface_t * +djvu_document_render (EvDocument *document, + EvRenderContext *rc) { DjvuDocument *djvu_document = DJVU_DOCUMENT (document); - GdkPixbuf *pixbuf; - GdkPixbuf *rotated_pixbuf; - + cairo_surface_t *surface, *rotated_surface; + gchar *pixels; + gint rowstride; ddjvu_rect_t rrect; ddjvu_rect_t prect; ddjvu_page_t *d_page; - double page_width, page_height; + static const cairo_user_data_key_t key; d_page = ddjvu_page_create_by_pageno (djvu_document->d_document, rc->page); while (!ddjvu_page_decoding_done (d_page)) djvu_handle_events(djvu_document, TRUE); - - page_width = ddjvu_page_get_width (d_page) * rc->scale * SCALE_FACTOR; - page_height = ddjvu_page_get_height (d_page) * rc->scale * SCALE_FACTOR; - pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, page_width, page_height); - - prect.x = 0; prect.y = 0; - prect.w = page_width; prect.h = page_height; + page_width = ddjvu_page_get_width (d_page) * rc->scale * SCALE_FACTOR + 0.5; + page_height = ddjvu_page_get_height (d_page) * rc->scale * SCALE_FACTOR + 0.5; + + rowstride = page_width * 4; + pixels = (gchar *) g_malloc (page_height * rowstride); + surface = cairo_image_surface_create_for_data (pixels, + CAIRO_FORMAT_ARGB32, + page_width, + page_height, + rowstride); + cairo_surface_set_user_data (surface, &key, + pixels, (cairo_destroy_func_t)g_free); + prect.x = 0; + prect.y = 0; + prect.w = page_width; + prect.h = page_height; rrect = prect; - ddjvu_page_render(d_page, DDJVU_RENDER_COLOR, - &prect, - &rrect, - djvu_document->d_format, - gdk_pixbuf_get_rowstride (pixbuf), - (gchar *)gdk_pixbuf_get_pixels (pixbuf)); - - rotated_pixbuf = gdk_pixbuf_rotate_simple (pixbuf, 360 - rc->rotation); - g_object_unref (pixbuf); - - return rotated_pixbuf; + ddjvu_page_render (d_page, DDJVU_RENDER_COLOR, + &prect, + &rrect, + djvu_document->d_format, + rowstride, + pixels); + + rotated_surface = ev_document_misc_surface_rotate_and_scale (surface, + page_width, + page_height, + rc->rotation); + cairo_surface_destroy (surface); + + return rotated_surface; } static void @@ -268,6 +280,7 @@ djvu_document_finalize (GObject *object) ddjvu_context_release (djvu_document->d_context); ddjvu_format_release (djvu_document->d_format); + ddjvu_format_release (djvu_document->thumbs_format); g_free (djvu_document->uri); G_OBJECT_CLASS (djvu_document_parent_class)->finalize (object); @@ -329,7 +342,7 @@ djvu_document_document_iface_init (EvDocumentIface *iface) iface->get_text = djvu_document_get_text; iface->get_n_pages = djvu_document_get_n_pages; iface->get_page_size = djvu_document_get_page_size; - iface->render_pixbuf = djvu_document_render_pixbuf; + iface->render = djvu_document_render; iface->get_info = djvu_document_get_info; } @@ -383,7 +396,7 @@ djvu_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document, ddjvu_thumbnail_render (djvu_document->d_document, rc->page, &thumb_width, &thumb_height, - djvu_document->d_format, + djvu_document->thumbs_format, gdk_pixbuf_get_rowstride (pixbuf), (gchar *)pixels); @@ -417,13 +430,13 @@ djvu_document_file_exporter_format_supported (EvFileExporter *exporter, static void djvu_document_file_exporter_begin (EvFileExporter *exporter, - EvFileExporterFormat format, - const char *filename, /* for storing the temp ps file */ - int first_page, - int last_page, - double width, - double height, - gboolean duplex) + EvFileExporterFormat format, + const char *filename, /* for storing the temp ps file */ + int first_page, + int last_page, + double width, + double height, + gboolean duplex) { DjvuDocument *djvu_document = DJVU_DOCUMENT (exporter); @@ -435,7 +448,8 @@ djvu_document_file_exporter_begin (EvFileExporter *exporter, } static void -djvu_document_file_exporter_do_page (EvFileExporter *exporter, EvRenderContext *rc) +djvu_document_file_exporter_do_page (EvFileExporter *exporter, + EvRenderContext *rc) { DjvuDocument *djvu_document = DJVU_DOCUMENT (exporter); @@ -478,9 +492,14 @@ djvu_document_file_exporter_iface_init (EvFileExporterIface *iface) static void djvu_document_init (DjvuDocument *djvu_document) { + guint masks[4] = { 0xff0000, 0xff00, 0xff, 0xff000000 }; + djvu_document->d_context = ddjvu_context_create ("Evince"); - djvu_document->d_format = ddjvu_format_create (DDJVU_FORMAT_RGB24, 0, 0); - ddjvu_format_set_row_order (djvu_document->d_format,1); + djvu_document->d_format = ddjvu_format_create (DDJVU_FORMAT_RGBMASK32, 4, masks); + ddjvu_format_set_row_order (djvu_document->d_format, 1); + + djvu_document->thumbs_format = ddjvu_format_create (DDJVU_FORMAT_RGB24, 0, 0); + ddjvu_format_set_row_order (djvu_document->thumbs_format, 1); djvu_document->ps_filename = NULL; djvu_document->opts = g_string_new (""); diff --git a/backend/dvi/dvi-document.c b/backend/dvi/dvi-document.c index 9abdca71..445c1e0c 100644 --- a/backend/dvi/dvi-document.c +++ b/backend/dvi/dvi-document.c @@ -152,15 +152,14 @@ dvi_document_get_page_size (EvDocument *document, return; } -static GdkPixbuf * -dvi_document_render_pixbuf (EvDocument *document, - EvRenderContext *rc) +static cairo_surface_t * +dvi_document_render (EvDocument *document, + EvRenderContext *rc) { GdkPixbuf *pixbuf; - GdkPixbuf *rotated_pixbuf; - + cairo_surface_t *surface; + cairo_surface_t *rotated_surface; DviDocument *dvi_document = DVI_DOCUMENT(document); - gint required_width, required_height; gint proposed_width, proposed_height; gint xmargin = 0, ymargin = 0; @@ -177,8 +176,8 @@ dvi_document_render_pixbuf (EvDocument *document, (int)((dvi_document->params->hshrink - 1) / rc->scale) + 1, (int)((dvi_document->params->vshrink - 1) / rc->scale) + 1); - required_width = dvi_document->base_width * rc->scale; - required_height = dvi_document->base_height * rc->scale; + required_width = dvi_document->base_width * rc->scale + 0.5; + required_height = dvi_document->base_height * rc->scale + 0.5; proposed_width = dvi_document->context->dvi_page_w * dvi_document->context->params.conv; proposed_height = dvi_document->context->dvi_page_h * dvi_document->context->params.vconv; @@ -195,10 +194,17 @@ dvi_document_render_pixbuf (EvDocument *document, g_mutex_unlock (dvi_context_mutex); - rotated_pixbuf = gdk_pixbuf_rotate_simple (pixbuf, 360 - rc->rotation); + /* FIXME: we should write a mdvi device based on cairo */ + surface = ev_document_misc_surface_from_pixbuf (pixbuf); g_object_unref (pixbuf); - return rotated_pixbuf; + rotated_surface = ev_document_misc_surface_rotate_and_scale (surface, + required_width, + required_height, + rc->rotation); + cairo_surface_destroy (surface); + + return rotated_surface; } static void @@ -260,7 +266,7 @@ dvi_document_document_iface_init (EvDocumentIface *iface) iface->can_get_text = dvi_document_can_get_text; iface->get_n_pages = dvi_document_get_n_pages; iface->get_page_size = dvi_document_get_page_size; - iface->render_pixbuf = dvi_document_render_pixbuf; + iface->render = dvi_document_render; iface->get_info = dvi_document_get_info; } diff --git a/backend/impress/impress-document.c b/backend/impress/impress-document.c index 5f5982ed..6251fbd2 100644 --- a/backend/impress/impress-document.c +++ b/backend/impress/impress-document.c @@ -355,8 +355,10 @@ imp_render_get_from_drawable (ImpressDocument *impress_document) g_return_val_if_fail (page != NULL, FALSE); + ev_document_doc_mutex_lock (); imp_context_set_page (impress_document->ctx, page); imp_render (impress_document->ctx, impress_document); + ev_document_doc_mutex_unlock (); impress_document->pixbuf = gdk_pixbuf_get_from_drawable (NULL, GDK_DRAWABLE (impress_document->pixmap), @@ -370,36 +372,56 @@ imp_render_get_from_drawable (ImpressDocument *impress_document) } static GdkPixbuf * -impress_document_render_pixbuf (EvDocument *document, +impress_document_render_pixbuf (EvDocument *document, EvRenderContext *rc) { ImpressDocument *impress_document = IMPRESS_DOCUMENT (document); - GdkPixbuf *scaled_pixbuf; - - g_return_val_if_fail (IMPRESS_IS_DOCUMENT (document), 0); - g_return_val_if_fail (impress_document->imp != NULL, 0); + GdkPixbuf *pixbuf; + g_return_val_if_fail (IMPRESS_IS_DOCUMENT (document), NULL); + g_return_val_if_fail (impress_document->imp != NULL, NULL); + impress_document->pagenum = rc->page; g_mutex_lock (impress_document->mutex); impress_document->cond = g_cond_new (); ev_document_fc_mutex_unlock (); + ev_document_doc_mutex_unlock (); g_idle_add ((GSourceFunc) imp_render_get_from_drawable, impress_document); g_cond_wait (impress_document->cond, impress_document->mutex); g_cond_free (impress_document->cond); + ev_document_doc_mutex_lock (); ev_document_fc_mutex_lock (); - + g_mutex_unlock (impress_document->mutex); - scaled_pixbuf = gdk_pixbuf_scale_simple (impress_document->pixbuf, - PAGE_WIDTH * rc->scale, - PAGE_HEIGHT * rc->scale, - GDK_INTERP_BILINEAR); - gdk_pixbuf_unref (impress_document->pixbuf); + pixbuf = impress_document->pixbuf; impress_document->pixbuf = NULL; - return scaled_pixbuf; + return pixbuf; +} + +static cairo_surface_t * +impress_document_render (EvDocument *document, + EvRenderContext *rc) +{ + GdkPixbuf *pixbuf; + cairo_surface_t *surface, *scaled_surface; + + pixbuf = impress_document_render_pixbuf (document, rc); + + /* FIXME: impress backend should be ported to cairo */ + surface = ev_document_misc_surface_from_pixbuf (pixbuf); + g_object_unref (pixbuf); + + scaled_surface = ev_document_misc_surface_rotate_and_scale (surface, + (PAGE_WIDTH * rc->scale) + 0.5, + (PAGE_HEIGHT * rc->scale) + 0.5, + rc->rotation); + cairo_surface_destroy (surface); + + return scaled_surface; } static void @@ -461,7 +483,7 @@ impress_document_document_iface_init (EvDocumentIface *iface) iface->can_get_text = impress_document_can_get_text; iface->get_n_pages = impress_document_get_n_pages; iface->get_page_size = impress_document_get_page_size; - iface->render_pixbuf = impress_document_render_pixbuf; + iface->render = impress_document_render; iface->get_info = impress_document_get_info; } @@ -470,20 +492,26 @@ impress_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document, EvRenderContext *rc, gboolean border) { - GdkPixbuf *pixbuf = NULL; + GdkPixbuf *pixbuf; + GdkPixbuf *scaled_pixbuf; gdouble w, h; pixbuf = impress_document_render_pixbuf (EV_DOCUMENT (document), rc); + scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf, + (PAGE_WIDTH * rc->scale), + (PAGE_HEIGHT * rc->scale), + GDK_INTERP_BILINEAR); + g_object_unref (pixbuf); if (border) { - GdkPixbuf *tmp_pixbuf = pixbuf; + GdkPixbuf *tmp_pixbuf = scaled_pixbuf; - pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, tmp_pixbuf); + scaled_pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, tmp_pixbuf); g_object_unref (tmp_pixbuf); } - return pixbuf; + return scaled_pixbuf; } static void diff --git a/backend/pdf/ev-poppler.cc b/backend/pdf/ev-poppler.cc index a3549b24..e3b80b45 100644 --- a/backend/pdf/ev-poppler.cc +++ b/backend/pdf/ev-poppler.cc @@ -426,12 +426,12 @@ pdf_document_get_attachments (EvDocument *document) return g_list_reverse (retval); } -static GdkPixbuf * -pdf_document_render_pixbuf (EvDocument *document, - EvRenderContext *rc) +static cairo_surface_t * +pdf_document_render (EvDocument *document, + EvRenderContext *rc) { PdfDocument *pdf_document; - GdkPixbuf *pixbuf; + cairo_surface_t *surface; double width_points, height_points; gint width, height; @@ -448,7 +448,37 @@ pdf_document_render_pixbuf (EvDocument *document, width = (int) ((width_points * rc->scale) + 0.5); height = (int) ((height_points * rc->scale) + 0.5); } - + +#ifdef HAVE_POPPLER_PAGE_RENDER + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + width, height); + memset (cairo_image_surface_get_data (surface), 0xff, + cairo_image_surface_get_height (surface) * + cairo_image_surface_get_stride (surface)); + + cr = cairo_create (surface); + switch (rc->rotation) { + case 90: + cairo_translate (cr, width, 0); + break; + case 180: + cairo_translate (cr, width, height); + break; + case 270: + cairo_translate (cr, 0, height); + break; + default: + cairo_translate (cr, 0, 0); + } + cairo_scale (cr, rc->scale, rc->scale); + cairo_rotate (cr, rc->rotation * G_PI / 180.0); + poppler_page_render (POPPLER_PAGE (rc->data), cr); + cairo_destroy (cr); +#else /* HAVE_POPPLER_PAGE_RENDER */ + GdkPixbuf *pixbuf; + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height); @@ -459,9 +489,11 @@ pdf_document_render_pixbuf (EvDocument *document, rc->scale, rc->rotation, pixbuf); - - - return pixbuf; + surface = ev_document_misc_surface_from_pixbuf (pixbuf); + g_object_unref (pixbuf); +#endif /* HAVE_POPPLER_PAGE_RENDER */ + + return surface; } /* EvDocumentSecurity */ @@ -671,7 +703,7 @@ pdf_document_document_iface_init (EvDocumentIface *iface) iface->get_page_label = pdf_document_get_page_label; iface->has_attachments = pdf_document_has_attachments; iface->get_attachments = pdf_document_get_attachments; - iface->render_pixbuf = pdf_document_render_pixbuf; + iface->render = pdf_document_render; iface->get_text = pdf_document_get_text; iface->can_get_text = pdf_document_can_get_text; iface->get_info = pdf_document_get_info; @@ -1600,11 +1632,11 @@ pdf_document_file_exporter_iface_init (EvFileExporterIface *iface) static void pdf_selection_render_selection (EvSelection *selection, EvRenderContext *rc, - GdkPixbuf **pixbuf, + cairo_surface_t **surface, EvRectangle *points, EvRectangle *old_points, - GdkColor *text, - GdkColor *base) + GdkColor *text, + GdkColor *base) { PdfDocument *pdf_document; double width_points, height_points; @@ -1613,23 +1645,54 @@ pdf_selection_render_selection (EvSelection *selection, pdf_document = PDF_DOCUMENT (selection); set_rc_data (pdf_document, rc); - poppler_page_get_size (POPPLER_PAGE (rc->data), &width_points, &height_points); + poppler_page_get_size (POPPLER_PAGE (rc->data), + &width_points, &height_points); width = (int) ((width_points * rc->scale) + 0.5); height = (int) ((height_points * rc->scale) + 0.5); - if (*pixbuf == NULL) { - * pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, - TRUE, 8, - width, height); + +#ifdef HAVE_POPPLER_PAGE_RENDER + cairo_t *cr; + + if (*surface == NULL) { + *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + width, height); + } + cr = cairo_create (*surface); + cairo_scale (cr, rc->scale, rc->scale); + cairo_surface_set_device_offset (*surface, 0, 0); + memset (cairo_image_surface_get_data (*surface), 0x00, + cairo_image_surface_get_height (*surface) * + cairo_image_surface_get_stride (*surface)); + poppler_page_render_selection (POPPLER_PAGE (rc->data), + cr, + (PopplerRectangle *)points, + (PopplerRectangle *)old_points, + POPPLER_SELECTION_NORMAL, /* SelectionStyle */ + text, + base); + cairo_destroy (cr); +#else /* HAVE_POPPLER_PAGE_RENDER */ + GdkPixbuf *pixbuf; + + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, + TRUE, 8, + width, height); + poppler_page_render_selection_to_pixbuf (POPPLER_PAGE (rc->data), - rc->scale, rc->rotation, *pixbuf, + rc->scale, rc->rotation, pixbuf, (PopplerRectangle *)points, (PopplerRectangle *)old_points, POPPLER_SELECTION_NORMAL, /* SelectionStyle */ text, base); + if (*surface) + cairo_surface_destroy (*surface); + *surface = ev_document_misc_surface_from_pixbuf (pixbuf); + g_object_unref (pixbuf); +#endif /* HAVE_POPPLER_PAGE_RENDER */ } @@ -1645,8 +1708,9 @@ pdf_selection_get_selection_region (EvSelection *selection, set_rc_data (pdf_document, rc); - retval = poppler_page_get_selection_region ((PopplerPage *)rc->data, rc->scale, (PopplerRectangle *) points); - + retval = poppler_page_get_selection_region ((PopplerPage *)rc->data, + rc->scale, + (PopplerRectangle *) points); return retval; } diff --git a/backend/pixbuf/pixbuf-document.c b/backend/pixbuf/pixbuf-document.c index c1cace00..83d2b8ae 100644 --- a/backend/pixbuf/pixbuf-document.c +++ b/backend/pixbuf/pixbuf-document.c @@ -101,22 +101,27 @@ pixbuf_document_get_page_size (EvDocument *document, *height = gdk_pixbuf_get_height (pixbuf_document->pixbuf); } -static GdkPixbuf* -pixbuf_document_render_pixbuf (EvDocument *document, - EvRenderContext *rc) +static cairo_surface_t * +pixbuf_document_render (EvDocument *document, + EvRenderContext *rc) { PixbufDocument *pixbuf_document = PIXBUF_DOCUMENT (document); GdkPixbuf *scaled_pixbuf, *rotated_pixbuf; + cairo_surface_t *surface; - scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf_document->pixbuf, - gdk_pixbuf_get_width (pixbuf_document->pixbuf) * rc->scale, - gdk_pixbuf_get_height (pixbuf_document->pixbuf) * rc->scale, - GDK_INTERP_BILINEAR); - + scaled_pixbuf = gdk_pixbuf_scale_simple ( + pixbuf_document->pixbuf, + (gdk_pixbuf_get_width (pixbuf_document->pixbuf) * rc->scale) + 0.5, + (gdk_pixbuf_get_height (pixbuf_document->pixbuf) * rc->scale) + 0.5, + GDK_INTERP_BILINEAR); + rotated_pixbuf = gdk_pixbuf_rotate_simple (scaled_pixbuf, 360 - rc->rotation); g_object_unref (scaled_pixbuf); - return rotated_pixbuf; + surface = ev_document_misc_surface_from_pixbuf (rotated_pixbuf); + g_object_unref (rotated_pixbuf); + + return surface; } static void @@ -163,7 +168,7 @@ pixbuf_document_document_iface_init (EvDocumentIface *iface) iface->can_get_text = pixbuf_document_can_get_text; iface->get_n_pages = pixbuf_document_get_n_pages; iface->get_page_size = pixbuf_document_get_page_size; - iface->render_pixbuf = pixbuf_document_render_pixbuf; + iface->render = pixbuf_document_render; iface->get_info = pixbuf_document_get_info; } diff --git a/backend/tiff/tiff-document.c b/backend/tiff/tiff-document.c index 74259472..8247c2a2 100644 --- a/backend/tiff/tiff-document.c +++ b/backend/tiff/tiff-document.c @@ -201,9 +201,9 @@ tiff_document_get_page_size (EvDocument *document, pop_handlers (); } -static GdkPixbuf * -tiff_document_render_pixbuf (EvDocument *document, - EvRenderContext *rc) +static cairo_surface_t * +tiff_document_render (EvDocument *document, + EvRenderContext *rc) { TiffDocument *tiff_document = TIFF_DOCUMENT (document); int width, height; @@ -213,6 +213,9 @@ tiff_document_render_pixbuf (EvDocument *document, GdkPixbuf *pixbuf; GdkPixbuf *scaled_pixbuf; GdkPixbuf *rotated_pixbuf; + 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); @@ -237,6 +240,79 @@ tiff_document_render_pixbuf (EvDocument *document, pop_handlers (); + /* Sanity check the doc */ + if (width <= 0 || height <= 0) + return NULL; + + rowstride = width * 4; + if (rowstride / 4 != width) + /* overflow */ + return NULL; + + bytes = height * rowstride; + if (bytes / rowstride != height) + /* overflow */ + return NULL; + + pixels = g_try_malloc (bytes); + if (!pixels) + return NULL; + + surface = cairo_image_surface_create_for_data (pixels, + CAIRO_FORMAT_ARGB32, + 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_TOPLEFT, 1); + pop_handlers (); + + rotated_surface = ev_document_misc_surface_rotate_and_scale (surface, + (width * rc->scale) + 0.5, + (height * rc->scale * (x_res / y_res)) + 0.5, + rc->rotation); + cairo_surface_destroy (surface); + + return rotated_surface; +} + +static GdkPixbuf * +tiff_document_render_pixbuf (EvDocument *document, + EvRenderContext *rc) +{ + TiffDocument *tiff_document = TIFF_DOCUMENT (document); + int width, height; + float x_res, y_res; + gint rowstride, bytes; + guchar *pixels = NULL; + GdkPixbuf *pixbuf; + GdkPixbuf *scaled_pixbuf; + GdkPixbuf *rotated_pixbuf; + + push_handlers (); + if (TIFFSetDirectory (tiff_document->tiff, rc->page) != 1) { + pop_handlers (); + return NULL; + } + + if (!TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGEWIDTH, &width)) { + pop_handlers (); + return NULL; + } + + if (! TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGELENGTH, &height)) { + pop_handlers (); + return NULL; + } + + tiff_document_get_resolution (tiff_document, &x_res, &y_res); + + pop_handlers (); + /* Sanity check the doc */ if (width <= 0 || height <= 0) return NULL; @@ -258,13 +334,12 @@ tiff_document_render_pixbuf (EvDocument *document, pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8, width, height, rowstride, (GdkPixbufDestroyNotify) g_free, NULL); - - pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height); - TIFFReadRGBAImageOriented (tiff_document->tiff, width, height, - (uint32 *)gdk_pixbuf_get_pixels (pixbuf), + TIFFReadRGBAImageOriented (tiff_document->tiff, + width, height, + (uint32 *)pixels, ORIENTATION_TOPLEFT, 1); pop_handlers (); - + scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf, width * rc->scale, height * rc->scale * (x_res / y_res), @@ -323,7 +398,7 @@ tiff_document_document_iface_init (EvDocumentIface *iface) iface->can_get_text = tiff_document_can_get_text; iface->get_n_pages = tiff_document_get_n_pages; iface->get_page_size = tiff_document_get_page_size; - iface->render_pixbuf = tiff_document_render_pixbuf; + iface->render = tiff_document_render; iface->get_info = tiff_document_get_info; } diff --git a/libdocument/ev-document-misc.c b/libdocument/ev-document-misc.c index 89ff5fa8..e8739a1a 100644 --- a/libdocument/ev-document-misc.c +++ b/libdocument/ev-document-misc.c @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2007 Carlos Garcia Campos + * Copyright (C) 2000-2003 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ #include "ev-document-misc.h" #include @@ -8,7 +26,6 @@ * NULL, then it will fill the return pixbuf with the contents of * source_pixbuf. */ - GdkPixbuf * ev_document_misc_get_thumbnail_frame (int width, int height, @@ -128,3 +145,77 @@ ev_document_misc_paint_one_page (GdkDrawable *drawable, border->right - border->left); } + +cairo_surface_t * +ev_document_misc_surface_from_pixbuf (GdkPixbuf *pixbuf) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + gdk_pixbuf_get_width (pixbuf), + gdk_pixbuf_get_height (pixbuf)); + cr = cairo_create (surface); + gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); + cairo_paint (cr); + cairo_destroy (cr); + + return surface; +} + +cairo_surface_t * +ev_document_misc_surface_rotate_and_scale (cairo_surface_t *surface, + gint dest_width, + gint dest_height, + gint dest_rotation) +{ + cairo_surface_t *new_surface; + cairo_t *cr; + gint width, height; + gint new_width = dest_width; + gint new_height = dest_height; + + width = cairo_image_surface_get_width (surface); + height = cairo_image_surface_get_height (surface); + + if (dest_width == width && + dest_height == height && + dest_rotation == 0) { + return cairo_surface_reference (surface); + } + + if (dest_rotation == 90 || dest_rotation == 270) { + new_width = dest_height; + new_height = dest_width; + } + + new_surface = cairo_surface_create_similar (surface, + CAIRO_CONTENT_COLOR_ALPHA, + new_width, new_height); + + cr = cairo_create (new_surface); + switch (dest_rotation) { + case 90: + cairo_translate (cr, new_width, 0); + break; + case 180: + cairo_translate (cr, new_width, new_height); + break; + case 270: + cairo_translate (cr, 0, new_height); + break; + default: + cairo_translate (cr, 0, 0); + } + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_BILINEAR); + cairo_scale (cr, + (gdouble)dest_width / width, + (gdouble)dest_height / height); + cairo_rotate (cr, dest_rotation * G_PI / 180.0); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); + cairo_destroy (cr); + + return new_surface; +} + diff --git a/libdocument/ev-document-misc.h b/libdocument/ev-document-misc.h index 5d846717..08607745 100644 --- a/libdocument/ev-document-misc.h +++ b/libdocument/ev-document-misc.h @@ -25,6 +25,7 @@ #include #include +#include G_BEGIN_DECLS @@ -40,6 +41,11 @@ void ev_document_misc_paint_one_page (GdkDrawable *drawable, GdkRectangle *area, GtkBorder *border, gboolean highlight); +cairo_surface_t *ev_document_misc_surface_from_pixbuf (GdkPixbuf *pixbuf); +cairo_surface_t *ev_document_misc_surface_rotate_and_scale (cairo_surface_t *surface, + gint dest_width, + gint dest_height, + gint dest_rotation); G_END_DECLS diff --git a/libdocument/ev-document.c b/libdocument/ev-document.c index a951bfa3..776e4bdf 100644 --- a/libdocument/ev-document.c +++ b/libdocument/ev-document.c @@ -230,17 +230,17 @@ ev_document_get_attachments (EvDocument *document) return retval; } -GdkPixbuf * -ev_document_render_pixbuf (EvDocument *document, - EvRenderContext *rc) +cairo_surface_t * +ev_document_render (EvDocument *document, + EvRenderContext *rc) { EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document); - GdkPixbuf *retval; + cairo_surface_t *retval; LOG ("ev_document_render_pixbuf"); - g_assert (iface->render_pixbuf); + g_assert (iface->render); - retval = iface->render_pixbuf (document, rc); + retval = iface->render (document, rc); return retval; } diff --git a/libdocument/ev-document.h b/libdocument/ev-document.h index 33b7f4d3..ce887fc6 100644 --- a/libdocument/ev-document.h +++ b/libdocument/ev-document.h @@ -25,6 +25,7 @@ #include #include #include +#include #include "ev-link.h" #include "ev-document-info.h" @@ -32,14 +33,14 @@ G_BEGIN_DECLS -#define EV_TYPE_DOCUMENT (ev_document_get_type ()) -#define EV_DOCUMENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EV_TYPE_DOCUMENT, EvDocument)) -#define EV_DOCUMENT_IFACE(k) (G_TYPE_CHECK_CLASS_CAST((k), EV_TYPE_DOCUMENT, EvDocumentIface)) -#define EV_IS_DOCUMENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EV_TYPE_DOCUMENT)) -#define EV_IS_DOCUMENT_IFACE(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EV_TYPE_DOCUMENT)) +#define EV_TYPE_DOCUMENT (ev_document_get_type ()) +#define EV_DOCUMENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EV_TYPE_DOCUMENT, EvDocument)) +#define EV_DOCUMENT_IFACE(k) (G_TYPE_CHECK_CLASS_CAST((k), EV_TYPE_DOCUMENT, EvDocumentIface)) +#define EV_IS_DOCUMENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EV_TYPE_DOCUMENT)) +#define EV_IS_DOCUMENT_IFACE(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EV_TYPE_DOCUMENT)) #define EV_DOCUMENT_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), EV_TYPE_DOCUMENT, EvDocumentIface)) -typedef struct _EvDocument EvDocument; +typedef struct _EvDocument EvDocument; typedef struct _EvDocumentIface EvDocumentIface; typedef struct _EvPageCache EvPageCache; typedef struct _EvPageCacheClass EvPageCacheClass; @@ -50,91 +51,91 @@ typedef struct _EvPageCacheClass EvPageCacheClass; typedef enum { - EV_DOCUMENT_ERROR_INVALID, - EV_DOCUMENT_ERROR_ENCRYPTED + EV_DOCUMENT_ERROR_INVALID, + EV_DOCUMENT_ERROR_ENCRYPTED } EvDocumentError; typedef struct { - double x; - double y; + double x; + double y; } EvPoint; typedef struct { - double x1; - double y1; - double x2; - double y2; + double x1; + double y1; + double x2; + double y2; } EvRectangle; struct _EvDocumentIface { - GTypeInterface base_iface; - - /* Methods */ - gboolean (* load) (EvDocument *document, - const char *uri, - GError **error); - gboolean (* save) (EvDocument *document, - const char *uri, - GError **error); - int (* get_n_pages) (EvDocument *document); - void (* get_page_size) (EvDocument *document, - int page, - double *width, - double *height); - char * (* get_page_label) (EvDocument *document, - int page); - gboolean (* can_get_text) (EvDocument *document); - char * (* get_text) (EvDocument *document, - int page, - EvRectangle *rect); - gboolean (* has_attachments) (EvDocument *document); - GList * (* get_attachments) (EvDocument *document); - GdkPixbuf * (* render_pixbuf) (EvDocument *document, - EvRenderContext *rc); - EvDocumentInfo * (* get_info) (EvDocument *document); + GTypeInterface base_iface; + + /* Methods */ + gboolean (* load) (EvDocument *document, + const char *uri, + GError **error); + gboolean (* save) (EvDocument *document, + const char *uri, + GError **error); + int (* get_n_pages) (EvDocument *document); + void (* get_page_size) (EvDocument *document, + int page, + double *width, + double *height); + char * (* get_page_label) (EvDocument *document, + int page); + gboolean (* can_get_text) (EvDocument *document); + char * (* get_text) (EvDocument *document, + int page, + EvRectangle *rect); + gboolean (* has_attachments) (EvDocument *document); + GList * (* get_attachments) (EvDocument *document); + cairo_surface_t * (* render) (EvDocument *document, + EvRenderContext *rc); + EvDocumentInfo * (* get_info) (EvDocument *document); }; -GType ev_document_get_type (void); -GQuark ev_document_error_quark (void); +GType ev_document_get_type (void) G_GNUC_CONST; +GQuark ev_document_error_quark (void); /* Document mutex */ -GMutex *ev_document_get_doc_mutex (void); -void ev_document_doc_mutex_lock (void); -void ev_document_doc_mutex_unlock (void); +GMutex *ev_document_get_doc_mutex (void); +void ev_document_doc_mutex_lock (void); +void ev_document_doc_mutex_unlock (void); /* FontConfig mutex */ -GMutex *ev_document_get_fc_mutex (void); -void ev_document_fc_mutex_lock (void); -void ev_document_fc_mutex_unlock (void); - -EvDocumentInfo *ev_document_get_info (EvDocument *document); -gboolean ev_document_load (EvDocument *document, - const char *uri, - GError **error); -gboolean ev_document_save (EvDocument *document, - const char *uri, - GError **error); -int ev_document_get_n_pages (EvDocument *document); -void ev_document_get_page_size (EvDocument *document, - int page, - double *width, - double *height); -char *ev_document_get_page_label (EvDocument *document, - int page); -gboolean ev_document_can_get_text (EvDocument *document); -char *ev_document_get_text (EvDocument *document, - int page, - EvRectangle *rect); -gboolean ev_document_has_attachments (EvDocument *document); -GList *ev_document_get_attachments (EvDocument *document); -GdkPixbuf *ev_document_render_pixbuf (EvDocument *document, - EvRenderContext *rc); - -gint ev_rect_cmp (EvRectangle *a, - EvRectangle *b); +GMutex *ev_document_get_fc_mutex (void); +void ev_document_fc_mutex_lock (void); +void ev_document_fc_mutex_unlock (void); + +EvDocumentInfo *ev_document_get_info (EvDocument *document); +gboolean ev_document_load (EvDocument *document, + const char *uri, + GError **error); +gboolean ev_document_save (EvDocument *document, + const char *uri, + GError **error); +int ev_document_get_n_pages (EvDocument *document); +void ev_document_get_page_size (EvDocument *document, + int page, + double *width, + double *height); +char *ev_document_get_page_label (EvDocument *document, + int page); +gboolean ev_document_can_get_text (EvDocument *document); +char *ev_document_get_text (EvDocument *document, + int page, + EvRectangle *rect); +gboolean ev_document_has_attachments (EvDocument *document); +GList *ev_document_get_attachments (EvDocument *document); +cairo_surface_t *ev_document_render (EvDocument *document, + EvRenderContext *rc); + +gint ev_rect_cmp (EvRectangle *a, + EvRectangle *b); G_END_DECLS -#endif +#endif /* EV_DOCUMENT_H */ diff --git a/libdocument/ev-selection.c b/libdocument/ev-selection.c index 2aa45a7c..f7aee2f7 100644 --- a/libdocument/ev-selection.c +++ b/libdocument/ev-selection.c @@ -59,7 +59,7 @@ ev_selection_base_init (gpointer g_class) void ev_selection_render_selection (EvSelection *selection, EvRenderContext *rc, - GdkPixbuf **pixbuf, + cairo_surface_t **surface, EvRectangle *points, EvRectangle *old_points, GdkColor *text, @@ -68,7 +68,7 @@ ev_selection_render_selection (EvSelection *selection, EvSelectionIface *iface = EV_SELECTION_GET_IFACE (selection); iface->render_selection (selection, rc, - pixbuf, + surface, points, old_points, text, base); } diff --git a/libdocument/ev-selection.h b/libdocument/ev-selection.h index d0816040..5ba9776d 100644 --- a/libdocument/ev-selection.h +++ b/libdocument/ev-selection.h @@ -45,7 +45,7 @@ struct _EvSelectionIface void (* render_selection) (EvSelection *selection, EvRenderContext *rc, - GdkPixbuf **pixbuf, + cairo_surface_t **surface, EvRectangle *points, EvRectangle *old_points, GdkColor *text, @@ -60,7 +60,7 @@ struct _EvSelectionIface GType ev_selection_get_type (void); void ev_selection_render_selection (EvSelection *selection, EvRenderContext *rc, - GdkPixbuf **pixbuf, + cairo_surface_t **surface, EvRectangle *points, EvRectangle *old_points, GdkColor *text, diff --git a/shell/ev-jobs.c b/shell/ev-jobs.c index 6ad4dfca..d9cdac8a 100644 --- a/shell/ev-jobs.c +++ b/shell/ev-jobs.c @@ -4,6 +4,7 @@ #include "ev-document-links.h" #include "ev-document-images.h" #include "ev-document-factory.h" +#include "ev-document-misc.h" #include "ev-file-helpers.h" #include "ev-document-fonts.h" #include "ev-selection.h" @@ -120,9 +121,9 @@ ev_job_render_dispose (GObject *object) job = EV_JOB_RENDER (object); - if (job->pixbuf) { - g_object_unref (job->pixbuf); - job->pixbuf = NULL; + if (job->surface) { + cairo_surface_destroy (job->surface); + job->surface = NULL; } if (job->rc) { @@ -131,7 +132,7 @@ ev_job_render_dispose (GObject *object) } if (job->selection) { - g_object_unref (job->selection); + cairo_surface_destroy (job->selection); job->selection = NULL; } @@ -299,13 +300,16 @@ ev_job_render_new (EvDocument *document, } static void -render_finished_cb (EvDocument *document, GdkPixbuf *pixbuf, EvJobRender *job) +render_finished_cb (EvDocument *document, + GdkPixbuf *pixbuf, + EvJobRender *job) { g_signal_handlers_disconnect_by_func (EV_JOB (job)->document, render_finished_cb, job); + /* FIXME: ps backend should be ported to cairo */ + job->surface = ev_document_misc_surface_from_pixbuf (pixbuf); EV_JOB (job)->finished = TRUE; - job->pixbuf = g_object_ref (pixbuf); ev_job_finished (EV_JOB (job)); } @@ -325,7 +329,7 @@ ev_job_render_run (EvJobRender *job) } else { ev_document_fc_mutex_lock (); - job->pixbuf = ev_document_render_pixbuf (EV_JOB (job)->document, job->rc); + job->surface = ev_document_render (EV_JOB (job)->document, job->rc); if (job->include_links && EV_IS_DOCUMENT_LINKS (EV_JOB (job)->document)) job->link_mapping = ev_document_links_get_links (EV_DOCUMENT_LINKS (EV_JOB (job)->document), diff --git a/shell/ev-jobs.h b/shell/ev-jobs.h index 1f210ece..fc681d37 100644 --- a/shell/ev-jobs.h +++ b/shell/ev-jobs.h @@ -121,13 +121,13 @@ struct _EvJobRender EvRenderContext *rc; gint target_width; gint target_height; - GdkPixbuf *pixbuf; + cairo_surface_t *surface; GList *link_mapping; GdkRegion *text_mapping; GList *image_mapping; - GdkPixbuf *selection; + cairo_surface_t *selection; GdkRegion *selection_region; EvRectangle selection_points; GdkColor base; diff --git a/shell/ev-pixbuf-cache.c b/shell/ev-pixbuf-cache.c index 777e0147..2c815c09 100644 --- a/shell/ev-pixbuf-cache.c +++ b/shell/ev-pixbuf-cache.c @@ -11,7 +11,7 @@ typedef struct _CacheJobInfo EvRenderContext *rc; /* Data we get from rendering */ - GdkPixbuf *pixbuf; + cairo_surface_t *surface; GList *link_mapping; GList *image_mapping; GdkRegion *text_mapping; @@ -23,7 +23,7 @@ typedef struct _CacheJobInfo EvRectangle target_points; gboolean points_set; - GdkPixbuf *selection; + cairo_surface_t *selection; GdkRegion *selection_region; } CacheJobInfo; @@ -74,10 +74,10 @@ static CacheJobInfo *find_job_cache (EvPixbufCache *pixbuf_cach static void copy_job_to_job_info (EvJobRender *job_render, CacheJobInfo *job_info, EvPixbufCache *pixbuf_cache); -static gboolean new_selection_pixbuf_needed(EvPixbufCache *pixbuf_cache, - CacheJobInfo *job_info, - gint page, - gfloat scale); +static gboolean new_selection_surface_needed(EvPixbufCache *pixbuf_cache, + CacheJobInfo *job_info, + gint page, + gfloat scale); /* These are used for iterating through the prev and next arrays */ @@ -149,9 +149,9 @@ dispose_cache_job_info (CacheJobInfo *job_info, g_object_unref (G_OBJECT (job_info->job)); job_info->job = NULL; } - if (job_info->pixbuf) { - g_object_unref (G_OBJECT (job_info->pixbuf)); - job_info->pixbuf = NULL; + if (job_info->surface) { + cairo_surface_destroy (job_info->surface); + job_info->surface = NULL; } if (job_info->link_mapping) { ev_link_mapping_free (job_info->link_mapping); @@ -166,7 +166,7 @@ dispose_cache_job_info (CacheJobInfo *job_info, job_info->text_mapping = NULL; } if (job_info->selection) { - g_object_unref (G_OBJECT (job_info->selection)); + cairo_surface_destroy (job_info->selection); job_info->selection = NULL; } if (job_info->selection_region) { @@ -321,7 +321,7 @@ move_one_job (CacheJobInfo *job_info, *target_page = *job_info; job_info->job = NULL; - job_info->pixbuf = NULL; + job_info->surface = NULL; job_info->link_mapping = NULL; job_info->image_mapping = NULL; @@ -411,10 +411,10 @@ copy_job_to_job_info (EvJobRender *job_render, job_info->points_set = FALSE; - if (job_info->pixbuf) { - g_object_unref (G_OBJECT (job_info->pixbuf)); + if (job_info->surface) { + cairo_surface_destroy (job_info->surface); } - job_info->pixbuf = g_object_ref (job_render->pixbuf); + job_info->surface = cairo_surface_reference (job_render->surface); if (job_info->rc) { g_object_unref (G_OBJECT (job_info->rc)); @@ -441,7 +441,7 @@ copy_job_to_job_info (EvJobRender *job_render, if (job_render->include_selection) { if (job_info->selection) { - g_object_unref (G_OBJECT (job_info->selection)); + cairo_surface_destroy (job_info->selection); job_info->selection = NULL; } if (job_info->selection_region) { @@ -451,7 +451,7 @@ copy_job_to_job_info (EvJobRender *job_render, job_info->selection_points = job_render->selection_points; job_info->selection_region = gdk_region_copy (job_render->selection_region); - job_info->selection = g_object_ref (job_render->selection); + job_info->selection = cairo_surface_reference (job_render->selection); g_assert (job_info->selection_points.x1 >= 0); job_info->points_set = TRUE; } @@ -554,9 +554,9 @@ add_job_if_needed (EvPixbufCache *pixbuf_cache, ev_page_cache_get_size (page_cache, page, rotation, scale, &width, &height); - if (job_info->pixbuf && - gdk_pixbuf_get_width (job_info->pixbuf) == width && - gdk_pixbuf_get_height (job_info->pixbuf) == height) + if (job_info->surface && + cairo_image_surface_get_width (job_info->surface) == width && + cairo_image_surface_get_height (job_info->surface) == height) return; /* make a new job now */ @@ -575,7 +575,7 @@ add_job_if_needed (EvPixbufCache *pixbuf_cache, include_images = TRUE; if (job_info->text_mapping == NULL) include_text = TRUE; - if (new_selection_pixbuf_needed (pixbuf_cache, job_info, page, scale)) { + if (new_selection_surface_needed (pixbuf_cache, job_info, page, scale)) { include_selection = TRUE; } @@ -672,9 +672,9 @@ ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache, ev_pixbuf_cache_add_jobs_if_needed (pixbuf_cache, rotation, scale); } -GdkPixbuf * -ev_pixbuf_cache_get_pixbuf (EvPixbufCache *pixbuf_cache, - gint page) +cairo_surface_t * +ev_pixbuf_cache_get_surface (EvPixbufCache *pixbuf_cache, + gint page) { CacheJobInfo *job_info; @@ -688,7 +688,7 @@ ev_pixbuf_cache_get_pixbuf (EvPixbufCache *pixbuf_cache, copy_job_to_job_info (EV_JOB_RENDER (job_info->job), job_info, pixbuf_cache); } - return job_info->pixbuf; + return job_info->surface; } GList * @@ -733,26 +733,32 @@ ev_pixbuf_cache_get_image_mapping (EvPixbufCache *pixbuf_cache, } static gboolean -new_selection_pixbuf_needed (EvPixbufCache *pixbuf_cache, +new_selection_surface_needed (EvPixbufCache *pixbuf_cache, CacheJobInfo *job_info, gint page, gfloat scale) { EvPageCache *page_cache; - gint width, height; if (job_info->selection) { + gint width, height; + gint selection_width, selection_height; + page_cache = ev_page_cache_get (pixbuf_cache->document); - ev_page_cache_get_size (page_cache, page, job_info->rc->rotation, + ev_page_cache_get_size (page_cache, page, + job_info->rc->rotation, scale, &width, &height); + + selection_width = cairo_image_surface_get_width (job_info->selection); + selection_height = cairo_image_surface_get_height (job_info->selection); - if (width != gdk_pixbuf_get_width (job_info->selection) || - height != gdk_pixbuf_get_height (job_info->selection)) + if (width != selection_width || height != selection_height) return TRUE; } else { if (job_info->points_set) return TRUE; } + return FALSE; } @@ -762,9 +768,9 @@ clear_selection_if_needed (EvPixbufCache *pixbuf_cache, gint page, gfloat scale) { - if (new_selection_pixbuf_needed (pixbuf_cache, job_info, page, scale)) { + if (new_selection_surface_needed (pixbuf_cache, job_info, page, scale)) { if (job_info->selection) - g_object_unref (job_info->selection); + cairo_surface_destroy (job_info->selection); job_info->selection = NULL; job_info->selection_points.x1 = -1; } @@ -818,13 +824,13 @@ ev_pixbuf_cache_style_changed (EvPixbufCache *pixbuf_cache) job_info = pixbuf_cache->prev_job + i; if (job_info->selection) { - g_object_unref (G_OBJECT (job_info->selection)); + cairo_surface_destroy (job_info->selection); job_info->selection = NULL; } job_info = pixbuf_cache->next_job + i; if (job_info->selection) { - g_object_unref (G_OBJECT (job_info->selection)); + cairo_surface_destroy (job_info->selection); job_info->selection = NULL; } } @@ -834,17 +840,17 @@ ev_pixbuf_cache_style_changed (EvPixbufCache *pixbuf_cache) job_info = pixbuf_cache->job_list + i; if (job_info->selection) { - g_object_unref (G_OBJECT (job_info->selection)); + cairo_surface_destroy (job_info->selection); job_info->selection = NULL; } } } -GdkPixbuf * -ev_pixbuf_cache_get_selection_pixbuf (EvPixbufCache *pixbuf_cache, - gint page, - gfloat scale, - GdkRegion **region) +cairo_surface_t * +ev_pixbuf_cache_get_selection_surface (EvPixbufCache *pixbuf_cache, + gint page, + gfloat scale, + GdkRegion **region) { CacheJobInfo *job_info; @@ -932,7 +938,7 @@ clear_job_selection (CacheJobInfo *job_info) job_info->selection_points.x1 = -1; if (job_info->selection) { - g_object_unref (job_info->selection); + cairo_surface_destroy (job_info->selection); job_info->selection = NULL; } } diff --git a/shell/ev-pixbuf-cache.h b/shell/ev-pixbuf-cache.h index 6f96dc18..79e0810a 100644 --- a/shell/ev-pixbuf-cache.h +++ b/shell/ev-pixbuf-cache.h @@ -57,7 +57,7 @@ void ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache gint rotation, gfloat scale, GList *selection_list); -GdkPixbuf *ev_pixbuf_cache_get_pixbuf (EvPixbufCache *pixbuf_cache, +cairo_surface_t *ev_pixbuf_cache_get_surface (EvPixbufCache *pixbuf_cache, gint page); GList *ev_pixbuf_cache_get_link_mapping (EvPixbufCache *pixbuf_cache, gint page); @@ -69,10 +69,10 @@ void ev_pixbuf_cache_clear (EvPixbufCache *pixbuf_cache void ev_pixbuf_cache_style_changed (EvPixbufCache *pixbuf_cache); /* Selection */ -GdkPixbuf *ev_pixbuf_cache_get_selection_pixbuf (EvPixbufCache *pixbuf_cache, - gint page, - gfloat scale, - GdkRegion **region); +cairo_surface_t *ev_pixbuf_cache_get_selection_surface (EvPixbufCache *pixbuf_cache, + gint page, + gfloat scale, + GdkRegion **region); void ev_pixbuf_cache_set_selection_list (EvPixbufCache *pixbuf_cache, GList *selection_list); GList *ev_pixbuf_cache_get_selection_list (EvPixbufCache *pixbuf_cache); diff --git a/shell/ev-view.c b/shell/ev-view.c index bcf3374e..ba69b27c 100644 --- a/shell/ev-view.c +++ b/shell/ev-view.c @@ -2003,6 +2003,9 @@ ev_view_button_press_event (GtkWidget *widget, view->selection_info.in_drag = TRUE; } else { clear_selection (view); + + view->selection_info.start.x = event->x + view->scroll_x; + view->selection_info.start.y = event->y + view->scroll_y; } gtk_widget_queue_draw (widget); @@ -2015,10 +2018,10 @@ ev_view_button_press_event (GtkWidget *widget, view->image_dnd_info.start.x = event->x + view->scroll_x; view->image_dnd_info.start.y = event->y + view->scroll_y; + } else { + view->selection_info.start.x = event->x + view->scroll_x; + view->selection_info.start.y = event->y + view->scroll_y; } - - view->selection_info.start.x = event->x + view->scroll_x; - view->selection_info.start.y = event->y + view->scroll_y; } return TRUE; case 2: @@ -2773,8 +2776,6 @@ highlight_find_results (EvView *view, int page) EvDocumentFind *find; int i, results = 0; - g_return_if_fail (EV_IS_DOCUMENT_FIND (view->document)); - find = EV_DOCUMENT_FIND (view->document); results = ev_document_find_get_n_results (find, page); @@ -2804,7 +2805,7 @@ draw_loading_text (EvView *view, { cairo_t *cr; gint width, height; - + /* Don't annoy users with loading messages during presentations. * FIXME: Temporary "workaround" for * http://bugzilla.gnome.org/show_bug.cgi?id=320352 */ @@ -2812,17 +2813,15 @@ draw_loading_text (EvView *view, return; if (!view->loading_text) { - const gchar *loading_text; + const gchar *loading_text = _("Loading..."); PangoLayout *layout; PangoFontDescription *font_desc; PangoRectangle logical_rect; - gdouble real_scale; gint target_width; - - loading_text = _("Loading..."); + gdouble real_scale; ev_document_fc_mutex_lock (); - + layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), loading_text); font_desc = pango_font_description_new (); @@ -2831,8 +2830,7 @@ draw_loading_text (EvView *view, pango_font_description_set_size (font_desc, 10 * PANGO_SCALE); pango_layout_set_font_description (layout, font_desc); pango_layout_get_pixel_extents (layout, NULL, &logical_rect); - - /* Make sure we fit the middle of the page */ + target_width = MAX (page_area->width / 2, 1); real_scale = ((double)target_width / (double) logical_rect.width) * (PANGO_SCALE * 10); pango_font_description_set_size (font_desc, (int)real_scale); @@ -2860,39 +2858,30 @@ draw_loading_text (EvView *view, height = (page_area->height - cairo_image_surface_get_height (view->loading_text)) / 2; cr = gdk_cairo_create (GTK_WIDGET (view)->window); - cairo_set_source_surface (cr, view->loading_text, - page_area->x + width, - page_area->y + height); + cairo_translate (cr, + page_area->x + width, + page_area->y + height); + cairo_set_source_surface (cr, view->loading_text, 0, 0); cairo_paint (cr); cairo_destroy (cr); } static void -draw_one_page (EvView *view, - gint page, - GdkRectangle *page_area, - GtkBorder *border, - GdkRectangle *expose_area, - gboolean *page_ready) +draw_one_page (EvView *view, + gint page, + GdkRectangle *page_area, + GtkBorder *border, + GdkRectangle *expose_area, + gboolean *page_ready) { - gint width, height; - GdkPixbuf *current_pixbuf; GdkRectangle overlap; GdkRectangle real_page_area; - EvViewSelection *selection; - gint current_page; g_assert (view->document); if (! gdk_rectangle_intersect (page_area, expose_area, &overlap)) return; - - current_page = ev_page_cache_get_current_page (view->page_cache); - selection = find_selection_for_page (view, page); - ev_page_cache_get_size (view->page_cache, - page, view->rotation, - view->scale, - &width, &height); + /* Render the document itself */ real_page_area = *page_area; @@ -2903,80 +2892,100 @@ draw_one_page (EvView *view, *page_ready = TRUE; if (!view->presentation) { - ev_document_misc_paint_one_page (GTK_WIDGET(view)->window, + gint current_page; + + current_page = ev_page_cache_get_current_page (view->page_cache); + ev_document_misc_paint_one_page (GTK_WIDGET (view)->window, GTK_WIDGET (view), page_area, border, page == current_page); } if (gdk_rectangle_intersect (&real_page_area, expose_area, &overlap)) { - GdkPixbuf *selection_pixbuf = NULL; - GdkPixbuf *scaled_image; - GdkPixbuf *scaled_selection; + gint width, height; + gint page_width, page_height; + cairo_surface_t *page_surface = NULL; + gint selection_width, selection_height; + cairo_surface_t *selection_surface = NULL; + cairo_t *cr = NULL; - current_pixbuf = ev_pixbuf_cache_get_pixbuf (view->pixbuf_cache, page); + page_surface = ev_pixbuf_cache_get_surface (view->pixbuf_cache, page); - /* Get the selection pixbuf iff we have something to draw */ - if (current_pixbuf && view->selection_mode == EV_VIEW_SELECTION_TEXT && selection) - selection_pixbuf = ev_pixbuf_cache_get_selection_pixbuf (view->pixbuf_cache, - page, - view->scale, - NULL); - - if (current_pixbuf == NULL) - scaled_image = NULL; - else if (width == gdk_pixbuf_get_width (current_pixbuf) && - height == gdk_pixbuf_get_height (current_pixbuf)) - scaled_image = g_object_ref (current_pixbuf); - else - /* FIXME: We don't want to scale the whole area, just the right - * area of it */ - scaled_image = gdk_pixbuf_scale_simple (current_pixbuf, - width, height, - GDK_INTERP_NEAREST); - - if (selection_pixbuf == NULL) - scaled_selection = NULL; - else if (width == gdk_pixbuf_get_width (selection_pixbuf) && - height == gdk_pixbuf_get_height (selection_pixbuf)) - scaled_selection = g_object_ref (selection_pixbuf); - else - /* FIXME: We don't want to scale the whole area, just the right - * area of it */ - scaled_selection = gdk_pixbuf_scale_simple (selection_pixbuf, - width, height, - GDK_INTERP_NEAREST); - - if (scaled_image) { - gdk_draw_pixbuf (GTK_WIDGET(view)->window, - GTK_WIDGET (view)->style->fg_gc[GTK_STATE_NORMAL], - scaled_image, - overlap.x - real_page_area.x, - overlap.y - real_page_area.y, - overlap.x, overlap.y, - overlap.width, overlap.height, - GDK_RGB_DITHER_NORMAL, - 0, 0); - g_object_unref (scaled_image); - } else { + if (!page_surface) { draw_loading_text (view, &real_page_area, expose_area); *page_ready = FALSE; + + return; + } + + ev_page_cache_get_size (view->page_cache, + page, view->rotation, + view->scale, + &width, &height); + + cr = gdk_cairo_create (GTK_WIDGET (view)->window); + + cairo_save (cr); + + page_width = cairo_image_surface_get_width (page_surface); + page_height = cairo_image_surface_get_height (page_surface); + + cairo_translate (cr, overlap.x, overlap.y); + + if (width != page_width || height != page_height) { + cairo_pattern_set_filter (cairo_get_source (cr), + CAIRO_FILTER_FAST); + cairo_scale (cr, + (gdouble)width / page_width, + (gdouble)height / page_height); } - if (scaled_selection) { - gdk_draw_pixbuf (GTK_WIDGET(view)->window, - GTK_WIDGET (view)->style->fg_gc[GTK_STATE_NORMAL], - scaled_selection, - overlap.x - real_page_area.x, - overlap.y - real_page_area.y, - overlap.x, overlap.y, - overlap.width, overlap.height, - GDK_RGB_DITHER_NORMAL, - 0, 0); - g_object_unref (scaled_selection); + cairo_surface_set_device_offset (page_surface, + overlap.x - real_page_area.x, + overlap.y - real_page_area.y); + + cairo_set_source_surface (cr, page_surface, 0, 0); + cairo_paint (cr); + + cairo_restore (cr); + + /* Get the selection pixbuf iff we have something to draw */ + if (find_selection_for_page (view, page) && + view->selection_mode == EV_VIEW_SELECTION_TEXT) { + selection_surface = + ev_pixbuf_cache_get_selection_surface (view->pixbuf_cache, + page, + view->scale, + NULL); + } + + if (!selection_surface) { + cairo_destroy (cr); + return; } + + selection_width = cairo_image_surface_get_width (selection_surface); + selection_height = cairo_image_surface_get_height (selection_surface); + + cairo_translate (cr, overlap.x, overlap.y); + + if (width != selection_width || height != selection_height) { + cairo_pattern_set_filter (cairo_get_source (cr), + CAIRO_FILTER_FAST); + cairo_scale (cr, + (gdouble)width / selection_width, + (gdouble)height / selection_height); + } + + cairo_surface_set_device_offset (selection_surface, + overlap.x - real_page_area.x, + overlap.y - real_page_area.y); + + cairo_set_source_surface (cr, selection_surface, 0, 0); + cairo_paint (cr); + cairo_destroy (cr); } } @@ -3569,7 +3578,7 @@ ev_view_set_zoom (EvView *view, cairo_surface_destroy (view->loading_text); view->loading_text = NULL; } - + view->scale = scale; view->pending_resize = TRUE; @@ -4453,8 +4462,6 @@ compute_new_selection_text (EvView *view, } - - /* Now create a list of EvViewSelection's for the affected * pages. This could be an empty list, a list of just one * page or a number of pages.*/ @@ -4561,10 +4568,12 @@ merge_selection_region (EvView *view, * region too. */ if (new_sel) { GdkRegion *tmp_region = NULL; - ev_pixbuf_cache_get_selection_pixbuf (view->pixbuf_cache, - cur_page, - view->scale, - &tmp_region); + + ev_pixbuf_cache_get_selection_surface (view->pixbuf_cache, + cur_page, + view->scale, + &tmp_region); + if (tmp_region) { new_sel->covered_region = gdk_region_copy (tmp_region); } @@ -4572,8 +4581,7 @@ merge_selection_region (EvView *view, /* Now we figure out what needs redrawing */ if (old_sel && new_sel) { - if (old_sel->covered_region && - new_sel->covered_region) { + if (old_sel->covered_region && new_sel->covered_region) { /* We only want to redraw the areas that have * changed, so we xor the old and new regions * and redraw if it's different */ @@ -4605,6 +4613,12 @@ merge_selection_region (EvView *view, GdkRectangle page_area; GtkBorder border; + /* I don't know why but the region is smaller + * than expected. This hack fixes it, I guess + * 10 pixels more won't hurt + */ + gdk_region_shrink (region, -5, -5); + get_page_extents (view, cur_page, &page_area, &border); gdk_region_offset (region, page_area.x + border.left - view->scroll_x, -- 2.43.5