[evince] EvView: render correctly on hi-dpi displays



commit a612f809e4e23d88a661a9604ce84f332189a658
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Thu Feb 27 19:20:17 2014 -0500

    EvView: render correctly on hi-dpi displays
    
    Make EvPixbufCache generate surfaces with extra resolution based on
    gtk_widget_get_scale_factor(). Handle cairo surfaces with a device
    scale in ev_view_draw(). Trigger an update of the pixbuf cache when
    the scale factor changes.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=723431

 libview/ev-pixbuf-cache.c |   71 ++++++++++++++++++++++++++++++++++-----------
 libview/ev-view.c         |   35 ++++++++++++++++++----
 2 files changed, 83 insertions(+), 23 deletions(-)
---
diff --git a/libview/ev-pixbuf-cache.c b/libview/ev-pixbuf-cache.c
index 4d0f876..0f4403e 100644
--- a/libview/ev-pixbuf-cache.c
+++ b/libview/ev-pixbuf-cache.c
@@ -19,6 +19,9 @@ typedef struct _CacheJobInfo
        /* Data we get from rendering */
        cairo_surface_t *surface;
 
+       /* Device scale factor of target widget */
+       int device_scale;
+
        /* Selection data. 
         * Selection_points are the coordinates encapsulated in selection.
         * target_points is the target selection size. */
@@ -245,6 +248,27 @@ ev_pixbuf_cache_set_max_size (EvPixbufCache *pixbuf_cache,
        pixbuf_cache->max_size = max_size;
 }
 
+static int
+get_device_scale (EvPixbufCache *pixbuf_cache)
+{
+#ifdef HAVE_HIDPI_SUPPORT
+        return gtk_widget_get_scale_factor (pixbuf_cache->view);
+#else
+        return 1;
+#endif
+}
+
+static void
+set_device_scale_on_surface (cairo_surface_t *surface,
+                             int              device_scale)
+{
+#ifdef HAVE_HIDPI_SUPPORT
+        cairo_surface_set_device_scale (surface, device_scale, device_scale);
+#else
+        g_return_if_fail (device_scale != 1);
+#endif
+}
+
 static void
 copy_job_to_job_info (EvJobRender   *job_render,
                      CacheJobInfo  *job_info,
@@ -254,6 +278,7 @@ copy_job_to_job_info (EvJobRender   *job_render,
                cairo_surface_destroy (job_info->surface);
        }
        job_info->surface = cairo_surface_reference (job_render->surface);
+       set_device_scale_on_surface (job_info->surface, job_info->device_scale);
        if (pixbuf_cache->inverted_colors) {
                ev_document_misc_invert_surface (job_info->surface);
        }
@@ -271,7 +296,8 @@ copy_job_to_job_info (EvJobRender   *job_render,
 
                job_info->selection_points = job_render->selection_points;
                job_info->selection = cairo_surface_reference (job_render->selection);
-               job_info->selection_scale = job_render->scale;
+               set_device_scale_on_surface (job_info->selection, job_info->device_scale);
+               job_info->selection_scale = job_render->scale * job_info->device_scale;
                g_assert (job_info->selection_points.x1 >= 0);
 
                job_info->selection_region_points = job_render->selection_points;
@@ -322,20 +348,24 @@ check_job_size_and_unref (EvPixbufCache *pixbuf_cache,
                          gfloat         scale)
 {
        gint width, height;
+       gint device_scale;
 
        g_assert (job_info);
 
        if (job_info->job == NULL)
                return;
 
-       _get_page_size_for_scale_and_rotation (job_info->job->document,
-                                              EV_JOB_RENDER (job_info->job)->page,
-                                              scale,
-                                              EV_JOB_RENDER (job_info->job)->rotation,
-                                              &width, &height);
-       if (width == EV_JOB_RENDER (job_info->job)->target_width &&
-           height == EV_JOB_RENDER (job_info->job)->target_height)
-               return;
+        device_scale = get_device_scale (pixbuf_cache);
+       if (job_info->device_scale == device_scale) {
+               _get_page_size_for_scale_and_rotation (job_info->job->document,
+                                                      EV_JOB_RENDER (job_info->job)->page,
+                                                      scale,
+                                                      EV_JOB_RENDER (job_info->job)->rotation,
+                                                      &width, &height);
+               if (width * device_scale == EV_JOB_RENDER (job_info->job)->target_width &&
+                   height * device_scale == EV_JOB_RENDER (job_info->job)->target_height)
+                       return;
+       }
 
        g_signal_handlers_disconnect_by_func (job_info->job,
                                              G_CALLBACK (job_finished_cb),
@@ -645,6 +675,7 @@ add_job (EvPixbufCache  *pixbuf_cache,
         gfloat          scale,
         EvJobPriority   priority)
 {
+       job_info->device_scale = get_device_scale (pixbuf_cache);
        job_info->page_ready = FALSE;
 
        if (job_info->region)
@@ -652,8 +683,10 @@ add_job (EvPixbufCache  *pixbuf_cache,
        job_info->region = region ? cairo_region_reference (region) : NULL;
 
        job_info->job = ev_job_render_new (pixbuf_cache->document,
-                                           page, rotation, 0.,
-                                          width, height);
+                                          page, rotation,
+                                           scale * job_info->device_scale,
+                                          width * job_info->device_scale,
+                                           height * job_info->device_scale);
 
        if (new_selection_surface_needed (pixbuf_cache, job_info, page, scale)) {
                GdkColor text, base;
@@ -679,6 +712,7 @@ add_job_if_needed (EvPixbufCache *pixbuf_cache,
                   gfloat         scale,
                   EvJobPriority  priority)
 {
+       gint device_scale = get_device_scale (pixbuf_cache);
        gint width, height;
 
        if (job_info->job)
@@ -689,8 +723,9 @@ add_job_if_needed (EvPixbufCache *pixbuf_cache,
                                               &width, &height);
 
        if (job_info->surface &&
-           cairo_image_surface_get_width (job_info->surface) == width &&
-           cairo_image_surface_get_height (job_info->surface) == height)
+           job_info->device_scale == device_scale &&
+           cairo_image_surface_get_width (job_info->surface) == width * device_scale &&
+           cairo_image_surface_get_height (job_info->surface) == height * device_scale)
                return;
 
        /* Free old surfaces for non visible pages */
@@ -1046,10 +1081,11 @@ ev_pixbuf_cache_get_selection_surface (EvPixbufCache   *pixbuf_cache,
 
                ev_page = ev_document_get_page (pixbuf_cache->document, page);
                 _get_page_size_for_scale_and_rotation (pixbuf_cache->document,
-                                                       page, scale, 0,
-                                                       &width, &height);
+                                                       page,
+                                                      scale * job_info->device_scale,
+                                                      0, &width, &height);
 
-                rc = ev_render_context_new (ev_page, 0, 0.);
+               rc = ev_render_context_new (ev_page, 0, scale * job_info->device_scale);
                 ev_render_context_set_target_size (rc, width, height);
                g_object_unref (ev_page);
 
@@ -1060,8 +1096,9 @@ ev_pixbuf_cache_get_selection_surface (EvPixbufCache   *pixbuf_cache,
                                               old_points,
                                               job_info->selection_style,
                                               &text, &base);
+               set_device_scale_on_surface (job_info->selection, job_info->device_scale);
                job_info->selection_points = job_info->target_points;
-               job_info->selection_scale = scale;
+               job_info->selection_scale = scale * job_info->device_scale;
                g_object_unref (rc);
                ev_document_doc_mutex_unlock ();
        }
diff --git a/libview/ev-view.c b/libview/ev-view.c
index 51ecd3a..26700d5 100644
--- a/libview/ev-view.c
+++ b/libview/ev-view.c
@@ -205,7 +205,6 @@ static void       ev_view_page_changed_cb                    (EvDocumentModel
                                                              EvView             *view);
 static void       on_adjustment_value_changed                (GtkAdjustment      *adjustment,
                                                              EvView             *view);
-
 /*** GObject ***/
 static void       ev_view_finalize                           (GObject            *object);
 static void       ev_view_dispose                            (GObject            *object);
@@ -6008,10 +6007,14 @@ draw_surface (cairo_t         *cr,
              gint             target_width,
              gint             target_height)
 {
-       gint width, height;
+       gdouble width, height;
+       gdouble device_scale_x = 1, device_scale_y = 1;
 
-       width = cairo_image_surface_get_width (surface);
-       height = cairo_image_surface_get_height (surface);
+#ifdef HAVE_HIDPI_SUPPORT
+       cairo_surface_get_device_scale (surface, &device_scale_x, &device_scale_y);
+#endif
+       width = cairo_image_surface_get_width (surface) / device_scale_x;
+       height = cairo_image_surface_get_height (surface) / device_scale_y;
 
        cairo_save (cr);
        cairo_translate (cr, x, y);
@@ -6030,8 +6033,8 @@ draw_surface (cairo_t           *cr,
        }
 
        cairo_surface_set_device_offset (surface,
-                                        offset_x,
-                                        offset_y);
+                                        offset_x * device_scale_x,
+                                        offset_y * device_scale_y);
        cairo_set_source_surface (cr, surface, 0, 0);
        cairo_paint (cr);
        cairo_restore (cr);
@@ -6165,9 +6168,18 @@ draw_one_page (EvView       *view,
                if (region) {
                        double scale_x, scale_y;
                        GdkRGBA color;
+                       double device_scale_x = 1, device_scale_y = 1;
 
                        scale_x = (gdouble)width / cairo_image_surface_get_width (page_surface);
                        scale_y = (gdouble)height / cairo_image_surface_get_height (page_surface);
+
+#ifdef HAVE_HIDPI_SUPPORT
+                       cairo_surface_get_device_scale (page_surface, &device_scale_x, &device_scale_y);
+#endif
+
+                       scale_x *= device_scale_x;
+                       scale_y *= device_scale_y;
+
                        _ev_view_get_selection_colors (view, &color, NULL);
                        draw_selection_region (cr, region, &color, real_page_area.x, real_page_area.y,
                                               scale_x, scale_y);
@@ -6868,6 +6880,14 @@ ev_view_class_init (EvViewClass *class)
 }
 
 static void
+on_notify_scale_factor (EvView     *view,
+                       GParamSpec *pspec)
+{
+       if (view->document)
+               view_update_range_and_current_page (view);
+}
+
+static void
 ev_view_init (EvView *view)
 {
        GtkStyleContext *context;
@@ -6916,6 +6936,9 @@ ev_view_init (EvView *view)
        view->pixbuf_cache_size = DEFAULT_PIXBUF_CACHE_SIZE;
        view->caret_enabled = FALSE;
        view->cursor_page = 0;
+
+       g_signal_connect (view, "notify::scale-factor",
+                         G_CALLBACK (on_notify_scale_factor), NULL);
 }
 
 /*** Callbacks ***/


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