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.
This commit is contained in:
Jeremie Knuesel 2018-01-24 20:49:57 +01:00
parent 9cf3239708
commit 4e9f8a7b1d
7 changed files with 85 additions and 62 deletions

View file

@ -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, &current_x, &current_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);
}
}

View file

@ -5,6 +5,7 @@
#include <limits.h>
#include <glib.h>
#include <gio/gio.h>
#include <math.h>
#include <girara/datastructures.h>
#include <girara/utils.h>
@ -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

View file

@ -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

View file

@ -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);

View file

@ -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);
}

View file

@ -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

View file

@ -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*));