From 4e9f8a7b1d77806b627ab8d602dfce38cda17ec0 Mon Sep 17 00:00:00 2001 From: Jeremie Knuesel Date: Wed, 24 Jan 2018 20:49:57 +0100 Subject: [PATCH] HiDPI: refactor handling of device scale factors The document scale factors are now guaranteed to be non-zero. A new Cairo helper function get_safe_device_factors() and a type zathura_device_factors_t are introduced to simplify the code and avoid some #ifdef blocks. --- zathura/callbacks.c | 17 +++++++++-------- zathura/document.c | 36 ++++++++++++++++++++++-------------- zathura/document.h | 11 +++++------ zathura/page-widget.c | 37 ++++++++++++++++++++++++++++--------- zathura/render.c | 33 ++++++++++----------------------- zathura/types.h | 9 +++++++++ zathura/zathura.c | 4 ++-- 7 files changed, 85 insertions(+), 62 deletions(-) diff --git a/zathura/callbacks.c b/zathura/callbacks.c index f82eda0..c7ba706 100644 --- a/zathura/callbacks.c +++ b/zathura/callbacks.c @@ -225,15 +225,16 @@ cb_scale_factor(GObject* object, GParamSpec* UNUSED(pspec), gpointer data) } int new_factor = gtk_widget_get_scale_factor(GTK_WIDGET(object)); + if (new_factor == 0) { + girara_debug("Ignoring new device scale factor = 0"); + return; + } - double current_x; - double current_y; - zathura_document_get_device_scale(zathura->document, ¤t_x, ¤t_y); - - if (new_factor != current_x || new_factor != current_y) { - zathura_document_set_device_scale(zathura->document, new_factor, - new_factor); - girara_debug("New device scale: %d", new_factor); + zathura_device_factors_t current = zathura_document_get_device_factors(zathura->document); + if (fabs(new_factor - current.x) >= DBL_EPSILON || + fabs(new_factor - current.y) >= DBL_EPSILON) { + zathura_document_set_device_factors(zathura->document, new_factor, new_factor); + girara_debug("New device scale factor: %d", new_factor); render_all(zathura); } } diff --git a/zathura/document.c b/zathura/document.c index 055a4d6..bf6539d 100644 --- a/zathura/document.c +++ b/zathura/document.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -36,8 +37,7 @@ struct zathura_document_s { double cell_height; /**< height of a page cell in the document (not ransformed by scale and rotation) */ unsigned int view_width; /**< width of current viewport */ unsigned int view_height; /**< height of current viewport */ - double device_scale_x; /**< x scale factor (for e.g. HiDPI) */ - double device_scale_y; /**< y scale factor (for e.g. HiDPI) */ + zathura_device_factors_t device_factors; /**< x and y device scale factors (for e.g. HiDPI) */ unsigned int pages_per_row; /**< number of pages in a row */ unsigned int first_page_column; /**< column of the first page */ unsigned int page_padding; /**< padding between pages */ @@ -134,8 +134,8 @@ zathura_document_open(zathura_t* zathura, const char* path, const char* uri, document->cell_height = 0.0; document->view_height = 0; document->view_width = 0; - document->device_scale_x = 0.0; - document->device_scale_y = 0.0; + document->device_factors.x = 1.0; + document->device_factors.y = 1.0; document->position_x = 0.0; document->position_y = 0.0; @@ -505,23 +505,31 @@ zathura_document_get_viewport_size(zathura_document_t* document, } void -zathura_document_set_device_scale(zathura_document_t* document, - double x_factor, double y_factor) +zathura_document_set_device_factors(zathura_document_t* document, + double x_factor, double y_factor) { if (document == NULL) { return; } - document->device_scale_x = x_factor; - document->device_scale_y = y_factor; + if (fabs(x_factor) < DBL_EPSILON || fabs(y_factor) < DBL_EPSILON) { + girara_debug("Ignoring new device factors %f and %f: too small", + x_factor, y_factor); + return; + } + + document->device_factors.x = x_factor; + document->device_factors.y = y_factor; } -void -zathura_document_get_device_scale(zathura_document_t* document, - double *x_factor, double* y_factor) +zathura_device_factors_t +zathura_document_get_device_factors(zathura_document_t* document) { - g_return_if_fail(document != NULL && x_factor != NULL && y_factor != NULL); - *x_factor = document->device_scale_x; - *y_factor = document->device_scale_y; + if (document == NULL) { + /* The function is guaranteed to not return zero values */ + return (zathura_device_factors_t){1.0, 1.0}; + } + + return document->device_factors; } void diff --git a/zathura/document.h b/zathura/document.h index b49e865..a993411 100644 --- a/zathura/document.h +++ b/zathura/document.h @@ -257,16 +257,15 @@ zathura_document_get_viewport_size(zathura_document_t* document, * @param[in] x_factor,yfactor The x and y scale factors */ void -zathura_document_set_device_scale(zathura_document_t* document, +zathura_document_set_device_factors(zathura_document_t* document, double x_factor, double y_factor); /** - * Return the current device scale factors. + * Return the current device scale factors (guaranteed to be non-zero). * - * @param[out] x_factor,yfactor The x and y scale factors + * @return The x and y device scale factors */ -void -zathura_document_get_device_scale(zathura_document_t* document, - double *x_factor, double* y_factor); +zathura_device_factors_t +zathura_document_get_device_factors(zathura_document_t* document); /** * Return the size of a cell from the document's layout table in pixels. Assumes diff --git a/zathura/page-widget.c b/zathura/page-widget.c index 765181e..3e5875f 100644 --- a/zathura/page-widget.c +++ b/zathura/page-widget.c @@ -409,6 +409,30 @@ zathura_page_widget_get_property(GObject* object, guint prop_id, GValue* value, } } +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,14,0) +static zathura_device_factors_t +get_safe_device_factors(cairo_surface_t* surface) +{ + zathura_device_factors_t factors; + cairo_surface_get_device_scale(surface, &factors.x, &factors.y); + + if (fabs(factors.x) < DBL_EPSILON) { + factors.x = 1.0; + } + if (fabs(factors.y) < DBL_EPSILON) { + factors.y = 1.0; + } + + return factors; +} +#else +static zathura_device_factors_t +get_safe_device_factors(cairo_surface_t* UNUSED(surface)) +{ + return (zathura_device_factors_t){1.0, 1.0}; +} +#endif + static gboolean zathura_page_widget_draw(GtkWidget* widget, cairo_t* cairo) { @@ -448,15 +472,10 @@ zathura_page_widget_draw(GtkWidget* widget, cairo_t* cairo) unsigned int pheight = (rotation % 180 ? page_width : page_height); unsigned int pwidth = (rotation % 180 ? page_height : page_width); -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,14,0) - double device_scale_x; - double device_scale_y; - cairo_surface_get_device_scale(priv->thumbnail, &device_scale_x, &device_scale_y); - if (fabs(device_scale_x) >= DBL_EPSILON && fabs(device_scale_y) >= DBL_EPSILON) { - pwidth *= device_scale_x; - pheight *= device_scale_y; - } -#endif + /* note: this always returns 1 and 1 if Cairo too old for device scale API */ + zathura_device_factors_t device = get_safe_device_factors(priv->thumbnail); + pwidth *= device.x; + pheight *= device.y; cairo_scale(cairo, pwidth / (double)width, pheight / (double)height); cairo_set_source_surface(cairo, priv->thumbnail, 0, 0); diff --git a/zathura/render.c b/zathura/render.c index a420d78..7cd3f3e 100644 --- a/zathura/render.c +++ b/zathura/render.c @@ -732,26 +732,20 @@ render(render_job_t* job, ZathuraRenderRequest* request, ZathuraRenderer* render unsigned int page_width = 0; unsigned int page_height = 0; + /* page size in points */ zathura_document_t* document = zathura_page_get_document(page); const double height = zathura_page_get_height(page); const double width = zathura_page_get_width(page); + /* page size in user pixels base on document zoom: 100% results in 1 pixel per point */ const double real_scale = page_calc_height_width(document, height, width, &page_height, &page_width, false); #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,14,0) - double device_scale_x; - double device_scale_y; - zathura_document_get_device_scale(document, &device_scale_x, &device_scale_y); - - gboolean scales_nonzero = (fabs(device_scale_x) >= DBL_EPSILON && - fabs(device_scale_y) >= DBL_EPSILON); - - if (scales_nonzero) { - page_width *= device_scale_x; - page_height *= device_scale_y; - } + zathura_device_factors_t device_factors = zathura_document_get_device_factors(document); + page_width *= device_factors.x; + page_height *= device_factors.y; #endif cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, @@ -759,21 +753,14 @@ render(render_job_t* job, ZathuraRenderRequest* request, ZathuraRenderer* render if (surface == NULL) { return false; } +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,14,0) + cairo_surface_set_device_scale(surface, device_factors.x, device_factors.y); +#endif if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { cairo_surface_destroy(surface); return false; } -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,14,0) - if (scales_nonzero) { - cairo_surface_set_device_scale(surface, device_scale_x, device_scale_y); - if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { - cairo_surface_destroy(surface); - return false; - } - } -#endif - cairo_t* cairo = cairo_create(surface); if (cairo == NULL) { cairo_surface_destroy(surface); @@ -782,11 +769,11 @@ render(render_job_t* job, ZathuraRenderRequest* request, ZathuraRenderer* render cairo_save(cairo); cairo_set_source_rgb(cairo, 1, 1, 1); - cairo_rectangle(cairo, 0, 0, page_width, page_height); - cairo_fill(cairo); + cairo_paint(cairo); cairo_restore(cairo); cairo_save(cairo); + /* apply scale (used by e.g. Poppler as pixels per point) */ if (fabs(real_scale - 1.0f) > FLT_EPSILON) { cairo_scale(cairo, real_scale, real_scale); } diff --git a/zathura/types.h b/zathura/types.h index e0028d7..0cf1f9b 100644 --- a/zathura/types.h +++ b/zathura/types.h @@ -271,4 +271,13 @@ void zathura_document_information_entry_free(zathura_document_information_entry_ */ typedef struct zathura_content_type_context_s zathura_content_type_context_t; +/** + * Device scaling structure. + */ +typedef struct zathura_device_factors_s +{ + double x; + double y; +} zathura_device_factors_t; + #endif // TYPES_H diff --git a/zathura/zathura.c b/zathura/zathura.c index 2d9a5d6..a435390 100644 --- a/zathura/zathura.c +++ b/zathura/zathura.c @@ -960,8 +960,8 @@ document_open(zathura_t* zathura, const char* path, const char* uri, const char* zathura_document_set_viewport_height(zathura->document, view_height); /* get initial device scale */ - int device_scale = gtk_widget_get_scale_factor(zathura->ui.session->gtk.view); - zathura_document_set_device_scale(zathura->document, device_scale, device_scale); + int device_factor = gtk_widget_get_scale_factor(zathura->ui.session->gtk.view); + zathura_document_set_device_factors(zathura->document, device_factor, device_factor); /* create blank pages */ zathura->pages = calloc(number_of_pages, sizeof(GtkWidget*));