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 GtkStyle *style = gtk_widget_get_style (widget);
609 if (gtk_widget_has_focus (widget)) {
610 *text = &style->text [GTK_STATE_SELECTED];
611 *base = &style->base [GTK_STATE_SELECTED];
613 *text = &style->text [GTK_STATE_ACTIVE];
614 *base = &style->base [GTK_STATE_ACTIVE];
619 add_job (EvPixbufCache *pixbuf_cache,
620 CacheJobInfo *job_info,
621 cairo_region_t *region,
627 EvJobPriority priority)
629 job_info->page_ready = FALSE;
631 if (job_info->region)
632 cairo_region_destroy (job_info->region);
633 job_info->region = region ? cairo_region_reference (region) : NULL;
635 job_info->job = ev_job_render_new (pixbuf_cache->document,
636 page, rotation, scale,
639 if (new_selection_surface_needed (pixbuf_cache, job_info, page, scale)) {
640 GdkColor *text, *base;
642 gtk_widget_ensure_style (pixbuf_cache->view);
643 get_selection_colors (pixbuf_cache->view, &text, &base);
644 ev_job_render_set_selection_info (EV_JOB_RENDER (job_info->job),
645 &(job_info->target_points),
646 job_info->selection_style,
650 g_signal_connect (job_info->job, "finished",
651 G_CALLBACK (job_finished_cb),
653 ev_job_scheduler_push_job (job_info->job, priority);
657 add_job_if_needed (EvPixbufCache *pixbuf_cache,
658 CacheJobInfo *job_info,
662 EvJobPriority priority)
669 _get_page_size_for_scale_and_rotation (pixbuf_cache->document,
670 page, scale, rotation,
673 if (job_info->surface &&
674 cairo_image_surface_get_width (job_info->surface) == width &&
675 cairo_image_surface_get_height (job_info->surface) == height)
678 /* Free old surfaces for non visible pages */
679 if (priority == EV_JOB_PRIORITY_LOW) {
680 if (job_info->surface) {
681 cairo_surface_destroy (job_info->surface);
682 job_info->surface = NULL;
685 if (job_info->selection) {
686 cairo_surface_destroy (job_info->selection);
687 job_info->selection = NULL;
691 add_job (pixbuf_cache, job_info, NULL,
692 width, height, page, rotation, scale,
697 ev_pixbuf_cache_add_jobs_if_needed (EvPixbufCache *pixbuf_cache,
701 CacheJobInfo *job_info;
705 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
706 job_info = (pixbuf_cache->job_list + i);
707 page = pixbuf_cache->start_page + i;
709 add_job_if_needed (pixbuf_cache, job_info,
710 page, rotation, scale,
711 EV_JOB_PRIORITY_URGENT);
714 for (i = FIRST_VISIBLE_PREV(pixbuf_cache); i < pixbuf_cache->preload_cache_size; i++) {
715 job_info = (pixbuf_cache->prev_job + i);
716 page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size + i;
718 add_job_if_needed (pixbuf_cache, job_info,
719 page, rotation, scale,
720 EV_JOB_PRIORITY_LOW);
723 for (i = 0; i < VISIBLE_NEXT_LEN(pixbuf_cache); i++) {
724 job_info = (pixbuf_cache->next_job + i);
725 page = pixbuf_cache->end_page + 1 + i;
727 add_job_if_needed (pixbuf_cache, job_info,
728 page, rotation, scale,
729 EV_JOB_PRIORITY_LOW);
735 ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache,
738 GList *selection_list)
740 gdouble scale = ev_document_model_get_scale (pixbuf_cache->model);
741 gint rotation = ev_document_model_get_rotation (pixbuf_cache->model);
743 g_return_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache));
745 g_return_if_fail (start_page >= 0 && start_page < ev_document_get_n_pages (pixbuf_cache->document));
746 g_return_if_fail (end_page >= 0 && end_page < ev_document_get_n_pages (pixbuf_cache->document));
747 g_return_if_fail (end_page >= start_page);
749 /* First, resize the page_range as needed. We cull old pages
751 ev_pixbuf_cache_update_range (pixbuf_cache, start_page, end_page, rotation, scale);
753 /* Then, we update the current jobs to see if any of them are the wrong
754 * size, we remove them if we need to. */
755 ev_pixbuf_cache_clear_job_sizes (pixbuf_cache, scale);
757 /* Next, we update the target selection for our pages */
758 ev_pixbuf_cache_set_selection_list (pixbuf_cache, selection_list);
760 /* Finally, we add the new jobs for all the sizes that don't have a
762 ev_pixbuf_cache_add_jobs_if_needed (pixbuf_cache, rotation, scale);
766 ev_pixbuf_cache_set_inverted_colors (EvPixbufCache *pixbuf_cache,
767 gboolean inverted_colors)
771 if (pixbuf_cache->inverted_colors == inverted_colors)
774 pixbuf_cache->inverted_colors = inverted_colors;
776 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
777 CacheJobInfo *job_info;
779 job_info = pixbuf_cache->prev_job + i;
780 if (job_info->surface)
781 ev_document_misc_invert_surface (job_info->surface);
783 job_info = pixbuf_cache->next_job + i;
784 if (job_info->surface)
785 ev_document_misc_invert_surface (job_info->surface);
788 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
789 CacheJobInfo *job_info;
791 job_info = pixbuf_cache->job_list + i;
792 if (job_info->surface)
793 ev_document_misc_invert_surface (job_info->surface);
798 ev_pixbuf_cache_get_surface (EvPixbufCache *pixbuf_cache,
801 CacheJobInfo *job_info;
803 job_info = find_job_cache (pixbuf_cache, page);
804 if (job_info == NULL)
807 if (job_info->page_ready)
808 return job_info->surface;
810 /* We don't need to wait for the idle to handle the callback */
812 EV_JOB_RENDER (job_info->job)->page_ready) {
813 copy_job_to_job_info (EV_JOB_RENDER (job_info->job), job_info, pixbuf_cache);
814 g_signal_emit (pixbuf_cache, signals[JOB_FINISHED], 0, job_info->region);
817 return job_info->surface;
821 new_selection_surface_needed (EvPixbufCache *pixbuf_cache,
822 CacheJobInfo *job_info,
826 if (job_info->selection) {
828 gint selection_width, selection_height;
830 _get_page_size_for_scale_and_rotation (pixbuf_cache->document,
834 selection_width = cairo_image_surface_get_width (job_info->selection);
835 selection_height = cairo_image_surface_get_height (job_info->selection);
837 if (width != selection_width || height != selection_height)
840 if (job_info->points_set)
848 clear_selection_if_needed (EvPixbufCache *pixbuf_cache,
849 CacheJobInfo *job_info,
853 if (new_selection_surface_needed (pixbuf_cache, job_info, page, scale)) {
854 if (job_info->selection)
855 cairo_surface_destroy (job_info->selection);
856 job_info->selection = NULL;
857 job_info->selection_points.x1 = -1;
861 /* Clears the cache of jobs and pixbufs.
864 ev_pixbuf_cache_clear (EvPixbufCache *pixbuf_cache)
868 if (!pixbuf_cache->job_list)
871 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
872 dispose_cache_job_info (pixbuf_cache->prev_job + i, pixbuf_cache);
873 dispose_cache_job_info (pixbuf_cache->next_job + i, pixbuf_cache);
876 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
877 dispose_cache_job_info (pixbuf_cache->job_list + i, pixbuf_cache);
883 ev_pixbuf_cache_style_changed (EvPixbufCache *pixbuf_cache)
887 if (!pixbuf_cache->job_list)
890 /* FIXME: doesn't update running jobs. */
891 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
892 CacheJobInfo *job_info;
894 job_info = pixbuf_cache->prev_job + i;
895 if (job_info->selection) {
896 cairo_surface_destroy (job_info->selection);
897 job_info->selection = NULL;
900 job_info = pixbuf_cache->next_job + i;
901 if (job_info->selection) {
902 cairo_surface_destroy (job_info->selection);
903 job_info->selection = NULL;
907 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
908 CacheJobInfo *job_info;
910 job_info = pixbuf_cache->job_list + i;
911 if (job_info->selection) {
912 cairo_surface_destroy (job_info->selection);
913 job_info->selection = NULL;
919 ev_pixbuf_cache_get_selection_surface (EvPixbufCache *pixbuf_cache,
922 cairo_region_t **region)
924 CacheJobInfo *job_info;
926 /* the document does not implement the selection interface */
927 if (!EV_IS_SELECTION (pixbuf_cache->document))
930 job_info = find_job_cache (pixbuf_cache, page);
931 if (job_info == NULL)
934 /* No selection on this page */
935 if (!job_info->points_set)
938 /* If we have a running job, we just return what we have under the
939 * assumption that it'll be updated later and we can scale it as need
941 if (job_info->job && EV_JOB_RENDER (job_info->job)->include_selection)
942 return job_info->selection;
944 /* Now, lets see if we need to resize the image. If we do, we clear the
946 clear_selection_if_needed (pixbuf_cache, job_info, page, scale);
948 /* Finally, we see if the two scales are the same, and get a new pixbuf
949 * if needed. We do this synchronously for now. At some point, we
950 * _should_ be able to get rid of the doc_mutex, so the synchronicity
951 * doesn't kill us. Rendering a few glyphs should really be fast.
953 if (ev_rect_cmp (&(job_info->target_points), &(job_info->selection_points))) {
954 EvRectangle *old_points;
955 GdkColor *text, *base;
959 /* we need to get a new selection pixbuf */
960 ev_document_doc_mutex_lock ();
961 if (job_info->selection_points.x1 < 0) {
962 g_assert (job_info->selection == NULL);
965 g_assert (job_info->selection != NULL);
966 old_points = &(job_info->selection_points);
969 ev_page = ev_document_get_page (pixbuf_cache->document, page);
970 rc = ev_render_context_new (ev_page, 0, scale);
971 g_object_unref (ev_page);
973 if (job_info->selection_region)
974 cairo_region_destroy (job_info->selection_region);
975 job_info->selection_region =
976 ev_selection_get_selection_region (EV_SELECTION (pixbuf_cache->document),
977 rc, job_info->selection_style,
978 &(job_info->target_points));
980 gtk_widget_ensure_style (pixbuf_cache->view);
982 get_selection_colors (pixbuf_cache->view, &text, &base);
984 ev_selection_render_selection (EV_SELECTION (pixbuf_cache->document),
985 rc, &(job_info->selection),
986 &(job_info->target_points),
988 job_info->selection_style,
990 job_info->selection_points = job_info->target_points;
992 ev_document_doc_mutex_unlock ();
995 *region = job_info->selection_region;
996 return job_info->selection;
1000 update_job_selection (CacheJobInfo *job_info,
1001 EvViewSelection *selection)
1003 job_info->points_set = TRUE;
1004 job_info->target_points = selection->rect;
1005 job_info->selection_style = selection->style;
1009 clear_job_selection (CacheJobInfo *job_info)
1011 job_info->points_set = FALSE;
1012 job_info->selection_points.x1 = -1;
1014 if (job_info->selection) {
1015 cairo_surface_destroy (job_info->selection);
1016 job_info->selection = NULL;
1020 /* This function will reset the selection on pages that no longer have them, and
1021 * will update the target_selection on those that need it. It will _not_ free
1022 * the previous selection_list -- that's up to caller to do.
1025 ev_pixbuf_cache_set_selection_list (EvPixbufCache *pixbuf_cache,
1026 GList *selection_list)
1028 EvViewSelection *selection;
1029 GList *list = selection_list;
1033 g_return_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache));
1035 if (!EV_IS_SELECTION (pixbuf_cache->document))
1038 /* We check each area to see what needs updating, and what needs freeing; */
1039 page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size;
1040 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
1048 if (((EvViewSelection *)list->data)->page == page) {
1049 selection = list->data;
1051 } else if (((EvViewSelection *)list->data)->page > page)
1057 update_job_selection (pixbuf_cache->prev_job + i, selection);
1059 clear_job_selection (pixbuf_cache->prev_job + i);
1063 page = pixbuf_cache->start_page;
1064 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
1067 if (((EvViewSelection *)list->data)->page == page) {
1068 selection = list->data;
1070 } else if (((EvViewSelection *)list->data)->page > page)
1076 update_job_selection (pixbuf_cache->job_list + i, selection);
1078 clear_job_selection (pixbuf_cache->job_list + i);
1082 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
1083 if (page >= ev_document_get_n_pages (pixbuf_cache->document))
1088 if (((EvViewSelection *)list->data)->page == page) {
1089 selection = list->data;
1091 } else if (((EvViewSelection *)list->data)->page > page)
1097 update_job_selection (pixbuf_cache->next_job + i, selection);
1099 clear_job_selection (pixbuf_cache->next_job + i);
1105 /* Returns what the pixbuf cache thinks is */
1108 ev_pixbuf_cache_get_selection_list (EvPixbufCache *pixbuf_cache)
1110 EvViewSelection *selection;
1111 GList *retval = NULL;
1115 g_return_val_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache), NULL);
1117 /* We check each area to see what needs updating, and what needs freeing; */
1118 page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size;
1119 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
1125 if (pixbuf_cache->prev_job[i].selection_points.x1 != -1) {
1126 selection = g_new0 (EvViewSelection, 1);
1127 selection->page = page;
1128 selection->rect = pixbuf_cache->prev_job[i].selection_points;
1129 if (pixbuf_cache->prev_job[i].selection_region)
1130 selection->covered_region = cairo_region_reference (pixbuf_cache->prev_job[i].selection_region);
1131 retval = g_list_append (retval, selection);
1137 page = pixbuf_cache->start_page;
1138 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
1139 if (pixbuf_cache->job_list[i].selection_points.x1 != -1) {
1140 selection = g_new0 (EvViewSelection, 1);
1141 selection->page = page;
1142 selection->rect = pixbuf_cache->job_list[i].selection_points;
1143 if (pixbuf_cache->job_list[i].selection_region)
1144 selection->covered_region = cairo_region_reference (pixbuf_cache->job_list[i].selection_region);
1145 retval = g_list_append (retval, selection);
1151 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
1152 if (page >= ev_document_get_n_pages (pixbuf_cache->document))
1155 if (pixbuf_cache->next_job[i].selection_points.x1 != -1) {
1156 selection = g_new0 (EvViewSelection, 1);
1157 selection->page = page;
1158 selection->rect = pixbuf_cache->next_job[i].selection_points;
1159 if (pixbuf_cache->next_job[i].selection_region)
1160 selection->covered_region = cairo_region_reference (pixbuf_cache->next_job[i].selection_region);
1161 retval = g_list_append (retval, selection);
1171 ev_pixbuf_cache_reload_page (EvPixbufCache *pixbuf_cache,
1172 cairo_region_t *region,
1177 CacheJobInfo *job_info;
1180 job_info = find_job_cache (pixbuf_cache, page);
1181 if (job_info == NULL)
1184 _get_page_size_for_scale_and_rotation (pixbuf_cache->document,
1185 page, scale, rotation,
1187 add_job (pixbuf_cache, job_info, region,
1188 width, height, page, rotation, scale,
1189 EV_JOB_PRIORITY_URGENT);