2 #include "ev-pixbuf-cache.h"
3 #include "ev-job-scheduler.h"
4 #include "ev-view-private.h"
6 typedef struct _CacheJobInfo
11 /* Region of the page that needs to be drawn */
12 cairo_region_t *region;
14 /* Data we get from rendering */
15 cairo_surface_t *surface;
18 * Selection_points are the coordinates encapsulated in selection.
19 * target_points is the target selection size. */
20 EvRectangle selection_points;
21 EvRectangle target_points;
22 EvSelectionStyle selection_style;
25 cairo_surface_t *selection;
26 cairo_region_t *selection_region;
33 /* We keep a link to our containing view just for style information. */
36 EvDocumentModel *model;
39 gboolean inverted_colors;
43 /* preload_cache_size is the number of pages prior to the current
44 * visible area that we cache. It's normally 1, but could be 2 in the
47 int preload_cache_size;
50 CacheJobInfo *prev_job;
51 CacheJobInfo *job_list;
52 CacheJobInfo *next_job;
55 struct _EvPixbufCacheClass
57 GObjectClass parent_class;
59 void (* job_finished) (EvPixbufCache *pixbuf_cache);
69 static guint signals[N_SIGNALS] = {0, };
71 static void ev_pixbuf_cache_init (EvPixbufCache *pixbuf_cache);
72 static void ev_pixbuf_cache_class_init (EvPixbufCacheClass *pixbuf_cache);
73 static void ev_pixbuf_cache_finalize (GObject *object);
74 static void ev_pixbuf_cache_dispose (GObject *object);
75 static void job_finished_cb (EvJob *job,
76 EvPixbufCache *pixbuf_cache);
77 static CacheJobInfo *find_job_cache (EvPixbufCache *pixbuf_cache,
79 static gboolean new_selection_surface_needed(EvPixbufCache *pixbuf_cache,
80 CacheJobInfo *job_info,
85 /* These are used for iterating through the prev and next arrays */
86 #define FIRST_VISIBLE_PREV(pixbuf_cache) \
87 (MAX (0, pixbuf_cache->preload_cache_size - pixbuf_cache->start_page))
88 #define VISIBLE_NEXT_LEN(pixbuf_cache) \
89 (MIN(pixbuf_cache->preload_cache_size, ev_document_get_n_pages (pixbuf_cache->document) - (1 + pixbuf_cache->end_page)))
90 #define PAGE_CACHE_LEN(pixbuf_cache) \
91 ((pixbuf_cache->end_page - pixbuf_cache->start_page) + 1)
93 #define MAX_PRELOADED_PAGES 3
95 G_DEFINE_TYPE (EvPixbufCache, ev_pixbuf_cache, G_TYPE_OBJECT)
98 ev_pixbuf_cache_init (EvPixbufCache *pixbuf_cache)
100 pixbuf_cache->start_page = -1;
101 pixbuf_cache->end_page = -1;
105 ev_pixbuf_cache_class_init (EvPixbufCacheClass *class)
107 GObjectClass *object_class;
109 object_class = G_OBJECT_CLASS (class);
111 object_class->finalize = ev_pixbuf_cache_finalize;
112 object_class->dispose = ev_pixbuf_cache_dispose;
114 signals[JOB_FINISHED] =
115 g_signal_new ("job-finished",
116 G_OBJECT_CLASS_TYPE (object_class),
117 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
118 G_STRUCT_OFFSET (EvPixbufCacheClass, job_finished),
120 g_cclosure_marshal_VOID__POINTER,
126 ev_pixbuf_cache_finalize (GObject *object)
128 EvPixbufCache *pixbuf_cache;
130 pixbuf_cache = EV_PIXBUF_CACHE (object);
132 if (pixbuf_cache->job_list) {
133 g_slice_free1 (sizeof (CacheJobInfo) * pixbuf_cache->job_list_len,
134 pixbuf_cache->job_list);
135 pixbuf_cache->job_list = NULL;
137 if (pixbuf_cache->prev_job) {
138 g_slice_free1 (sizeof (CacheJobInfo) * pixbuf_cache->preload_cache_size,
139 pixbuf_cache->prev_job);
140 pixbuf_cache->prev_job = NULL;
142 if (pixbuf_cache->next_job) {
143 g_slice_free1 (sizeof (CacheJobInfo) * pixbuf_cache->preload_cache_size,
144 pixbuf_cache->next_job);
145 pixbuf_cache->next_job = NULL;
148 g_object_unref (pixbuf_cache->model);
150 G_OBJECT_CLASS (ev_pixbuf_cache_parent_class)->finalize (object);
154 dispose_cache_job_info (CacheJobInfo *job_info,
157 if (job_info == NULL)
161 g_signal_handlers_disconnect_by_func (job_info->job,
162 G_CALLBACK (job_finished_cb),
164 ev_job_cancel (job_info->job);
165 g_object_unref (job_info->job);
166 job_info->job = NULL;
168 if (job_info->surface) {
169 cairo_surface_destroy (job_info->surface);
170 job_info->surface = NULL;
172 if (job_info->region) {
173 cairo_region_destroy (job_info->region);
174 job_info->region = NULL;
176 if (job_info->selection) {
177 cairo_surface_destroy (job_info->selection);
178 job_info->selection = NULL;
180 if (job_info->selection_region) {
181 cairo_region_destroy (job_info->selection_region);
182 job_info->selection_region = NULL;
185 job_info->points_set = FALSE;
189 ev_pixbuf_cache_dispose (GObject *object)
191 EvPixbufCache *pixbuf_cache;
194 pixbuf_cache = EV_PIXBUF_CACHE (object);
196 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
197 dispose_cache_job_info (pixbuf_cache->prev_job + i, pixbuf_cache);
198 dispose_cache_job_info (pixbuf_cache->next_job + i, pixbuf_cache);
201 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
202 dispose_cache_job_info (pixbuf_cache->job_list + i, pixbuf_cache);
205 G_OBJECT_CLASS (ev_pixbuf_cache_parent_class)->dispose (object);
210 ev_pixbuf_cache_new (GtkWidget *view,
211 EvDocumentModel *model,
214 EvPixbufCache *pixbuf_cache;
216 pixbuf_cache = (EvPixbufCache *) g_object_new (EV_TYPE_PIXBUF_CACHE, NULL);
217 /* This is a backlink, so we don't ref this */
218 pixbuf_cache->view = view;
219 pixbuf_cache->model = g_object_ref (model);
220 pixbuf_cache->document = ev_document_model_get_document (model);
221 pixbuf_cache->max_size = max_size;
227 ev_pixbuf_cache_set_max_size (EvPixbufCache *pixbuf_cache,
230 if (pixbuf_cache->max_size == max_size)
233 if (pixbuf_cache->max_size > max_size)
234 ev_pixbuf_cache_clear (pixbuf_cache);
235 pixbuf_cache->max_size = max_size;
239 copy_job_to_job_info (EvJobRender *job_render,
240 CacheJobInfo *job_info,
241 EvPixbufCache *pixbuf_cache)
243 if (job_info->surface) {
244 cairo_surface_destroy (job_info->surface);
246 job_info->surface = cairo_surface_reference (job_render->surface);
247 if (pixbuf_cache->inverted_colors) {
248 ev_document_misc_invert_surface (job_info->surface);
251 job_info->points_set = FALSE;
252 if (job_render->include_selection) {
253 if (job_info->selection) {
254 cairo_surface_destroy (job_info->selection);
255 job_info->selection = NULL;
257 if (job_info->selection_region) {
258 cairo_region_destroy (job_info->selection_region);
259 job_info->selection_region = NULL;
262 job_info->selection_points = job_render->selection_points;
263 job_info->selection_region = cairo_region_reference (job_render->selection_region);
264 job_info->selection = cairo_surface_reference (job_render->selection);
265 g_assert (job_info->selection_points.x1 >= 0);
266 job_info->points_set = TRUE;
270 g_signal_handlers_disconnect_by_func (job_info->job,
271 G_CALLBACK (job_finished_cb),
273 ev_job_cancel (job_info->job);
274 g_object_unref (job_info->job);
275 job_info->job = NULL;
278 job_info->page_ready = TRUE;
282 job_finished_cb (EvJob *job,
283 EvPixbufCache *pixbuf_cache)
285 CacheJobInfo *job_info;
286 EvJobRender *job_render = EV_JOB_RENDER (job);
288 /* If the job is outside of our interest, we silently discard it */
289 if ((job_render->page < (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size)) ||
290 (job_render->page > (pixbuf_cache->end_page + pixbuf_cache->preload_cache_size))) {
291 g_object_unref (job);
295 job_info = find_job_cache (pixbuf_cache, job_render->page);
297 copy_job_to_job_info (job_render, job_info, pixbuf_cache);
298 g_signal_emit (pixbuf_cache, signals[JOB_FINISHED], 0, job_info->region);
301 /* This checks a job to see if the job would generate the right sized pixbuf
302 * given a scale. If it won't, it removes the job and clears it to NULL.
305 check_job_size_and_unref (EvPixbufCache *pixbuf_cache,
306 CacheJobInfo *job_info,
313 if (job_info->job == NULL)
316 _get_page_size_for_scale_and_rotation (job_info->job->document,
317 EV_JOB_RENDER (job_info->job)->page,
319 EV_JOB_RENDER (job_info->job)->rotation,
321 if (width == EV_JOB_RENDER (job_info->job)->target_width &&
322 height == EV_JOB_RENDER (job_info->job)->target_height)
325 g_signal_handlers_disconnect_by_func (job_info->job,
326 G_CALLBACK (job_finished_cb),
328 ev_job_cancel (job_info->job);
329 g_object_unref (job_info->job);
330 job_info->job = NULL;
333 /* Do all function that copies a job from an older cache to it's position in the
334 * new cache. It clears the old job if it doesn't have a place.
337 move_one_job (CacheJobInfo *job_info,
338 EvPixbufCache *pixbuf_cache,
340 CacheJobInfo *new_job_list,
341 CacheJobInfo *new_prev_job,
342 CacheJobInfo *new_next_job,
343 int new_preload_cache_size,
348 CacheJobInfo *target_page = NULL;
352 if (page < (start_page - new_preload_cache_size) ||
353 page > (end_page + new_preload_cache_size)) {
354 dispose_cache_job_info (job_info, pixbuf_cache);
358 /* find the target page to copy it over to. */
359 if (page < start_page) {
360 page_offset = (page - (start_page - new_preload_cache_size));
362 g_assert (page_offset >= 0 &&
363 page_offset < new_preload_cache_size);
364 target_page = new_prev_job + page_offset;
365 new_priority = EV_JOB_PRIORITY_LOW;
366 } else if (page > end_page) {
367 page_offset = (page - (end_page + 1));
369 g_assert (page_offset >= 0 &&
370 page_offset < new_preload_cache_size);
371 target_page = new_next_job + page_offset;
372 new_priority = EV_JOB_PRIORITY_LOW;
374 page_offset = page - start_page;
375 g_assert (page_offset >= 0 &&
376 page_offset <= ((end_page - start_page) + 1));
377 new_priority = EV_JOB_PRIORITY_URGENT;
378 target_page = new_job_list + page_offset;
381 *target_page = *job_info;
382 job_info->job = NULL;
383 job_info->region = NULL;
384 job_info->surface = NULL;
386 if (new_priority != priority && target_page->job) {
387 ev_job_scheduler_update_job (target_page->job, new_priority);
392 ev_pixbuf_cache_get_page_size (EvPixbufCache *pixbuf_cache,
399 _get_page_size_for_scale_and_rotation (pixbuf_cache->document,
400 page_index, scale, rotation,
402 return height * cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
406 ev_pixbuf_cache_get_preload_size (EvPixbufCache *pixbuf_cache,
412 gsize range_size = 0;
413 gint new_preload_cache_size = 0;
415 guint n_pages = ev_document_get_n_pages (pixbuf_cache->document);
417 /* Get the size of the current range */
418 for (i = start_page; i <= end_page; i++) {
419 range_size += ev_pixbuf_cache_get_page_size (pixbuf_cache, i, scale, rotation);
422 if (range_size >= pixbuf_cache->max_size)
423 return new_preload_cache_size;
426 while (((start_page - i > 0) || (end_page + i < n_pages)) &&
427 new_preload_cache_size < MAX_PRELOADED_PAGES) {
429 gboolean updated = FALSE;
431 if (end_page + i < n_pages) {
432 page_size = ev_pixbuf_cache_get_page_size (pixbuf_cache, end_page + i,
434 if (page_size + range_size <= pixbuf_cache->max_size) {
435 range_size += page_size;
436 new_preload_cache_size++;
443 if (start_page - i > 0) {
444 page_size = ev_pixbuf_cache_get_page_size (pixbuf_cache, start_page - i,
446 if (page_size + range_size <= pixbuf_cache->max_size) {
447 range_size += page_size;
449 new_preload_cache_size++;
457 return new_preload_cache_size;
461 ev_pixbuf_cache_update_range (EvPixbufCache *pixbuf_cache,
467 CacheJobInfo *new_job_list;
468 CacheJobInfo *new_prev_job = NULL;
469 CacheJobInfo *new_next_job = NULL;
470 gint new_preload_cache_size;
471 guint new_job_list_len;
474 new_preload_cache_size = ev_pixbuf_cache_get_preload_size (pixbuf_cache,
479 if (pixbuf_cache->start_page == start_page &&
480 pixbuf_cache->end_page == end_page &&
481 pixbuf_cache->preload_cache_size == new_preload_cache_size)
484 new_job_list_len = (end_page - start_page) + 1;
485 new_job_list = g_slice_alloc0 (sizeof (CacheJobInfo) * new_job_list_len);
486 if (new_preload_cache_size > 0) {
487 new_prev_job = g_slice_alloc0 (sizeof (CacheJobInfo) * new_preload_cache_size);
488 new_next_job = g_slice_alloc0 (sizeof (CacheJobInfo) * new_preload_cache_size);
491 /* We go through each job in the old cache and either clear it or move
492 * it to a new location. */
494 /* Start with the prev cache. */
495 page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size;
496 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
498 dispose_cache_job_info (pixbuf_cache->prev_job + i, pixbuf_cache);
500 move_one_job (pixbuf_cache->prev_job + i,
502 new_job_list, new_prev_job, new_next_job,
503 new_preload_cache_size,
504 start_page, end_page, EV_JOB_PRIORITY_LOW);
509 page = pixbuf_cache->start_page;
510 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache) && page >= 0; i++) {
511 move_one_job (pixbuf_cache->job_list + i,
513 new_job_list, new_prev_job, new_next_job,
514 new_preload_cache_size,
515 start_page, end_page, EV_JOB_PRIORITY_URGENT);
519 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
520 if (page >= ev_document_get_n_pages (pixbuf_cache->document)) {
521 dispose_cache_job_info (pixbuf_cache->next_job + i, pixbuf_cache);
523 move_one_job (pixbuf_cache->next_job + i,
525 new_job_list, new_prev_job, new_next_job,
526 new_preload_cache_size,
527 start_page, end_page, EV_JOB_PRIORITY_LOW);
532 if (pixbuf_cache->job_list) {
533 g_slice_free1 (sizeof (CacheJobInfo) * pixbuf_cache->job_list_len,
534 pixbuf_cache->job_list);
536 if (pixbuf_cache->prev_job) {
537 g_slice_free1 (sizeof (CacheJobInfo) * pixbuf_cache->preload_cache_size,
538 pixbuf_cache->prev_job);
540 if (pixbuf_cache->next_job) {
541 g_slice_free1 (sizeof (CacheJobInfo) * pixbuf_cache->preload_cache_size,
542 pixbuf_cache->next_job);
545 pixbuf_cache->preload_cache_size = new_preload_cache_size;
546 pixbuf_cache->job_list_len = new_job_list_len;
548 pixbuf_cache->job_list = new_job_list;
549 pixbuf_cache->prev_job = new_prev_job;
550 pixbuf_cache->next_job = new_next_job;
552 pixbuf_cache->start_page = start_page;
553 pixbuf_cache->end_page = end_page;
556 static CacheJobInfo *
557 find_job_cache (EvPixbufCache *pixbuf_cache,
562 if (page < (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size) ||
563 page > (pixbuf_cache->end_page + pixbuf_cache->preload_cache_size))
566 if (page < pixbuf_cache->start_page) {
567 page_offset = (page - (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size));
569 g_assert (page_offset >= 0 &&
570 page_offset < pixbuf_cache->preload_cache_size);
571 return pixbuf_cache->prev_job + page_offset;
574 if (page > pixbuf_cache->end_page) {
575 page_offset = (page - (pixbuf_cache->end_page + 1));
577 g_assert (page_offset >= 0 &&
578 page_offset < pixbuf_cache->preload_cache_size);
579 return pixbuf_cache->next_job + page_offset;
582 page_offset = page - pixbuf_cache->start_page;
583 g_assert (page_offset >= 0 &&
584 page_offset <= PAGE_CACHE_LEN(pixbuf_cache));
585 return pixbuf_cache->job_list + page_offset;
589 ev_pixbuf_cache_clear_job_sizes (EvPixbufCache *pixbuf_cache,
594 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
595 check_job_size_and_unref (pixbuf_cache, pixbuf_cache->job_list + i, scale);
598 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
599 check_job_size_and_unref (pixbuf_cache, pixbuf_cache->prev_job + i, scale);
600 check_job_size_and_unref (pixbuf_cache, pixbuf_cache->next_job + i, scale);
605 get_selection_colors (GtkWidget *widget, GdkColor *text, GdkColor *base)
607 GtkStyleContext *context = gtk_widget_get_style_context (widget);
608 GtkStateFlags state = 0;
611 state |= gtk_widget_has_focus (widget) ? GTK_STATE_FLAG_SELECTED : GTK_STATE_FLAG_ACTIVE;
613 gtk_style_context_get_color (context, state, &fg);
615 text->red = CLAMP ((guint) (fg.red * 65535), 0, 65535);
616 text->green = CLAMP ((guint) (fg.green * 65535), 0, 65535);
617 text->blue = CLAMP ((guint) (fg.blue * 65535), 0, 65535);
619 gtk_style_context_get_background_color (context, state, &bg);
621 base->red = CLAMP ((guint) (bg.red * 65535), 0, 65535);
622 base->green = CLAMP ((guint) (bg.green * 65535), 0, 65535);
623 base->blue = CLAMP ((guint) (bg.blue * 65535), 0, 65535);
627 add_job (EvPixbufCache *pixbuf_cache,
628 CacheJobInfo *job_info,
629 cairo_region_t *region,
635 EvJobPriority priority)
637 job_info->page_ready = FALSE;
639 if (job_info->region)
640 cairo_region_destroy (job_info->region);
641 job_info->region = region ? cairo_region_reference (region) : NULL;
643 job_info->job = ev_job_render_new (pixbuf_cache->document,
644 page, rotation, scale,
647 if (new_selection_surface_needed (pixbuf_cache, job_info, page, scale)) {
650 get_selection_colors (pixbuf_cache->view, &text, &base);
651 ev_job_render_set_selection_info (EV_JOB_RENDER (job_info->job),
652 &(job_info->target_points),
653 job_info->selection_style,
657 g_signal_connect (job_info->job, "finished",
658 G_CALLBACK (job_finished_cb),
660 ev_job_scheduler_push_job (job_info->job, priority);
664 add_job_if_needed (EvPixbufCache *pixbuf_cache,
665 CacheJobInfo *job_info,
669 EvJobPriority priority)
676 _get_page_size_for_scale_and_rotation (pixbuf_cache->document,
677 page, scale, rotation,
680 if (job_info->surface &&
681 cairo_image_surface_get_width (job_info->surface) == width &&
682 cairo_image_surface_get_height (job_info->surface) == height)
685 /* Free old surfaces for non visible pages */
686 if (priority == EV_JOB_PRIORITY_LOW) {
687 if (job_info->surface) {
688 cairo_surface_destroy (job_info->surface);
689 job_info->surface = NULL;
692 if (job_info->selection) {
693 cairo_surface_destroy (job_info->selection);
694 job_info->selection = NULL;
698 add_job (pixbuf_cache, job_info, NULL,
699 width, height, page, rotation, scale,
704 ev_pixbuf_cache_add_jobs_if_needed (EvPixbufCache *pixbuf_cache,
708 CacheJobInfo *job_info;
712 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
713 job_info = (pixbuf_cache->job_list + i);
714 page = pixbuf_cache->start_page + i;
716 add_job_if_needed (pixbuf_cache, job_info,
717 page, rotation, scale,
718 EV_JOB_PRIORITY_URGENT);
721 for (i = FIRST_VISIBLE_PREV(pixbuf_cache); i < pixbuf_cache->preload_cache_size; i++) {
722 job_info = (pixbuf_cache->prev_job + i);
723 page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size + i;
725 add_job_if_needed (pixbuf_cache, job_info,
726 page, rotation, scale,
727 EV_JOB_PRIORITY_LOW);
730 for (i = 0; i < VISIBLE_NEXT_LEN(pixbuf_cache); i++) {
731 job_info = (pixbuf_cache->next_job + i);
732 page = pixbuf_cache->end_page + 1 + i;
734 add_job_if_needed (pixbuf_cache, job_info,
735 page, rotation, scale,
736 EV_JOB_PRIORITY_LOW);
742 ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache,
745 GList *selection_list)
747 gdouble scale = ev_document_model_get_scale (pixbuf_cache->model);
748 gint rotation = ev_document_model_get_rotation (pixbuf_cache->model);
750 g_return_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache));
752 g_return_if_fail (start_page >= 0 && start_page < ev_document_get_n_pages (pixbuf_cache->document));
753 g_return_if_fail (end_page >= 0 && end_page < ev_document_get_n_pages (pixbuf_cache->document));
754 g_return_if_fail (end_page >= start_page);
756 /* First, resize the page_range as needed. We cull old pages
758 ev_pixbuf_cache_update_range (pixbuf_cache, start_page, end_page, rotation, scale);
760 /* Then, we update the current jobs to see if any of them are the wrong
761 * size, we remove them if we need to. */
762 ev_pixbuf_cache_clear_job_sizes (pixbuf_cache, scale);
764 /* Next, we update the target selection for our pages */
765 ev_pixbuf_cache_set_selection_list (pixbuf_cache, selection_list);
767 /* Finally, we add the new jobs for all the sizes that don't have a
769 ev_pixbuf_cache_add_jobs_if_needed (pixbuf_cache, rotation, scale);
773 ev_pixbuf_cache_set_inverted_colors (EvPixbufCache *pixbuf_cache,
774 gboolean inverted_colors)
778 if (pixbuf_cache->inverted_colors == inverted_colors)
781 pixbuf_cache->inverted_colors = inverted_colors;
783 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
784 CacheJobInfo *job_info;
786 job_info = pixbuf_cache->prev_job + i;
787 if (job_info && job_info->surface)
788 ev_document_misc_invert_surface (job_info->surface);
790 job_info = pixbuf_cache->next_job + i;
791 if (job_info && job_info->surface)
792 ev_document_misc_invert_surface (job_info->surface);
795 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
796 CacheJobInfo *job_info;
798 job_info = pixbuf_cache->job_list + i;
799 if (job_info && job_info->surface)
800 ev_document_misc_invert_surface (job_info->surface);
805 ev_pixbuf_cache_get_surface (EvPixbufCache *pixbuf_cache,
808 CacheJobInfo *job_info;
810 job_info = find_job_cache (pixbuf_cache, page);
811 if (job_info == NULL)
814 if (job_info->page_ready)
815 return job_info->surface;
817 /* We don't need to wait for the idle to handle the callback */
819 EV_JOB_RENDER (job_info->job)->page_ready) {
820 copy_job_to_job_info (EV_JOB_RENDER (job_info->job), job_info, pixbuf_cache);
821 g_signal_emit (pixbuf_cache, signals[JOB_FINISHED], 0, job_info->region);
824 return job_info->surface;
828 new_selection_surface_needed (EvPixbufCache *pixbuf_cache,
829 CacheJobInfo *job_info,
833 if (job_info->selection) {
835 gint selection_width, selection_height;
837 _get_page_size_for_scale_and_rotation (pixbuf_cache->document,
841 selection_width = cairo_image_surface_get_width (job_info->selection);
842 selection_height = cairo_image_surface_get_height (job_info->selection);
844 if (width != selection_width || height != selection_height)
847 if (job_info->points_set)
855 clear_selection_if_needed (EvPixbufCache *pixbuf_cache,
856 CacheJobInfo *job_info,
860 if (new_selection_surface_needed (pixbuf_cache, job_info, page, scale)) {
861 if (job_info->selection)
862 cairo_surface_destroy (job_info->selection);
863 job_info->selection = NULL;
864 job_info->selection_points.x1 = -1;
868 /* Clears the cache of jobs and pixbufs.
871 ev_pixbuf_cache_clear (EvPixbufCache *pixbuf_cache)
875 if (!pixbuf_cache->job_list)
878 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
879 dispose_cache_job_info (pixbuf_cache->prev_job + i, pixbuf_cache);
880 dispose_cache_job_info (pixbuf_cache->next_job + i, pixbuf_cache);
883 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
884 dispose_cache_job_info (pixbuf_cache->job_list + i, pixbuf_cache);
890 ev_pixbuf_cache_style_changed (EvPixbufCache *pixbuf_cache)
894 if (!pixbuf_cache->job_list)
897 /* FIXME: doesn't update running jobs. */
898 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
899 CacheJobInfo *job_info;
901 job_info = pixbuf_cache->prev_job + i;
902 if (job_info->selection) {
903 cairo_surface_destroy (job_info->selection);
904 job_info->selection = NULL;
907 job_info = pixbuf_cache->next_job + i;
908 if (job_info->selection) {
909 cairo_surface_destroy (job_info->selection);
910 job_info->selection = NULL;
914 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
915 CacheJobInfo *job_info;
917 job_info = pixbuf_cache->job_list + i;
918 if (job_info->selection) {
919 cairo_surface_destroy (job_info->selection);
920 job_info->selection = NULL;
926 ev_pixbuf_cache_get_selection_surface (EvPixbufCache *pixbuf_cache,
929 cairo_region_t **region)
931 CacheJobInfo *job_info;
933 /* the document does not implement the selection interface */
934 if (!EV_IS_SELECTION (pixbuf_cache->document))
937 job_info = find_job_cache (pixbuf_cache, page);
938 if (job_info == NULL)
941 /* No selection on this page */
942 if (!job_info->points_set)
945 /* If we have a running job, we just return what we have under the
946 * assumption that it'll be updated later and we can scale it as need
948 if (job_info->job && EV_JOB_RENDER (job_info->job)->include_selection)
949 return job_info->selection;
951 /* Now, lets see if we need to resize the image. If we do, we clear the
953 clear_selection_if_needed (pixbuf_cache, job_info, page, scale);
955 /* Finally, we see if the two scales are the same, and get a new pixbuf
956 * if needed. We do this synchronously for now. At some point, we
957 * _should_ be able to get rid of the doc_mutex, so the synchronicity
958 * doesn't kill us. Rendering a few glyphs should really be fast.
960 if (ev_rect_cmp (&(job_info->target_points), &(job_info->selection_points))) {
961 EvRectangle *old_points;
966 /* we need to get a new selection pixbuf */
967 ev_document_doc_mutex_lock ();
968 if (job_info->selection_points.x1 < 0) {
969 g_assert (job_info->selection == NULL);
972 g_assert (job_info->selection != NULL);
973 old_points = &(job_info->selection_points);
976 ev_page = ev_document_get_page (pixbuf_cache->document, page);
977 rc = ev_render_context_new (ev_page, 0, scale);
978 g_object_unref (ev_page);
980 if (job_info->selection_region)
981 cairo_region_destroy (job_info->selection_region);
982 job_info->selection_region =
983 ev_selection_get_selection_region (EV_SELECTION (pixbuf_cache->document),
984 rc, job_info->selection_style,
985 &(job_info->target_points));
987 get_selection_colors (pixbuf_cache->view, &text, &base);
989 ev_selection_render_selection (EV_SELECTION (pixbuf_cache->document),
990 rc, &(job_info->selection),
991 &(job_info->target_points),
993 job_info->selection_style,
995 job_info->selection_points = job_info->target_points;
997 ev_document_doc_mutex_unlock ();
1000 *region = job_info->selection_region;
1001 return job_info->selection;
1005 update_job_selection (CacheJobInfo *job_info,
1006 EvViewSelection *selection)
1008 job_info->points_set = TRUE;
1009 job_info->target_points = selection->rect;
1010 job_info->selection_style = selection->style;
1014 clear_job_selection (CacheJobInfo *job_info)
1016 job_info->points_set = FALSE;
1017 job_info->selection_points.x1 = -1;
1019 if (job_info->selection) {
1020 cairo_surface_destroy (job_info->selection);
1021 job_info->selection = NULL;
1025 /* This function will reset the selection on pages that no longer have them, and
1026 * will update the target_selection on those that need it. It will _not_ free
1027 * the previous selection_list -- that's up to caller to do.
1030 ev_pixbuf_cache_set_selection_list (EvPixbufCache *pixbuf_cache,
1031 GList *selection_list)
1033 EvViewSelection *selection;
1034 GList *list = selection_list;
1038 g_return_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache));
1040 if (!EV_IS_SELECTION (pixbuf_cache->document))
1043 if (pixbuf_cache->start_page == -1 || pixbuf_cache->end_page == -1)
1046 /* We check each area to see what needs updating, and what needs freeing; */
1047 page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size;
1048 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
1056 if (((EvViewSelection *)list->data)->page == page) {
1057 selection = list->data;
1059 } else if (((EvViewSelection *)list->data)->page > page)
1065 update_job_selection (pixbuf_cache->prev_job + i, selection);
1067 clear_job_selection (pixbuf_cache->prev_job + i);
1071 page = pixbuf_cache->start_page;
1072 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
1075 if (((EvViewSelection *)list->data)->page == page) {
1076 selection = list->data;
1078 } else if (((EvViewSelection *)list->data)->page > page)
1084 update_job_selection (pixbuf_cache->job_list + i, selection);
1086 clear_job_selection (pixbuf_cache->job_list + i);
1090 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
1091 if (page >= ev_document_get_n_pages (pixbuf_cache->document))
1096 if (((EvViewSelection *)list->data)->page == page) {
1097 selection = list->data;
1099 } else if (((EvViewSelection *)list->data)->page > page)
1105 update_job_selection (pixbuf_cache->next_job + i, selection);
1107 clear_job_selection (pixbuf_cache->next_job + i);
1113 /* Returns what the pixbuf cache thinks is */
1116 ev_pixbuf_cache_get_selection_list (EvPixbufCache *pixbuf_cache)
1118 EvViewSelection *selection;
1119 GList *retval = NULL;
1123 g_return_val_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache), NULL);
1125 if (pixbuf_cache->start_page == -1 || pixbuf_cache->end_page == -1)
1128 /* We check each area to see what needs updating, and what needs freeing; */
1129 page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size;
1130 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
1136 if (pixbuf_cache->prev_job[i].selection_points.x1 != -1) {
1137 selection = g_new0 (EvViewSelection, 1);
1138 selection->page = page;
1139 selection->rect = pixbuf_cache->prev_job[i].selection_points;
1140 if (pixbuf_cache->prev_job[i].selection_region)
1141 selection->covered_region = cairo_region_reference (pixbuf_cache->prev_job[i].selection_region);
1142 retval = g_list_append (retval, selection);
1148 page = pixbuf_cache->start_page;
1149 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
1150 if (pixbuf_cache->job_list[i].selection_points.x1 != -1) {
1151 selection = g_new0 (EvViewSelection, 1);
1152 selection->page = page;
1153 selection->rect = pixbuf_cache->job_list[i].selection_points;
1154 if (pixbuf_cache->job_list[i].selection_region)
1155 selection->covered_region = cairo_region_reference (pixbuf_cache->job_list[i].selection_region);
1156 retval = g_list_append (retval, selection);
1162 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
1163 if (page >= ev_document_get_n_pages (pixbuf_cache->document))
1166 if (pixbuf_cache->next_job[i].selection_points.x1 != -1) {
1167 selection = g_new0 (EvViewSelection, 1);
1168 selection->page = page;
1169 selection->rect = pixbuf_cache->next_job[i].selection_points;
1170 if (pixbuf_cache->next_job[i].selection_region)
1171 selection->covered_region = cairo_region_reference (pixbuf_cache->next_job[i].selection_region);
1172 retval = g_list_append (retval, selection);
1182 ev_pixbuf_cache_reload_page (EvPixbufCache *pixbuf_cache,
1183 cairo_region_t *region,
1188 CacheJobInfo *job_info;
1191 job_info = find_job_cache (pixbuf_cache, page);
1192 if (job_info == NULL)
1195 _get_page_size_for_scale_and_rotation (pixbuf_cache->document,
1196 page, scale, rotation,
1198 add_job (pixbuf_cache, job_info, region,
1199 width, height, page, rotation, scale,
1200 EV_JOB_PRIORITY_URGENT);