From b6a20b77926727af99b39773ee104ffa457c604f Mon Sep 17 00:00:00 2001 From: Matthew Petroff Date: Tue, 18 Oct 2016 15:10:13 -0400 Subject: Add hi-dpi support for main view. Based on Evince commits 8b965e769808815df9c75a10a0e4972c0904d26a and a612f809e4e23d88a661a9604ce84f332189a658. https://github.com/linuxmint/xreader/commit/4eccf6b --- configure.ac | 17 +++++++++++++ libview/ev-pixbuf-cache.c | 64 ++++++++++++++++++++++++++++++++++++----------- libview/ev-view.c | 32 ++++++++++++++++++------ 3 files changed, 91 insertions(+), 22 deletions(-) diff --git a/configure.ac b/configure.ac index b0d22d03..55149721 100644 --- a/configure.ac +++ b/configure.ac @@ -123,6 +123,23 @@ PKG_CHECK_MODULES(GMODULE, gmodule-2.0 >= $GLIB_REQUIRED) PKG_CHECK_MODULES([SHELL_CORE],[libxml-2.0 >= $LIBXML_REQUIRED gtk+-3.0 >= $GTK_REQUIRED gio-2.0 >= $GLIB_REQUIRED gthread-2.0 x11]) +# Although GTK+ 3.10 includes hi-dpi functionality, it does not require a cairo with +# cairo_surface_set_device_scale(), which we also need if we're to support hi-dpi, +# so we need check for that explicity. + +atril_save_LIBS=$LIBS +LIBS="$LIBS $LIBVIEW_LIBS" +AC_CHECK_FUNCS(cairo_surface_set_device_scale) +LIBS=$atril_save_LIBS + +AC_MSG_CHECKING([for hi-dpi support]) +if test "$ac_cv_func_cairo_surface_set_device_scale" = yes ; then + AC_DEFINE([HAVE_HIDPI_SUPPORT], [1], [Define if cairo and GTK+ have necessary functions for hi-dpi]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + dnl dnl zlib support dnl diff --git a/libview/ev-pixbuf-cache.c b/libview/ev-pixbuf-cache.c index 409b9c39..506d1316 100644 --- a/libview/ev-pixbuf-cache.c +++ b/libview/ev-pixbuf-cache.c @@ -14,6 +14,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. */ @@ -235,6 +238,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, @@ -244,6 +268,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); } @@ -262,6 +287,7 @@ copy_job_to_job_info (EvJobRender *job_render, job_info->selection_points = job_render->selection_points; job_info->selection_region = cairo_region_reference (job_render->selection_region); job_info->selection = cairo_surface_reference (job_render->selection); + set_device_scale_on_surface (job_info->selection, job_info->device_scale); g_assert (job_info->selection_points.x1 >= 0); job_info->points_set = TRUE; } @@ -307,20 +333,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), @@ -634,6 +664,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) @@ -641,8 +672,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, scale, - 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; @@ -667,6 +700,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) @@ -677,8 +711,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 */ @@ -949,7 +984,7 @@ ev_pixbuf_cache_get_selection_surface (EvPixbufCache *pixbuf_cache, /* Now, lets see if we need to resize the image. If we do, we clear the * old one. */ - clear_selection_if_needed (pixbuf_cache, job_info, page, scale); + clear_selection_if_needed (pixbuf_cache, job_info, page, scale * job_info->device_scale); /* Finally, we see if the two scales are the same, and get a new pixbuf * if needed. We do this synchronously for now. At some point, we @@ -973,7 +1008,7 @@ ev_pixbuf_cache_get_selection_surface (EvPixbufCache *pixbuf_cache, } ev_page = ev_document_get_page (pixbuf_cache->document, page); - rc = ev_render_context_new (ev_page, 0, scale); + rc = ev_render_context_new (ev_page, 0, scale * job_info->device_scale); g_object_unref (ev_page); if (job_info->selection_region) @@ -991,6 +1026,7 @@ 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; g_object_unref (rc); ev_document_doc_mutex_unlock (); diff --git a/libview/ev-view.c b/libview/ev-view.c index 0e84a1e4..86eef350 100644 --- a/libview/ev-view.c +++ b/libview/ev-view.c @@ -4467,6 +4467,7 @@ draw_one_page (EvView *view, cairo_surface_t *page_surface = NULL; gint selection_width, selection_height; cairo_surface_t *selection_surface = NULL; + double device_scale_x = 1, device_scale_y = 1; page_surface = ev_pixbuf_cache_get_surface (view->pixbuf_cache, page); @@ -4479,6 +4480,10 @@ draw_one_page (EvView *view, return; } +#ifdef HAVE_HIDPI_SUPPORT + cairo_surface_get_device_scale (page_surface, &device_scale_x, &device_scale_y); +#endif + if (page == current_page) hide_loading_window (view); @@ -4494,13 +4499,13 @@ draw_one_page (EvView *view, cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_FAST); cairo_scale (cr, - (gdouble)width / page_width, - (gdouble)height / page_height); + (gdouble)width / page_width * device_scale_x, + (gdouble)height / page_height * device_scale_y); } cairo_surface_set_device_offset (page_surface, - overlap.x - real_page_area.x, - overlap.y - real_page_area.y); + (overlap.x - real_page_area.x) * device_scale_x, + (overlap.y - real_page_area.y) * device_scale_y); cairo_set_source_surface (cr, page_surface, 0, 0); cairo_paint (cr); cairo_restore (cr); @@ -4529,13 +4534,13 @@ draw_one_page (EvView *view, cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_FAST); cairo_scale (cr, - (gdouble)width / selection_width, - (gdouble)height / selection_height); + (gdouble)width / selection_width * device_scale_x, + (gdouble)height / selection_height * device_scale_y); } cairo_surface_set_device_offset (selection_surface, - overlap.x - real_page_area.x, - overlap.y - real_page_area.y); + (overlap.x - real_page_area.x) * device_scale_x, + (overlap.y - real_page_area.y) * device_scale_y); cairo_set_source_surface (cr, selection_surface, 0, 0); cairo_paint (cr); @@ -4876,6 +4881,14 @@ ev_view_class_init (EvViewClass *class) GTK_SCROLL_STEP_FORWARD, G_TYPE_BOOLEAN, TRUE); } +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) { @@ -4922,6 +4935,9 @@ ev_view_init (EvView *view) view->pending_scroll = SCROLL_TO_KEEP_POSITION; view->jump_to_find_result = TRUE; view->highlight_find_results = FALSE; + + g_signal_connect (view, "notify::scale-factor", + G_CALLBACK (on_notify_scale_factor), NULL); } /*** Callbacks ***/ -- cgit v1.2.1