render.c 17 KB
Newer Older
Moritz Lipp's avatar
Moritz Lipp committed
1
2
3
/* See LICENSE file for license and copyright information */

#include <math.h>
4
5
#include <girara/datastructures.h>
#include <girara/utils.h>
6
#include "glib-compat.h"
Moritz Lipp's avatar
Moritz Lipp committed
7
8
#include "render.h"
#include "zathura.h"
9
#include "document.h"
Moritz Lipp's avatar
Moritz Lipp committed
10
#include "page.h"
11
#include "page-widget.h"
Sebastian Ramacher's avatar
Sebastian Ramacher committed
12
#include "utils.h"
Moritz Lipp's avatar
Moritz Lipp committed
13

14
15
16
17
18
19
20
21
22
/* define the two types */
G_DEFINE_TYPE(ZathuraRenderer, zathura_renderer, G_TYPE_OBJECT)
G_DEFINE_TYPE(ZathuraRenderRequest, zathura_render_request, G_TYPE_OBJECT)

/* private methods for ZathuraRenderer  */
static void zathura_renderer_finalize(GObject* object);
/* private methods for ZathuraRenderRequest */
static void zathura_render_request_finalize(GObject* object);

23
static void render_job(void* data, void* user_data);
24
static bool render(ZathuraRenderRequest* request, ZathuraRenderer* renderer);
25
static gint render_thread_sort(gconstpointer a, gconstpointer b, gpointer data);
26
static void color2double(const GdkColor* col, double* v);
27

Moritz Lipp's avatar
Moritz Lipp committed
28

29
30
/* private data for ZathuraRenderer */
typedef struct private_s {
31
  GThreadPool* pool; /**< Pool of threads */
32
  mutex mutex; /**< Render lock */
33
34
35
36
37
38
39
40
  volatile bool about_to_close; /**< Render thread is to be freed */

  /* recolor information */
  struct {
    bool enabled;
    bool hue;

    double light[3];
41
    GdkColor light_gdk;
42
    double dark[3];
43
    GdkColor dark_gdk;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
  } recolor;
} private_t;

/* private data for ZathuraRenderRequest */
typedef struct request_private_s {
  ZathuraRenderer* renderer;
  zathura_page_t* page;
  bool requested;
  bool aborted;
} request_private_t;

#define GET_PRIVATE(obj) \
  (G_TYPE_INSTANCE_GET_PRIVATE((obj), ZATHURA_TYPE_RENDERER, private_t))
#define REQUEST_GET_PRIVATE(obj) \
  (G_TYPE_INSTANCE_GET_PRIVATE((obj), ZATHURA_TYPE_RENDER_REQUEST, \
                               request_private_t))

/* init, new and free for ZathuraRenderer */
62
63

static void
64
zathura_renderer_class_init(ZathuraRendererClass* class)
65
{
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  /* add private members */
  g_type_class_add_private(class, sizeof(private_t));

  /* overwrite methods */
  GObjectClass* object_class = G_OBJECT_CLASS(class);
  object_class->finalize     = zathura_renderer_finalize;
}

static void
zathura_renderer_init(ZathuraRenderer* renderer)
{
  private_t* priv = GET_PRIVATE(renderer);
  priv->pool = g_thread_pool_new(render_job, renderer, 1, TRUE, NULL);
  priv->about_to_close = false;
  g_thread_pool_set_sort_function(priv->pool, render_thread_sort, NULL);
  mutex_init(&priv->mutex);

  priv->recolor.enabled = false;
  priv->recolor.hue = true;
85
86

  zathura_renderer_set_recolor_colors_str(renderer, "#000000", "#FFFFFF");
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
}

ZathuraRenderer*
zathura_renderer_new(zathura_t* zathura)
{
  g_return_val_if_fail(zathura != NULL, NULL);

  return g_object_new(ZATHURA_TYPE_RENDERER, /*"page", page, "zathura", zathura, */ NULL);
}

static void
zathura_renderer_finalize(GObject* object)
{
  ZathuraRenderer* renderer = ZATHURA_RENDERER(object);
  private_t* priv = GET_PRIVATE(renderer);

  zathura_renderer_stop(renderer);
  if (priv->pool) {
    g_thread_pool_free(priv->pool, TRUE, TRUE);
Moritz Lipp's avatar
Moritz Lipp committed
106
  }
107
108
109
110
111
112
113
114
115
  mutex_free(&(priv->mutex));
}

/* init, new and free for ZathuraRenderRequest */

enum {
  REQUEST_COMPLETED,
  REQUEST_LAST_SIGNAL
};
Moritz Lipp's avatar
Moritz Lipp committed
116

117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
static guint request_signals[REQUEST_LAST_SIGNAL] = { 0 };

static void
zathura_render_request_class_init(ZathuraRenderRequestClass* class)
{
  /* add private members */
  g_type_class_add_private(class, sizeof(request_private_t));

  /* overwrite methods */
  GObjectClass* object_class = G_OBJECT_CLASS(class);
  object_class->finalize     = zathura_render_request_finalize;

  request_signals[REQUEST_COMPLETED] = g_signal_new("completed",
      ZATHURA_TYPE_RENDER_REQUEST,
      G_SIGNAL_RUN_LAST,
      0,
      NULL,
      NULL,
      g_cclosure_marshal_generic,
      G_TYPE_NONE,
      1,
      G_TYPE_POINTER);
}

static void
zathura_render_request_init(ZathuraRenderRequest* request)
{
  request_private_t* priv = REQUEST_GET_PRIVATE(request);
  priv->renderer = NULL;
  priv->page = NULL;
}

ZathuraRenderRequest*
zathura_render_request_new(ZathuraRenderer* renderer, zathura_page_t* page)
{
  g_return_val_if_fail(renderer != NULL && page != NULL, NULL);

  GObject* obj = g_object_new(ZATHURA_TYPE_RENDER_REQUEST, NULL);
  if (obj == NULL) {
    return NULL;
157
  }
158
159
160
161
162
163
164
165
166
167

  ZathuraRenderRequest* request = ZATHURA_RENDER_REQUEST(obj);
  request_private_t* priv = REQUEST_GET_PRIVATE(request);
  /* we want to make sure that renderer lives long enough */
  priv->renderer = g_object_ref(renderer);
  priv->page = page;
  priv->aborted = false;
  priv->requested = false;

  return request;
Moritz Lipp's avatar
Moritz Lipp committed
168
169
}

170
171
static void
zathura_render_request_finalize(GObject* object)
Moritz Lipp's avatar
Moritz Lipp committed
172
{
173
174
  ZathuraRenderRequest* request = ZATHURA_RENDER_REQUEST(object);
  request_private_t* priv = REQUEST_GET_PRIVATE(request);
Moritz Lipp's avatar
Moritz Lipp committed
175

176
177
  if (priv->renderer) {
    g_object_unref(priv->renderer);
178
  }
179
180
181
}

/* renderer methods */
182

183
184
185
186
bool
zathura_renderer_recolor_enabled(ZathuraRenderer* renderer)
{
  g_return_val_if_fail(ZATHURA_IS_RENDERER(renderer), false);
187

188
189
  return GET_PRIVATE(renderer)->recolor.enabled;
}
Moritz Lipp's avatar
Moritz Lipp committed
190

191
192
193
194
void
zathura_renderer_enable_recolor(ZathuraRenderer* renderer, bool enable)
{
  g_return_if_fail(ZATHURA_IS_RENDERER(renderer));
Moritz Lipp's avatar
Moritz Lipp committed
195

196
197
198
199
200
201
202
203
204
  GET_PRIVATE(renderer)->recolor.enabled = enable;
}

bool
zathura_renderer_recolor_hue_enabled(ZathuraRenderer* renderer)
{
  g_return_val_if_fail(ZATHURA_IS_RENDERER(renderer), false);

  return GET_PRIVATE(renderer)->recolor.hue;
Moritz Lipp's avatar
Moritz Lipp committed
205
206
207
}

void
208
zathura_renderer_enable_recolor_hue(ZathuraRenderer* renderer, bool enable)
Moritz Lipp's avatar
Moritz Lipp committed
209
{
210
211
212
213
214
  g_return_if_fail(ZATHURA_IS_RENDERER(renderer));

  GET_PRIVATE(renderer)->recolor.hue = enable;
}

215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
void
zathura_renderer_set_recolor_colors(ZathuraRenderer* renderer,
    const GdkColor* light, const GdkColor* dark)
{
  g_return_if_fail(ZATHURA_IS_RENDERER(renderer));

  private_t* priv = GET_PRIVATE(renderer);
  if (light != NULL) {
    priv->recolor.light_gdk.red = light->red;
    priv->recolor.light_gdk.blue = light->blue;
    priv->recolor.light_gdk.green = light->green;
    color2double(light, priv->recolor.light);
  }
  if (dark != NULL) {
    priv->recolor.dark_gdk.red = dark->red;
    priv->recolor.dark_gdk.blue = dark->blue;
    priv->recolor.dark_gdk.green = dark->green;
    color2double(dark, priv->recolor.dark);
  }
}

void
zathura_renderer_set_recolor_colors_str(ZathuraRenderer* renderer,
    const char* light, const char* dark)
{
  g_return_if_fail(ZATHURA_IS_RENDERER(renderer));

  if (dark != NULL) {
    GdkColor color;
    gdk_color_parse(dark, &color);
    zathura_renderer_set_recolor_colors(renderer, NULL, &color);
  }
  if (light != NULL) {
    GdkColor color;
    gdk_color_parse(light, &color);
    zathura_renderer_set_recolor_colors(renderer, &color, NULL);
  }
}

void
zathura_renderer_get_recolor_colors(ZathuraRenderer* renderer,
256
257
258
259
260
    GdkColor* light, GdkColor* dark)
{
  g_return_if_fail(ZATHURA_IS_RENDERER(renderer));

  private_t* priv = GET_PRIVATE(renderer);
261
262
263
264
265
266
267
268
269
270
  if (light != NULL) {
    light->red = priv->recolor.light_gdk.red;
    light->blue = priv->recolor.light_gdk.blue;
    light->green = priv->recolor.light_gdk.green;
  }
  if (dark != NULL) {
    dark->red = priv->recolor.dark_gdk.red;
    dark->blue = priv->recolor.dark_gdk.blue;
    dark->green = priv->recolor.dark_gdk.green;
  }
271
272
273
274
275
276
277
278
279
280
}

void
zathura_renderer_lock(ZathuraRenderer* renderer)
{
  g_return_if_fail(ZATHURA_IS_RENDERER(renderer));

  private_t* priv = GET_PRIVATE(renderer);
  mutex_lock(&priv->mutex);
}
Moritz Lipp's avatar
Moritz Lipp committed
281

282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
void
zathura_renderer_unlock(ZathuraRenderer* renderer)
{
  g_return_if_fail(ZATHURA_IS_RENDERER(renderer));

  private_t* priv = GET_PRIVATE(renderer);
  mutex_unlock(&priv->mutex);
}

void
zathura_renderer_stop(ZathuraRenderer* renderer)
{
  g_return_if_fail(ZATHURA_IS_RENDERER(renderer));
  GET_PRIVATE(renderer)->about_to_close = true;
}


/* ZathuraRenderRequest methods */

void
zathura_render_request(ZathuraRenderRequest* request)
{
  g_return_if_fail(ZATHURA_IS_RENDER_REQUEST(request));

  request_private_t* request_priv = REQUEST_GET_PRIVATE(request);
  private_t* priv = GET_PRIVATE(request_priv->renderer);
  if (request_priv->requested == false) {
    request_priv->requested = true;
    request_priv->aborted = false;

    g_thread_pool_push(priv->pool, request, NULL);
Moritz Lipp's avatar
Moritz Lipp committed
313
  }
314
}
315

316
317
318
319
320
321
322
323
324
void
zathura_render_request_abort(ZathuraRenderRequest* request)
{
  g_return_if_fail(ZATHURA_IS_RENDER_REQUEST(request));

  request_private_t* request_priv = REQUEST_GET_PRIVATE(request);
  if (request_priv->requested == true) {
    request_priv->aborted = true;
  }
Moritz Lipp's avatar
Moritz Lipp committed
325
326
}

327
328
329

static void
render_job(void* data, void* user_data)
Moritz Lipp's avatar
Moritz Lipp committed
330
{
331
332
333
334
335
336
337
338
339
340
341
  ZathuraRenderRequest* request = data;
  ZathuraRenderer* renderer = user_data;
  g_return_if_fail(ZATHURA_IS_RENDER_REQUEST(request));
  g_return_if_fail(ZATHURA_IS_RENDERER(renderer));

  private_t* priv = GET_PRIVATE(renderer);
  request_private_t* request_priv = REQUEST_GET_PRIVATE(request);
  if (priv->about_to_close == true || request_priv->aborted == true) {
    /* back out early */
    request_priv->requested = false;
    return;
Moritz Lipp's avatar
Moritz Lipp committed
342
343
  }

344
345
346
347
  girara_debug("Rendering page %d ...", zathura_page_get_index(request_priv->page) + 1);
  if (render(request, renderer) != true) {
    girara_error("Rendering failed (page %d)\n", zathura_page_get_index(request_priv->page) + 1);
  }
Moritz Lipp's avatar
Moritz Lipp committed
348
349
}

Sebastian Ramacher's avatar
Sebastian Ramacher committed
350
static void
351
color2double(const GdkColor* col, double* v)
352
353
354
355
356
357
358
359
360
{
  v[0] = (double) col->red / 65535.;
  v[1] = (double) col->green / 65535.;
  v[2] = (double) col->blue / 65535.;
}

/* Returns the maximum possible saturation for given h and l.
   Assumes that l is in the interval l1, l2 and corrects the value to
   force u=0 on l1 and l2 */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
361
static double
362
colorumax(const double* h, double l, double l1, double l2)
363
364
365
366
367
368
369
370
371
372
373
374
375
{
  double u, uu, v, vv, lv;
  if (h[0] == 0 && h[1] == 0 && h[2] == 0) {
    return 0;
  }

  lv = (l - l1)/(l2 - l1);    /* Remap l to the whole interval 0,1 */
  u = v = 1000000;
  for (int k = 0; k < 3; k++) {
    if (h[k] > 0) {
      uu = fabs((1-l)/h[k]);
      vv = fabs((1-lv)/h[k]);

Sebastian Ramacher's avatar
Sebastian Ramacher committed
376
377
378
379
380
381
      if (uu < u) {
        u = uu;
      }
      if (vv < v) {
        v = vv;
      }
382
383
384
385
    } else if (h[k] < 0) {
      uu = fabs(l/h[k]);
      vv = fabs(lv/h[k]);

Sebastian Ramacher's avatar
Sebastian Ramacher committed
386
387
388
389
390
391
      if (uu < u) {
        u = uu;
      }
      if (vv < v) {
        v = vv;
      }
392
393
394
395
    }
  }

  /* rescale v according to the length of the interval [l1, l2] */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
396
  v = fabs(l2 - l1) * v;
397
398
399
400
401

  /* forces the returned value to be 0 on l1 and l2, trying not to distort colors too much */
  return fmin(u, v);
}

402
403
typedef struct emit_completed_signal_s
{
404
  ZathuraRenderer* renderer;
405
406
407
408
409
410
411
412
  ZathuraRenderRequest* request;
  cairo_surface_t* surface;
} emit_completed_signal_t;

static gboolean
emit_completed_signal(void* data)
{
  emit_completed_signal_t* ecs = data;
413
414
415
416
417
418
419
420
421
422
  private_t* priv = GET_PRIVATE(ecs->renderer);
  request_private_t* request_priv = REQUEST_GET_PRIVATE(ecs->request);

  if (priv->about_to_close == false && request_priv->aborted == false) {
    /* emit the signal */
    g_signal_emit(ecs->request, request_signals[REQUEST_COMPLETED], 0, ecs->surface);
  }
  /* mark the request as done */
  request_priv->requested = false;

423
424
  /* clean up the data */
  cairo_surface_destroy(ecs->surface);
425
426
  g_object_unref(ecs->renderer);
  g_object_unref(ecs->request);
427
  g_free(ecs);
428

Sebastian Ramacher's avatar
Sebastian Ramacher committed
429
  return FALSE;
430
}
431

432
static bool
433
render(ZathuraRenderRequest* request, ZathuraRenderer* renderer)
Moritz Lipp's avatar
Moritz Lipp committed
434
{
435
436
437
  private_t* priv = GET_PRIVATE(renderer);
  request_private_t* request_priv = REQUEST_GET_PRIVATE(request);
  zathura_page_t* page = request_priv->page;
Moritz Lipp's avatar
Update    
Moritz Lipp committed
438

Moritz Lipp's avatar
Moritz Lipp committed
439
440
441
  /* create cairo surface */
  unsigned int page_width  = 0;
  unsigned int page_height = 0;
442
  const double real_scale = page_calc_height_width(page, &page_height, &page_width, false);
Moritz Lipp's avatar
Moritz Lipp committed
443
444
445

  cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, page_width, page_height);
  if (surface == NULL) {
Moritz Lipp's avatar
Moritz Lipp committed
446
447
448
    return false;
  }

Moritz Lipp's avatar
Moritz Lipp committed
449
450
451
452
453
  cairo_t* cairo = cairo_create(surface);
  if (cairo == NULL) {
    cairo_surface_destroy(surface);
    return false;
  }
Moritz Lipp's avatar
Moritz Lipp committed
454

Moritz Lipp's avatar
Moritz Lipp committed
455
456
457
458
459
460
  cairo_save(cairo);
  cairo_set_source_rgb(cairo, 1, 1, 1);
  cairo_rectangle(cairo, 0, 0, page_width, page_height);
  cairo_fill(cairo);
  cairo_restore(cairo);
  cairo_save(cairo);
Moritz Lipp's avatar
Moritz Lipp committed
461

462
463
  if (fabs(real_scale - 1.0f) > FLT_EPSILON) {
    cairo_scale(cairo, real_scale, real_scale);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
464
465
  }

466
  zathura_renderer_lock(renderer);
467
  if (zathura_page_render(page, cairo, false) != ZATHURA_ERROR_OK) {
468
    zathura_renderer_unlock(renderer);
Moritz Lipp's avatar
Moritz Lipp committed
469
470
471
    cairo_destroy(cairo);
    cairo_surface_destroy(surface);
    return false;
Moritz Lipp's avatar
Moritz Lipp committed
472
  }
Moritz Lipp's avatar
Moritz Lipp committed
473

474
  zathura_renderer_unlock(renderer);
Moritz Lipp's avatar
Moritz Lipp committed
475
476
477
  cairo_restore(cairo);
  cairo_destroy(cairo);

478
479
480
481
482
483
  /* before recoloring, check if we've been aborted */
  if (priv->about_to_close == true || request_priv->aborted == true) {
    cairo_surface_destroy(surface);
    return true;
  }

Moritz Lipp's avatar
Moritz Lipp committed
484

Moritz Lipp's avatar
Moritz Lipp committed
485
  /* recolor */
486
487
488
489
490
  /* uses a representation of a rgb color as follows:
     - a lightness scalar (between 0,1), which is a weighted average of r, g, b,
     - a hue vector, which indicates a radian direction from the grey axis, inside the equal lightness plane.
     - a saturation scalar between 0,1. It is 0 when grey, 1 when the color is in the boundary of the rgb cube.
  */
491
492
493
  if (priv->recolor.enabled == true) {
    const int rowstride  = cairo_image_surface_get_stride(surface);
    unsigned char* image = cairo_image_surface_get_data(surface);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
494

495
496
    /* RGB weights for computing lightness. Must sum to one */
    static const double a[] = {0.30, 0.59, 0.11};
Moritz Lipp's avatar
Moritz Lipp committed
497

498
499
500
501
#define rgb1 priv->recolor.dark
#define rgb2 priv->recolor.light
    const double l1 = (a[0]*rgb1[0] + a[1]*rgb1[1] + a[2]*rgb1[2]);
    const double l2 = (a[0]*rgb2[0] + a[1]*rgb2[1] + a[2]*rgb2[2]);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
502

Sebastian Ramacher's avatar
Sebastian Ramacher committed
503
504
505
506
507
508
    const double rgb_diff[] = {
      rgb2[0] - rgb1[0],
      rgb2[1] - rgb1[1],
      rgb2[2] - rgb1[2]
    };

Moritz Lipp's avatar
Moritz Lipp committed
509
510
511
    for (unsigned int y = 0; y < page_height; y++) {
      unsigned char* data = image + y * rowstride;

512
      for (unsigned int x = 0; x < page_width; x++, data += 4) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
513
        /* Careful. data color components blue, green, red. */
514
515
516
517
518
        const double rgb[3] = {
          (double) data[2] / 256.,
          (double) data[1] / 256.,
          (double) data[0] / 256.
        };
Sebastian Ramacher's avatar
Sebastian Ramacher committed
519
520

        /* compute h, s, l data   */
521
522
523
524
525
526
527
528
529
530
531
532
        double l = a[0]*rgb[0] + a[1]*rgb[1] + a[2]*rgb[2];

        const double h[3] = {
          rgb[0] - l,
          rgb[1] - l,
          rgb[2] - l
        };

        /* u is the maximum possible saturation for given h and l. s is a
         * rescaled saturation between 0 and 1 */
        double u = colorumax(h, l, 0, 1);
        double s;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
533
534
535
536
537
538
        if (u == 0) {
          s = 0;
        } else {
          s = 1/u;
        }

539
540
541
        /* Interpolates lightness between light and dark colors. white goes to
         * light, and black goes to dark. */
        const double t = l;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
542
543
        l = t * (l2 - l1) + l1;

544
545
546
        if (priv->recolor.hue == true) {
          /* adjusting lightness keeping hue of current color. white and black
           * go to grays of same ligtness as light and dark colors. */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
547
548
549
550
551
          u = colorumax(h, l, l1, l2);
          data[2] = (unsigned char)round(255.*(l + s*u * h[0]));
          data[1] = (unsigned char)round(255.*(l + s*u * h[1]));
          data[0] = (unsigned char)round(255.*(l + s*u * h[2]));
        } else {
552
553
          /* linear interpolation between dark and light with color ligtness as
           * a parameter */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
554
555
556
          data[2] = (unsigned char)round(255.*(t * rgb_diff[0] + rgb1[0]));
          data[1] = (unsigned char)round(255.*(t * rgb_diff[1] + rgb1[1]));
          data[0] = (unsigned char)round(255.*(t * rgb_diff[2] + rgb1[2]));
Sebastian Ramacher's avatar
Sebastian Ramacher committed
557
        }
Moritz Lipp's avatar
Moritz Lipp committed
558
559
      }
    }
560
561
562

#undef rgb1
#undef rgb2
Moritz Lipp's avatar
Moritz Lipp committed
563
564
  }

565
566
567
568
569
570
571
  emit_completed_signal_t* ecs = g_malloc(sizeof(ecs));
  ecs->renderer = renderer;
  ecs->request = request;
  ecs->surface = surface;
  g_object_ref(renderer);
  g_object_ref(request);
  cairo_surface_reference(surface);
572

573
574
  /* emit signal from the main context, i.e. the main thread */
  g_main_context_invoke(NULL, emit_completed_signal, ecs);
Moritz Lipp's avatar
Moritz Lipp committed
575

576
577
  cairo_surface_destroy(surface);

Moritz Lipp's avatar
Moritz Lipp committed
578
579
  return true;
}
580
581

void
Moritz Lipp's avatar
Moritz Lipp committed
582
render_all(zathura_t* zathura)
583
{
584
  if (zathura == NULL || zathura->document == NULL) {
585
586
587
588
    return;
  }

  /* unmark all pages */
589
590
591
  unsigned int number_of_pages = zathura_document_get_number_of_pages(zathura->document);
  for (unsigned int page_id = 0; page_id < number_of_pages; page_id++) {
    zathura_page_t* page = zathura_document_get_page(zathura->document, page_id);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
592
    unsigned int page_height = 0, page_width = 0;
593
    page_calc_height_width(page, &page_height, &page_width, true);
594

595
    GtkWidget* widget = zathura_page_get_widget(zathura, page);
Moritz Lipp's avatar
Moritz Lipp committed
596
597
    gtk_widget_set_size_request(widget, page_width, page_height);
    gtk_widget_queue_resize(widget);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
598
  }
Moritz Lipp's avatar
Update    
Moritz Lipp committed
599
}
600
601

static gint
602
render_thread_sort(gconstpointer a, gconstpointer b, gpointer UNUSED(data))
603
{
604
  if (a == NULL || b == NULL) {
605
606
607
    return 0;
  }

608
609
610
611
612
613
614
615
616
  ZathuraRenderRequest* request_a = (ZathuraRenderRequest*) a;
  ZathuraRenderRequest* request_b = (ZathuraRenderRequest*) b;
  request_private_t* priv_a = REQUEST_GET_PRIVATE(request_a);
  request_private_t* priv_b = REQUEST_GET_PRIVATE(request_b);
  if (priv_a->aborted == priv_b->aborted) {
    unsigned int page_a_index = zathura_page_get_index(priv_a->page);
    unsigned int page_b_index = zathura_page_get_index(priv_b->page);
    return page_a_index < page_b_index ? -1 :
        (page_a_index > page_b_index ? 1 : 0);
617
618
  }

619
620
  /* sort aborted entries earlier so that the are thrown out of the queue */
  return priv_a->aborted ? 1 : -1;
621
}