From b5d0b28bb9a061740edd9640d9f8f87163b20b44 Mon Sep 17 00:00:00 2001 From: Jeremie Knuesel Date: Mon, 22 Jan 2018 22:51:36 +0100 Subject: [PATCH 01/10] Implement support for HiDPI displays --- zathura/callbacks.c | 22 ++++++++++++++++++++++ zathura/callbacks.h | 15 +++++++++++++++ zathura/document.c | 24 ++++++++++++++++++++++++ zathura/document.h | 19 +++++++++++++++++++ zathura/render.c | 16 ++++++++++++++++ zathura/zathura.c | 3 +++ 6 files changed, 99 insertions(+) diff --git a/zathura/callbacks.c b/zathura/callbacks.c index 7db22f8..c768195 100644 --- a/zathura/callbacks.c +++ b/zathura/callbacks.c @@ -216,6 +216,28 @@ cb_refresh_view(GtkWidget* GIRARA_UNUSED(view), gpointer data) statusbar_page_number_update(zathura); } +gboolean +cb_window_configure(GtkWidget* widget, GdkEventConfigure* UNUSED(configure), zathura_t* zathura) +{ + if (widget == NULL || zathura == NULL || zathura->document == NULL) { + return false; + } + + int new_factor = gtk_widget_get_scale_factor(widget); + + 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); + render_all(zathura); + } + + return false; +} + void cb_page_layout_value_changed(girara_session_t* session, const char* name, girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data)) { diff --git a/zathura/callbacks.h b/zathura/callbacks.h index 15e4ba1..8ef65b8 100644 --- a/zathura/callbacks.h +++ b/zathura/callbacks.h @@ -79,6 +79,21 @@ void cb_view_vadjustment_changed(GtkAdjustment *adjustment, gpointer data); */ void cb_refresh_view(GtkWidget* view, gpointer data); +/** + * This function gets called when the main window is reconfigured, i.e. when + * its size, position or stacking order has changed, or when the device scale + * factor has changed (e.g. when moving from a regular to a HiDPI screen). + * + * It checks if the device scale factor has changed and if yes, records the new + * value and triggers a re-rendering of the document. + * + * @param widget The main window GtkWidget + * @param configure The GDK configure event + * @param zathura The zathura instance + */ +gboolean cb_window_configure(GtkWidget* widget, GdkEventConfigure* configure, + zathura_t* zathura); + /** * This function gets called when the value of the "pages-per-row" * variable changes diff --git a/zathura/document.c b/zathura/document.c index cddb00d..055a4d6 100644 --- a/zathura/document.c +++ b/zathura/document.c @@ -36,6 +36,8 @@ 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) */ 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 */ @@ -132,6 +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->position_x = 0.0; document->position_y = 0.0; @@ -500,6 +504,26 @@ zathura_document_get_viewport_size(zathura_document_t* document, *width = document->view_width; } +void +zathura_document_set_device_scale(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; +} + +void +zathura_document_get_device_scale(zathura_document_t* document, + double *x_factor, double* y_factor) +{ + g_return_if_fail(document != NULL && x_factor != NULL && y_factor != NULL); + *x_factor = document->device_scale_x; + *y_factor = document->device_scale_y; +} + void zathura_document_get_cell_size(zathura_document_t* document, unsigned int* height, unsigned int* width) diff --git a/zathura/document.h b/zathura/document.h index 3118f30..b49e865 100644 --- a/zathura/document.h +++ b/zathura/document.h @@ -249,6 +249,25 @@ void zathura_document_get_viewport_size(zathura_document_t* document, unsigned int *height, unsigned int* width); +/** + * Set the device scale factors (e.g. for HiDPI). These are generally integers + * and equal for x and y. These scaling factors are only used when rendering to + * the screen. + * + * @param[in] x_factor,yfactor The x and y scale factors + */ +void +zathura_document_set_device_scale(zathura_document_t* document, + double x_factor, double y_factor); +/** + * Return the current device scale factors. + * + * @param[out] x_factor,yfactor The x and y scale factors + */ +void +zathura_document_get_device_scale(zathura_document_t* document, + double *x_factor, double* y_factor); + /** * Return the size of a cell from the document's layout table in pixels. Assumes * that the table is homogeneous (i.e. every cell has the same dimensions). It diff --git a/zathura/render.c b/zathura/render.c index 51967a8..727d357 100644 --- a/zathura/render.c +++ b/zathura/render.c @@ -740,6 +740,14 @@ render(render_job_t* job, ZathuraRenderRequest* request, ZathuraRenderer* render &page_height, &page_width, false); + double device_scale_x; + double device_scale_y; + zathura_document_get_device_scale(document, &device_scale_x, &device_scale_y); + + if (device_scale_x != 0.0 && device_scale_y != 0.0) { + page_width *= device_scale_x; + page_height *= device_scale_y; + } cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, page_width, page_height); @@ -751,6 +759,14 @@ render(render_job_t* job, ZathuraRenderRequest* request, ZathuraRenderer* render return false; } + if (device_scale_x != 0.0 && device_scale_y != 0.0) { + 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; + } + } + cairo_t* cairo = cairo_create(surface); if (cairo == NULL) { cairo_surface_destroy(surface); diff --git a/zathura/zathura.c b/zathura/zathura.c index 938aed3..250dcaa 100644 --- a/zathura/zathura.c +++ b/zathura/zathura.c @@ -153,6 +153,9 @@ init_ui(zathura_t* zathura) g_signal_connect(G_OBJECT(zathura->ui.session->gtk.view), "refresh-view", G_CALLBACK(cb_refresh_view), zathura); + g_signal_connect(G_OBJECT(zathura->ui.session->gtk.window), "configure-event", + G_CALLBACK(cb_window_configure), zathura); + /* page view */ zathura->ui.page_widget = gtk_grid_new(); gtk_grid_set_row_homogeneous(GTK_GRID(zathura->ui.page_widget), TRUE); From 5fa4b8907e3df4643481641227f78c68bfcb798d Mon Sep 17 00:00:00 2001 From: Jeremie Knuesel Date: Tue, 23 Jan 2018 09:17:01 +0100 Subject: [PATCH 02/10] HiDPI: watch GtkWidget scale-factor property The scale-factor property is more specific than the GDK configure event and is the recommended way to watch for scale factor changes. --- zathura/callbacks.c | 11 +++++------ zathura/callbacks.h | 15 ++++++--------- zathura/zathura.c | 8 ++++++-- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/zathura/callbacks.c b/zathura/callbacks.c index c768195..4c4728d 100644 --- a/zathura/callbacks.c +++ b/zathura/callbacks.c @@ -216,11 +216,11 @@ cb_refresh_view(GtkWidget* GIRARA_UNUSED(view), gpointer data) statusbar_page_number_update(zathura); } -gboolean -cb_window_configure(GtkWidget* widget, GdkEventConfigure* UNUSED(configure), zathura_t* zathura) +void +cb_scale_factor(GtkWidget* widget, GParamSpec* UNUSED(pspec), zathura_t* zathura) { if (widget == NULL || zathura == NULL || zathura->document == NULL) { - return false; + return; } int new_factor = gtk_widget_get_scale_factor(widget); @@ -230,12 +230,11 @@ cb_window_configure(GtkWidget* widget, GdkEventConfigure* UNUSED(configure), zat 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); + zathura_document_set_device_scale(zathura->document, new_factor, + new_factor); girara_debug("New device scale: %d", new_factor); render_all(zathura); } - - return false; } void diff --git a/zathura/callbacks.h b/zathura/callbacks.h index 8ef65b8..2be79b0 100644 --- a/zathura/callbacks.h +++ b/zathura/callbacks.h @@ -80,19 +80,16 @@ void cb_view_vadjustment_changed(GtkAdjustment *adjustment, gpointer data); void cb_refresh_view(GtkWidget* view, gpointer data); /** - * This function gets called when the main window is reconfigured, i.e. when - * its size, position or stacking order has changed, or when the device scale - * factor has changed (e.g. when moving from a regular to a HiDPI screen). + * This function gets called when the view widget scale factor changes (e.g. + * when moving from a regular to a HiDPI screen). * - * It checks if the device scale factor has changed and if yes, records the new - * value and triggers a re-rendering of the document. + * It records the new value and triggers a re-rendering of the document. * - * @param widget The main window GtkWidget - * @param configure The GDK configure event + * @param widget The view widget + * @param pspec The GParamSpec for the scale-factor property * @param zathura The zathura instance */ -gboolean cb_window_configure(GtkWidget* widget, GdkEventConfigure* configure, - zathura_t* zathura); +void cb_scale_factor(GtkWidget* widget, GParamSpec *pspec, zathura_t* zathura); /** * This function gets called when the value of the "pages-per-row" diff --git a/zathura/zathura.c b/zathura/zathura.c index 250dcaa..2d9a5d6 100644 --- a/zathura/zathura.c +++ b/zathura/zathura.c @@ -153,8 +153,8 @@ init_ui(zathura_t* zathura) g_signal_connect(G_OBJECT(zathura->ui.session->gtk.view), "refresh-view", G_CALLBACK(cb_refresh_view), zathura); - g_signal_connect(G_OBJECT(zathura->ui.session->gtk.window), "configure-event", - G_CALLBACK(cb_window_configure), zathura); + g_signal_connect(G_OBJECT(zathura->ui.session->gtk.view), + "notify::scale-factor", G_CALLBACK(cb_scale_factor), zathura); /* page view */ zathura->ui.page_widget = gtk_grid_new(); @@ -959,6 +959,10 @@ document_open(zathura_t* zathura, const char* path, const char* uri, const char* const unsigned int view_height = (unsigned int)floor(gtk_adjustment_get_page_size(vadjustment)); 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); + /* create blank pages */ zathura->pages = calloc(number_of_pages, sizeof(GtkWidget*)); if (zathura->pages == NULL) { From 36d9ece978b012d6515c0d51e7c6ae9190b74827 Mon Sep 17 00:00:00 2001 From: Jeremie Knuesel Date: Tue, 23 Jan 2018 09:34:22 +0100 Subject: [PATCH 03/10] HiDPI: add preprocessor conditionals --- config.mk | 9 +++++++++ zathura/callbacks.c | 4 ++++ zathura/render.c | 4 ++++ zathura/zathura.c | 2 ++ 4 files changed, 19 insertions(+) diff --git a/config.mk b/config.mk index 7a488cf..9d957bb 100644 --- a/config.mk +++ b/config.mk @@ -47,6 +47,15 @@ WITH_SYNCTEX ?= $(shell (${PKG_CONFIG} synctex && echo 1) || echo 0) # To disable support for mimetype detction with libmagic set WITH_MAGIC to 0. WITH_MAGIC ?= 1 +# HiDPI +HIDPI_SUPPORT_CAIRO = $(shell (${PKG_CONFIG} --atleast-version=1.14 cairo && echo 1) || echo 0) +HIDPI_SUPPORT_GTK = $(shell (${PKG_CONFIG} --atleast-version=3.10 ${GTK_PKG_CONFIG_NAME} && echo 1) || echo 0) +ifeq (${HIDPI_SUPPORT_CAIRO},1) +ifeq (${HIDPI_SUPPORT_GTK},1) +CPPFLAGS += -DHAVE_HIDPI_SUPPORT +endif +endif + # paths PREFIX ?= /usr MANPREFIX ?= ${PREFIX}/share/man diff --git a/zathura/callbacks.c b/zathura/callbacks.c index 4c4728d..b257b17 100644 --- a/zathura/callbacks.c +++ b/zathura/callbacks.c @@ -223,7 +223,11 @@ cb_scale_factor(GtkWidget* widget, GParamSpec* UNUSED(pspec), zathura_t* zathura return; } +#ifdef HAVE_HIDPI_SUPPORT int new_factor = gtk_widget_get_scale_factor(widget); +#else + int new_factor = 1; +#endif double current_x; double current_y; diff --git a/zathura/render.c b/zathura/render.c index 727d357..6c5db86 100644 --- a/zathura/render.c +++ b/zathura/render.c @@ -740,6 +740,7 @@ render(render_job_t* job, ZathuraRenderRequest* request, ZathuraRenderer* render &page_height, &page_width, false); +#ifdef HAVE_HIDPI_SUPPORT double device_scale_x; double device_scale_y; zathura_document_get_device_scale(document, &device_scale_x, &device_scale_y); @@ -748,6 +749,7 @@ render(render_job_t* job, ZathuraRenderRequest* request, ZathuraRenderer* render page_width *= device_scale_x; page_height *= device_scale_y; } +#endif cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, page_width, page_height); @@ -759,6 +761,7 @@ render(render_job_t* job, ZathuraRenderRequest* request, ZathuraRenderer* render return false; } +#ifdef HAVE_HIDPI_SUPPORT if (device_scale_x != 0.0 && device_scale_y != 0.0) { cairo_surface_set_device_scale(surface, device_scale_x, device_scale_y); if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { @@ -766,6 +769,7 @@ render(render_job_t* job, ZathuraRenderRequest* request, ZathuraRenderer* render return false; } } +#endif cairo_t* cairo = cairo_create(surface); if (cairo == NULL) { diff --git a/zathura/zathura.c b/zathura/zathura.c index 2d9a5d6..e83bf7b 100644 --- a/zathura/zathura.c +++ b/zathura/zathura.c @@ -153,8 +153,10 @@ init_ui(zathura_t* zathura) g_signal_connect(G_OBJECT(zathura->ui.session->gtk.view), "refresh-view", G_CALLBACK(cb_refresh_view), zathura); +#ifdef HAVE_HIDPI_SUPPORT g_signal_connect(G_OBJECT(zathura->ui.session->gtk.view), "notify::scale-factor", G_CALLBACK(cb_scale_factor), zathura); +#endif /* page view */ zathura->ui.page_widget = gtk_grid_new(); From 7f4acdb0f4869b93ff87df56c15715e39ab04cb7 Mon Sep 17 00:00:00 2001 From: Jeremie Knuesel Date: Tue, 23 Jan 2018 11:34:22 +0100 Subject: [PATCH 04/10] HiDPI: fix thumbnail scaling --- zathura/page-widget.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/zathura/page-widget.c b/zathura/page-widget.c index d5e4ad6..c6e170e 100644 --- a/zathura/page-widget.c +++ b/zathura/page-widget.c @@ -445,8 +445,18 @@ zathura_page_widget_draw(GtkWidget* widget, cairo_t* cairo) } else { const unsigned int height = cairo_image_surface_get_height(priv->thumbnail); const unsigned int width = cairo_image_surface_get_width(priv->thumbnail); - const unsigned int pheight = (rotation % 180 ? page_width : page_height); - const unsigned int pwidth = (rotation % 180 ? page_height : page_width); + unsigned int pheight = (rotation % 180 ? page_width : page_height); + unsigned int pwidth = (rotation % 180 ? page_height : page_width); + +#ifdef HAVE_HIDPI_SUPPORT + double device_scale_x; + double device_scale_y; + cairo_surface_get_device_scale(priv->thumbnail, &device_scale_x, &device_scale_y); + if (device_scale_x != 0.0 && device_scale_y != 0.0) { + pwidth *= device_scale_x; + pheight *= device_scale_y; + } +#endif cairo_scale(cairo, pwidth / (double)width, pheight / (double)height); cairo_set_source_surface(cairo, priv->thumbnail, 0, 0); From e487df053d7891d057dd04f85f047ce20d3c9d52 Mon Sep 17 00:00:00 2001 From: Jeremie Knuesel Date: Tue, 23 Jan 2018 19:57:16 +0100 Subject: [PATCH 05/10] HiDPI: use original notify callback signature --- zathura/callbacks.c | 7 ++++--- zathura/callbacks.h | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/zathura/callbacks.c b/zathura/callbacks.c index b257b17..b89a4a7 100644 --- a/zathura/callbacks.c +++ b/zathura/callbacks.c @@ -217,14 +217,15 @@ cb_refresh_view(GtkWidget* GIRARA_UNUSED(view), gpointer data) } void -cb_scale_factor(GtkWidget* widget, GParamSpec* UNUSED(pspec), zathura_t* zathura) +cb_scale_factor(GObject* object, GParamSpec* UNUSED(pspec), gpointer data) { - if (widget == NULL || zathura == NULL || zathura->document == NULL) { + zathura_t* zathura = data; + if (zathura == NULL || zathura->document == NULL) { return; } #ifdef HAVE_HIDPI_SUPPORT - int new_factor = gtk_widget_get_scale_factor(widget); + int new_factor = gtk_widget_get_scale_factor(GTK_WIDGET(object)); #else int new_factor = 1; #endif diff --git a/zathura/callbacks.h b/zathura/callbacks.h index 2be79b0..95ee0fe 100644 --- a/zathura/callbacks.h +++ b/zathura/callbacks.h @@ -85,11 +85,11 @@ void cb_refresh_view(GtkWidget* view, gpointer data); * * It records the new value and triggers a re-rendering of the document. * - * @param widget The view widget + * @param object The view widget * @param pspec The GParamSpec for the scale-factor property - * @param zathura The zathura instance + * @param gpointer The zathura instance */ -void cb_scale_factor(GtkWidget* widget, GParamSpec *pspec, zathura_t* zathura); +void cb_scale_factor(GObject* object, GParamSpec* pspec, gpointer data); /** * This function gets called when the value of the "pages-per-row" From 29b6e45c02da0044ecd2bcf6bfd0b388ba060316 Mon Sep 17 00:00:00 2001 From: Jeremie Knuesel Date: Tue, 23 Jan 2018 22:19:02 +0100 Subject: [PATCH 06/10] Bump GTK+ to 3.10 --- config.mk | 5 +---- zathura/callbacks.c | 4 ---- zathura/zathura.c | 2 -- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/config.mk b/config.mk index 9d957bb..05fffec 100644 --- a/config.mk +++ b/config.mk @@ -26,7 +26,7 @@ GLIB_MIN_VERSION = 2.50 GLIB_PKG_CONFIG_NAME = glib-2.0 # GTK GTK_VERSION_CHECK ?= 1 -GTK_MIN_VERSION = 3.6 +GTK_MIN_VERSION = 3.10 GTK_PKG_CONFIG_NAME = gtk+-3.0 # pkg-config binary @@ -49,12 +49,9 @@ WITH_MAGIC ?= 1 # HiDPI HIDPI_SUPPORT_CAIRO = $(shell (${PKG_CONFIG} --atleast-version=1.14 cairo && echo 1) || echo 0) -HIDPI_SUPPORT_GTK = $(shell (${PKG_CONFIG} --atleast-version=3.10 ${GTK_PKG_CONFIG_NAME} && echo 1) || echo 0) ifeq (${HIDPI_SUPPORT_CAIRO},1) -ifeq (${HIDPI_SUPPORT_GTK},1) CPPFLAGS += -DHAVE_HIDPI_SUPPORT endif -endif # paths PREFIX ?= /usr diff --git a/zathura/callbacks.c b/zathura/callbacks.c index b89a4a7..f82eda0 100644 --- a/zathura/callbacks.c +++ b/zathura/callbacks.c @@ -224,11 +224,7 @@ cb_scale_factor(GObject* object, GParamSpec* UNUSED(pspec), gpointer data) return; } -#ifdef HAVE_HIDPI_SUPPORT int new_factor = gtk_widget_get_scale_factor(GTK_WIDGET(object)); -#else - int new_factor = 1; -#endif double current_x; double current_y; diff --git a/zathura/zathura.c b/zathura/zathura.c index e83bf7b..2d9a5d6 100644 --- a/zathura/zathura.c +++ b/zathura/zathura.c @@ -153,10 +153,8 @@ init_ui(zathura_t* zathura) g_signal_connect(G_OBJECT(zathura->ui.session->gtk.view), "refresh-view", G_CALLBACK(cb_refresh_view), zathura); -#ifdef HAVE_HIDPI_SUPPORT g_signal_connect(G_OBJECT(zathura->ui.session->gtk.view), "notify::scale-factor", G_CALLBACK(cb_scale_factor), zathura); -#endif /* page view */ zathura->ui.page_widget = gtk_grid_new(); From e0cf06ff058266f54faabad0516e5945e06233af Mon Sep 17 00:00:00 2001 From: Jeremie Knuesel Date: Tue, 23 Jan 2018 22:22:38 +0100 Subject: [PATCH 07/10] Remove HAVE_HIDPI_SUPPORT One can simply check the Cairo version now that GTK+ has been bumped to 3.10. --- config.mk | 6 ------ zathura/page-widget.c | 2 +- zathura/render.c | 4 ++-- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/config.mk b/config.mk index 05fffec..d40a334 100644 --- a/config.mk +++ b/config.mk @@ -47,12 +47,6 @@ WITH_SYNCTEX ?= $(shell (${PKG_CONFIG} synctex && echo 1) || echo 0) # To disable support for mimetype detction with libmagic set WITH_MAGIC to 0. WITH_MAGIC ?= 1 -# HiDPI -HIDPI_SUPPORT_CAIRO = $(shell (${PKG_CONFIG} --atleast-version=1.14 cairo && echo 1) || echo 0) -ifeq (${HIDPI_SUPPORT_CAIRO},1) -CPPFLAGS += -DHAVE_HIDPI_SUPPORT -endif - # paths PREFIX ?= /usr MANPREFIX ?= ${PREFIX}/share/man diff --git a/zathura/page-widget.c b/zathura/page-widget.c index c6e170e..8067d3d 100644 --- a/zathura/page-widget.c +++ b/zathura/page-widget.c @@ -448,7 +448,7 @@ 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); -#ifdef HAVE_HIDPI_SUPPORT +#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); diff --git a/zathura/render.c b/zathura/render.c index 6c5db86..a890e49 100644 --- a/zathura/render.c +++ b/zathura/render.c @@ -740,7 +740,7 @@ render(render_job_t* job, ZathuraRenderRequest* request, ZathuraRenderer* render &page_height, &page_width, false); -#ifdef HAVE_HIDPI_SUPPORT +#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); @@ -761,7 +761,7 @@ render(render_job_t* job, ZathuraRenderRequest* request, ZathuraRenderer* render return false; } -#ifdef HAVE_HIDPI_SUPPORT +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,14,0) if (device_scale_x != 0.0 && device_scale_y != 0.0) { cairo_surface_set_device_scale(surface, device_scale_x, device_scale_y); if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { From 9cf323970898dd0cc76e65925b9293fb7d90beee Mon Sep 17 00:00:00 2001 From: Jeremie Knuesel Date: Tue, 23 Jan 2018 22:38:45 +0100 Subject: [PATCH 08/10] HiDPI: zero check using DBL_EPSILON --- zathura/page-widget.c | 2 +- zathura/render.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/zathura/page-widget.c b/zathura/page-widget.c index 8067d3d..765181e 100644 --- a/zathura/page-widget.c +++ b/zathura/page-widget.c @@ -452,7 +452,7 @@ zathura_page_widget_draw(GtkWidget* widget, cairo_t* cairo) double device_scale_x; double device_scale_y; cairo_surface_get_device_scale(priv->thumbnail, &device_scale_x, &device_scale_y); - if (device_scale_x != 0.0 && device_scale_y != 0.0) { + if (fabs(device_scale_x) >= DBL_EPSILON && fabs(device_scale_y) >= DBL_EPSILON) { pwidth *= device_scale_x; pheight *= device_scale_y; } diff --git a/zathura/render.c b/zathura/render.c index a890e49..a420d78 100644 --- a/zathura/render.c +++ b/zathura/render.c @@ -745,7 +745,10 @@ render(render_job_t* job, ZathuraRenderRequest* request, ZathuraRenderer* render double device_scale_y; zathura_document_get_device_scale(document, &device_scale_x, &device_scale_y); - if (device_scale_x != 0.0 && device_scale_y != 0.0) { + 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; } @@ -762,7 +765,7 @@ render(render_job_t* job, ZathuraRenderRequest* request, ZathuraRenderer* render } #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,14,0) - if (device_scale_x != 0.0 && device_scale_y != 0.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); From 4e9f8a7b1d77806b627ab8d602dfce38cda17ec0 Mon Sep 17 00:00:00 2001 From: Jeremie Knuesel Date: Wed, 24 Jan 2018 20:49:57 +0100 Subject: [PATCH 09/10] 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*)); From 9752b8f03baac58a82d5ded704d4046b344bb343 Mon Sep 17 00:00:00 2001 From: Jeremie Knuesel Date: Wed, 24 Jan 2018 20:56:18 +0100 Subject: [PATCH 10/10] HiDPI: fix initial-zooming artifact --- zathura/page-widget.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/zathura/page-widget.c b/zathura/page-widget.c index 3e5875f..ebb41f5 100644 --- a/zathura/page-widget.c +++ b/zathura/page-widget.c @@ -654,8 +654,14 @@ draw_thumbnail_image(cairo_surface_t* surface, size_t max_size) width = width * scale; height = height * scale; + /* note: this always returns 1 and 1 if Cairo too old for device scale API */ + zathura_device_factors_t device = get_safe_device_factors(surface); + const unsigned int user_width = width / device.x; + const unsigned int user_height = height / device.y; + + /* create thumbnail surface, taking width and height as device sizes */ cairo_surface_t *thumbnail; - thumbnail = cairo_surface_create_similar(surface, CAIRO_CONTENT_COLOR, width, height); + thumbnail = cairo_surface_create_similar(surface, CAIRO_CONTENT_COLOR, user_width, user_height); if (thumbnail == NULL) { return NULL; }