2 #include "ev-pixbuf-cache.h"
3 #include "ev-job-scheduler.h"
4 #include "ev-mapping.h"
5 #include "ev-document-forms.h"
6 #include "ev-document-images.h"
7 #include "ev-document-annotations.h"
8 #include "ev-view-private.h"
10 typedef struct _CacheJobInfo
15 /* Region of the page that needs to be drawn */
18 /* Data we get from rendering */
19 cairo_surface_t *surface;
22 * Selection_points are the coordinates encapsulated in selection.
23 * target_points is the target selection size. */
24 EvRectangle selection_points;
25 EvRectangle target_points;
26 EvSelectionStyle selection_style;
29 cairo_surface_t *selection;
30 GdkRegion *selection_region;
37 /* We keep a link to our containing view just for style information. */
42 gboolean inverted_colors;
44 /* preload_cache_size is the number of pages prior to the current
45 * visible area that we cache. It's normally 1, but could be 2 in the
48 int preload_cache_size;
49 CacheJobInfo *prev_job;
50 CacheJobInfo *job_list;
51 CacheJobInfo *next_job;
54 struct _EvPixbufCacheClass
56 GObjectClass parent_class;
58 void (* job_finished) (EvPixbufCache *pixbuf_cache);
68 static guint signals[N_SIGNALS] = {0, };
70 static void ev_pixbuf_cache_init (EvPixbufCache *pixbuf_cache);
71 static void ev_pixbuf_cache_class_init (EvPixbufCacheClass *pixbuf_cache);
72 static void ev_pixbuf_cache_finalize (GObject *object);
73 static void ev_pixbuf_cache_dispose (GObject *object);
74 static void job_finished_cb (EvJob *job,
75 EvPixbufCache *pixbuf_cache);
76 static CacheJobInfo *find_job_cache (EvPixbufCache *pixbuf_cache,
78 static gboolean new_selection_surface_needed(EvPixbufCache *pixbuf_cache,
79 CacheJobInfo *job_info,
84 /* These are used for iterating through the prev and next arrays */
85 #define FIRST_VISIBLE_PREV(pixbuf_cache) \
86 (MAX (0, pixbuf_cache->preload_cache_size - pixbuf_cache->start_page))
87 #define VISIBLE_NEXT_LEN(pixbuf_cache) \
88 (MIN(pixbuf_cache->preload_cache_size, ev_document_get_n_pages (pixbuf_cache->document) - (1 + pixbuf_cache->end_page)))
89 #define PAGE_CACHE_LEN(pixbuf_cache) \
90 ((pixbuf_cache->end_page - pixbuf_cache->start_page) + 1)
92 G_DEFINE_TYPE (EvPixbufCache, ev_pixbuf_cache, G_TYPE_OBJECT)
95 ev_pixbuf_cache_init (EvPixbufCache *pixbuf_cache)
97 pixbuf_cache->start_page = 0;
98 pixbuf_cache->end_page = 0;
99 pixbuf_cache->job_list = g_new0 (CacheJobInfo, PAGE_CACHE_LEN (pixbuf_cache));
101 pixbuf_cache->preload_cache_size = 2;
102 pixbuf_cache->prev_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size);
103 pixbuf_cache->next_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size);
107 ev_pixbuf_cache_class_init (EvPixbufCacheClass *class)
109 GObjectClass *object_class;
111 object_class = G_OBJECT_CLASS (class);
113 object_class->finalize = ev_pixbuf_cache_finalize;
114 object_class->dispose = ev_pixbuf_cache_dispose;
116 signals[JOB_FINISHED] =
117 g_signal_new ("job-finished",
118 G_OBJECT_CLASS_TYPE (object_class),
119 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
120 G_STRUCT_OFFSET (EvPixbufCacheClass, job_finished),
122 g_cclosure_marshal_VOID__POINTER,
128 ev_pixbuf_cache_finalize (GObject *object)
130 EvPixbufCache *pixbuf_cache;
132 pixbuf_cache = EV_PIXBUF_CACHE (object);
134 g_free (pixbuf_cache->prev_job);
135 g_free (pixbuf_cache->job_list);
136 g_free (pixbuf_cache->next_job);
138 G_OBJECT_CLASS (ev_pixbuf_cache_parent_class)->finalize (object);
142 dispose_cache_job_info (CacheJobInfo *job_info,
145 if (job_info == NULL)
149 g_signal_handlers_disconnect_by_func (job_info->job,
150 G_CALLBACK (job_finished_cb),
152 ev_job_cancel (job_info->job);
153 g_object_unref (job_info->job);
154 job_info->job = NULL;
156 if (job_info->surface) {
157 cairo_surface_destroy (job_info->surface);
158 job_info->surface = NULL;
160 if (job_info->region) {
161 gdk_region_destroy (job_info->region);
162 job_info->region = NULL;
164 if (job_info->selection) {
165 cairo_surface_destroy (job_info->selection);
166 job_info->selection = NULL;
168 if (job_info->selection_region) {
169 gdk_region_destroy (job_info->selection_region);
170 job_info->selection_region = NULL;
173 job_info->points_set = FALSE;
177 ev_pixbuf_cache_dispose (GObject *object)
179 EvPixbufCache *pixbuf_cache;
182 pixbuf_cache = EV_PIXBUF_CACHE (object);
184 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
185 dispose_cache_job_info (pixbuf_cache->prev_job + i, pixbuf_cache);
186 dispose_cache_job_info (pixbuf_cache->next_job + i, pixbuf_cache);
189 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
190 dispose_cache_job_info (pixbuf_cache->job_list + i, pixbuf_cache);
193 G_OBJECT_CLASS (ev_pixbuf_cache_parent_class)->dispose (object);
198 ev_pixbuf_cache_new (GtkWidget *view,
199 EvDocument *document)
201 EvPixbufCache *pixbuf_cache;
203 pixbuf_cache = (EvPixbufCache *) g_object_new (EV_TYPE_PIXBUF_CACHE, NULL);
204 /* This is a backlink, so we don't ref this */
205 pixbuf_cache->view = view;
206 pixbuf_cache->document = document;
212 copy_job_to_job_info (EvJobRender *job_render,
213 CacheJobInfo *job_info,
214 EvPixbufCache *pixbuf_cache)
216 if (job_info->surface) {
217 cairo_surface_destroy (job_info->surface);
219 job_info->surface = cairo_surface_reference (job_render->surface);
220 if (pixbuf_cache->inverted_colors) {
221 ev_document_misc_invert_surface (job_info->surface);
224 job_info->points_set = FALSE;
225 if (job_render->include_selection) {
226 if (job_info->selection) {
227 cairo_surface_destroy (job_info->selection);
228 job_info->selection = NULL;
230 if (job_info->selection_region) {
231 gdk_region_destroy (job_info->selection_region);
232 job_info->selection_region = NULL;
235 job_info->selection_points = job_render->selection_points;
236 job_info->selection_region = gdk_region_copy (job_render->selection_region);
237 job_info->selection = cairo_surface_reference (job_render->selection);
238 g_assert (job_info->selection_points.x1 >= 0);
239 job_info->points_set = TRUE;
243 g_signal_handlers_disconnect_by_func (job_info->job,
244 G_CALLBACK (job_finished_cb),
246 ev_job_cancel (job_info->job);
247 g_object_unref (job_info->job);
248 job_info->job = NULL;
251 job_info->page_ready = TRUE;
255 job_finished_cb (EvJob *job,
256 EvPixbufCache *pixbuf_cache)
258 CacheJobInfo *job_info;
259 EvJobRender *job_render = EV_JOB_RENDER (job);
261 /* If the job is outside of our interest, we silently discard it */
262 if ((job_render->page < (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size)) ||
263 (job_render->page > (pixbuf_cache->end_page + pixbuf_cache->preload_cache_size))) {
264 g_object_unref (job);
268 job_info = find_job_cache (pixbuf_cache, job_render->page);
270 copy_job_to_job_info (job_render, job_info, pixbuf_cache);
271 g_signal_emit (pixbuf_cache, signals[JOB_FINISHED], 0, job_info->region);
274 /* This checks a job to see if the job would generate the right sized pixbuf
275 * given a scale. If it won't, it removes the job and clears it to NULL.
278 check_job_size_and_unref (EvPixbufCache *pixbuf_cache,
279 CacheJobInfo *job_info,
286 if (job_info->job == NULL)
289 _get_page_size_for_scale_and_rotation (job_info->job->document,
290 EV_JOB_RENDER (job_info->job)->page,
292 EV_JOB_RENDER (job_info->job)->rotation,
294 if (width == EV_JOB_RENDER (job_info->job)->target_width &&
295 height == EV_JOB_RENDER (job_info->job)->target_height)
298 g_signal_handlers_disconnect_by_func (job_info->job,
299 G_CALLBACK (job_finished_cb),
301 ev_job_cancel (job_info->job);
302 g_object_unref (job_info->job);
303 job_info->job = NULL;
306 /* Do all function that copies a job from an older cache to it's position in the
307 * new cache. It clears the old job if it doesn't have a place.
310 move_one_job (CacheJobInfo *job_info,
311 EvPixbufCache *pixbuf_cache,
313 CacheJobInfo *new_job_list,
314 CacheJobInfo *new_prev_job,
315 CacheJobInfo *new_next_job,
320 CacheJobInfo *target_page = NULL;
324 if (page < (start_page - pixbuf_cache->preload_cache_size) ||
325 page > (end_page + pixbuf_cache->preload_cache_size)) {
326 dispose_cache_job_info (job_info, pixbuf_cache);
330 /* find the target page to copy it over to. */
331 if (page < start_page) {
332 page_offset = (page - (start_page - pixbuf_cache->preload_cache_size));
334 g_assert (page_offset >= 0 &&
335 page_offset < pixbuf_cache->preload_cache_size);
336 target_page = new_prev_job + page_offset;
337 new_priority = EV_JOB_PRIORITY_LOW;
338 } else if (page > end_page) {
339 page_offset = (page - (end_page + 1));
341 g_assert (page_offset >= 0 &&
342 page_offset < pixbuf_cache->preload_cache_size);
343 target_page = new_next_job + page_offset;
344 new_priority = EV_JOB_PRIORITY_LOW;
346 page_offset = page - start_page;
347 g_assert (page_offset >= 0 &&
348 page_offset <= ((end_page - start_page) + 1));
349 new_priority = EV_JOB_PRIORITY_URGENT;
350 target_page = new_job_list + page_offset;
353 *target_page = *job_info;
354 job_info->job = NULL;
355 job_info->region = NULL;
356 job_info->surface = NULL;
358 if (new_priority != priority && target_page->job) {
359 ev_job_scheduler_update_job (target_page->job, new_priority);
364 ev_pixbuf_cache_update_range (EvPixbufCache *pixbuf_cache,
368 CacheJobInfo *new_job_list;
369 CacheJobInfo *new_prev_job;
370 CacheJobInfo *new_next_job;
373 if (pixbuf_cache->start_page == start_page &&
374 pixbuf_cache->end_page == end_page)
377 new_job_list = g_new0 (CacheJobInfo, (end_page - start_page) + 1);
378 new_prev_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size);
379 new_next_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size);
381 /* We go through each job in the old cache and either clear it or move
382 * it to a new location. */
384 /* Start with the prev cache. */
385 page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size;
386 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
388 dispose_cache_job_info (pixbuf_cache->prev_job + i, pixbuf_cache);
390 move_one_job (pixbuf_cache->prev_job + i,
392 new_job_list, new_prev_job, new_next_job,
393 start_page, end_page, EV_JOB_PRIORITY_LOW);
398 page = pixbuf_cache->start_page;
399 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
400 move_one_job (pixbuf_cache->job_list + i,
402 new_job_list, new_prev_job, new_next_job,
403 start_page, end_page, EV_JOB_PRIORITY_URGENT);
407 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
408 if (page >= ev_document_get_n_pages (pixbuf_cache->document)) {
409 dispose_cache_job_info (pixbuf_cache->next_job + i, pixbuf_cache);
411 move_one_job (pixbuf_cache->next_job + i,
413 new_job_list, new_prev_job, new_next_job,
414 start_page, end_page, EV_JOB_PRIORITY_LOW);
419 g_free (pixbuf_cache->job_list);
420 g_free (pixbuf_cache->prev_job);
421 g_free (pixbuf_cache->next_job);
423 pixbuf_cache->job_list = new_job_list;
424 pixbuf_cache->prev_job = new_prev_job;
425 pixbuf_cache->next_job = new_next_job;
427 pixbuf_cache->start_page = start_page;
428 pixbuf_cache->end_page = end_page;
431 static CacheJobInfo *
432 find_job_cache (EvPixbufCache *pixbuf_cache,
437 if (page < (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size) ||
438 page > (pixbuf_cache->end_page + pixbuf_cache->preload_cache_size))
441 if (page < pixbuf_cache->start_page) {
442 page_offset = (page - (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size));
444 g_assert (page_offset >= 0 &&
445 page_offset < pixbuf_cache->preload_cache_size);
446 return pixbuf_cache->prev_job + page_offset;
449 if (page > pixbuf_cache->end_page) {
450 page_offset = (page - (pixbuf_cache->end_page + 1));
452 g_assert (page_offset >= 0 &&
453 page_offset < pixbuf_cache->preload_cache_size);
454 return pixbuf_cache->next_job + page_offset;
457 page_offset = page - pixbuf_cache->start_page;
458 g_assert (page_offset >= 0 &&
459 page_offset <= PAGE_CACHE_LEN(pixbuf_cache));
460 return pixbuf_cache->job_list + page_offset;
464 ev_pixbuf_cache_clear_job_sizes (EvPixbufCache *pixbuf_cache,
469 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
470 check_job_size_and_unref (pixbuf_cache, pixbuf_cache->job_list + i, scale);
473 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
474 check_job_size_and_unref (pixbuf_cache, pixbuf_cache->prev_job + i, scale);
475 check_job_size_and_unref (pixbuf_cache, pixbuf_cache->next_job + i, scale);
480 get_selection_colors (GtkWidget *widget, GdkColor **text, GdkColor **base)
482 GtkStyle *style = gtk_widget_get_style (widget);
484 if (gtk_widget_has_focus (widget)) {
485 *text = &style->text [GTK_STATE_SELECTED];
486 *base = &style->base [GTK_STATE_SELECTED];
488 *text = &style->text [GTK_STATE_ACTIVE];
489 *base = &style->base [GTK_STATE_ACTIVE];
494 add_job (EvPixbufCache *pixbuf_cache,
495 CacheJobInfo *job_info,
502 EvJobPriority priority)
504 job_info->page_ready = FALSE;
506 if (job_info->region)
507 gdk_region_destroy (job_info->region);
508 job_info->region = region ? gdk_region_copy (region) : NULL;
510 job_info->job = ev_job_render_new (pixbuf_cache->document,
511 page, rotation, scale,
514 if (new_selection_surface_needed (pixbuf_cache, job_info, page, scale)) {
515 GdkColor *text, *base;
517 gtk_widget_ensure_style (pixbuf_cache->view);
518 get_selection_colors (pixbuf_cache->view, &text, &base);
519 ev_job_render_set_selection_info (EV_JOB_RENDER (job_info->job),
520 &(job_info->target_points),
521 job_info->selection_style,
525 g_signal_connect (job_info->job, "finished",
526 G_CALLBACK (job_finished_cb),
528 ev_job_scheduler_push_job (job_info->job, priority);
532 add_job_if_needed (EvPixbufCache *pixbuf_cache,
533 CacheJobInfo *job_info,
537 EvJobPriority priority)
544 _get_page_size_for_scale_and_rotation (pixbuf_cache->document,
545 page, scale, rotation,
548 if (job_info->surface &&
549 cairo_image_surface_get_width (job_info->surface) == width &&
550 cairo_image_surface_get_height (job_info->surface) == height)
553 add_job (pixbuf_cache, job_info, NULL,
554 width, height, page, rotation, scale,
559 ev_pixbuf_cache_add_jobs_if_needed (EvPixbufCache *pixbuf_cache,
563 CacheJobInfo *job_info;
567 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
568 job_info = (pixbuf_cache->job_list + i);
569 page = pixbuf_cache->start_page + i;
571 add_job_if_needed (pixbuf_cache, job_info,
572 page, rotation, scale,
573 EV_JOB_PRIORITY_URGENT);
576 for (i = FIRST_VISIBLE_PREV(pixbuf_cache); i < pixbuf_cache->preload_cache_size; i++) {
577 job_info = (pixbuf_cache->prev_job + i);
578 page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size + i;
580 add_job_if_needed (pixbuf_cache, job_info,
581 page, rotation, scale,
582 EV_JOB_PRIORITY_LOW);
585 for (i = 0; i < VISIBLE_NEXT_LEN(pixbuf_cache); i++) {
586 job_info = (pixbuf_cache->next_job + i);
587 page = pixbuf_cache->end_page + 1 + i;
589 add_job_if_needed (pixbuf_cache, job_info,
590 page, rotation, scale,
591 EV_JOB_PRIORITY_LOW);
597 ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache,
602 GList *selection_list)
604 g_return_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache));
606 g_return_if_fail (start_page >= 0 && start_page < ev_document_get_n_pages (pixbuf_cache->document));
607 g_return_if_fail (end_page >= 0 && end_page < ev_document_get_n_pages (pixbuf_cache->document));
608 g_return_if_fail (end_page >= start_page);
610 /* First, resize the page_range as needed. We cull old pages
612 ev_pixbuf_cache_update_range (pixbuf_cache, start_page, end_page);
614 /* Then, we update the current jobs to see if any of them are the wrong
615 * size, we remove them if we need to. */
616 ev_pixbuf_cache_clear_job_sizes (pixbuf_cache, scale);
618 /* Next, we update the target selection for our pages */
619 ev_pixbuf_cache_set_selection_list (pixbuf_cache, selection_list);
621 /* Finally, we add the new jobs for all the sizes that don't have a
623 ev_pixbuf_cache_add_jobs_if_needed (pixbuf_cache, rotation, scale);
627 ev_pixbuf_cache_set_inverted_colors (EvPixbufCache *pixbuf_cache,
628 gboolean inverted_colors)
632 if (pixbuf_cache->inverted_colors == inverted_colors)
635 pixbuf_cache->inverted_colors = inverted_colors;
637 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
638 CacheJobInfo *job_info;
640 job_info = pixbuf_cache->prev_job + i;
641 if (job_info->surface)
642 ev_document_misc_invert_surface (job_info->surface);
644 job_info = pixbuf_cache->next_job + i;
645 if (job_info->surface)
646 ev_document_misc_invert_surface (job_info->surface);
649 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
650 CacheJobInfo *job_info;
652 job_info = pixbuf_cache->job_list + i;
653 if (job_info->surface)
654 ev_document_misc_invert_surface (job_info->surface);
659 ev_pixbuf_cache_get_surface (EvPixbufCache *pixbuf_cache,
662 CacheJobInfo *job_info;
664 job_info = find_job_cache (pixbuf_cache, page);
665 if (job_info == NULL)
668 if (job_info->page_ready)
669 return job_info->surface;
671 /* We don't need to wait for the idle to handle the callback */
673 EV_JOB_RENDER (job_info->job)->page_ready) {
674 copy_job_to_job_info (EV_JOB_RENDER (job_info->job), job_info, pixbuf_cache);
675 g_signal_emit (pixbuf_cache, signals[JOB_FINISHED], 0, job_info->region);
678 return job_info->surface;
682 new_selection_surface_needed (EvPixbufCache *pixbuf_cache,
683 CacheJobInfo *job_info,
687 if (job_info->selection) {
689 gint selection_width, selection_height;
691 _get_page_size_for_scale_and_rotation (pixbuf_cache->document,
695 selection_width = cairo_image_surface_get_width (job_info->selection);
696 selection_height = cairo_image_surface_get_height (job_info->selection);
698 if (width != selection_width || height != selection_height)
701 if (job_info->points_set)
709 clear_selection_if_needed (EvPixbufCache *pixbuf_cache,
710 CacheJobInfo *job_info,
714 if (new_selection_surface_needed (pixbuf_cache, job_info, page, scale)) {
715 if (job_info->selection)
716 cairo_surface_destroy (job_info->selection);
717 job_info->selection = NULL;
718 job_info->selection_points.x1 = -1;
722 /* Clears the cache of jobs and pixbufs.
725 ev_pixbuf_cache_clear (EvPixbufCache *pixbuf_cache)
729 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
730 dispose_cache_job_info (pixbuf_cache->prev_job + i, pixbuf_cache);
731 dispose_cache_job_info (pixbuf_cache->next_job + i, pixbuf_cache);
734 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
735 dispose_cache_job_info (pixbuf_cache->job_list + i, pixbuf_cache);
741 ev_pixbuf_cache_style_changed (EvPixbufCache *pixbuf_cache)
745 /* FIXME: doesn't update running jobs. */
746 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
747 CacheJobInfo *job_info;
749 job_info = pixbuf_cache->prev_job + i;
750 if (job_info->selection) {
751 cairo_surface_destroy (job_info->selection);
752 job_info->selection = NULL;
755 job_info = pixbuf_cache->next_job + i;
756 if (job_info->selection) {
757 cairo_surface_destroy (job_info->selection);
758 job_info->selection = NULL;
762 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
763 CacheJobInfo *job_info;
765 job_info = pixbuf_cache->job_list + i;
766 if (job_info->selection) {
767 cairo_surface_destroy (job_info->selection);
768 job_info->selection = NULL;
774 ev_pixbuf_cache_get_selection_surface (EvPixbufCache *pixbuf_cache,
779 CacheJobInfo *job_info;
781 /* the document does not implement the selection interface */
782 if (!EV_IS_SELECTION (pixbuf_cache->document))
785 job_info = find_job_cache (pixbuf_cache, page);
786 if (job_info == NULL)
789 /* No selection on this page */
790 if (!job_info->points_set)
793 /* If we have a running job, we just return what we have under the
794 * assumption that it'll be updated later and we can scale it as need
796 if (job_info->job && EV_JOB_RENDER (job_info->job)->include_selection)
797 return job_info->selection;
799 /* Now, lets see if we need to resize the image. If we do, we clear the
801 clear_selection_if_needed (pixbuf_cache, job_info, page, scale);
803 /* Finally, we see if the two scales are the same, and get a new pixbuf
804 * if needed. We do this synchronously for now. At some point, we
805 * _should_ be able to get rid of the doc_mutex, so the synchronicity
806 * doesn't kill us. Rendering a few glyphs should really be fast.
808 if (ev_rect_cmp (&(job_info->target_points), &(job_info->selection_points))) {
809 EvRectangle *old_points;
810 GdkColor *text, *base;
814 /* we need to get a new selection pixbuf */
815 ev_document_doc_mutex_lock ();
816 if (job_info->selection_points.x1 < 0) {
817 g_assert (job_info->selection == NULL);
820 g_assert (job_info->selection != NULL);
821 old_points = &(job_info->selection_points);
824 ev_page = ev_document_get_page (pixbuf_cache->document, page);
825 rc = ev_render_context_new (ev_page, 0, scale);
826 g_object_unref (ev_page);
828 if (job_info->selection_region)
829 gdk_region_destroy (job_info->selection_region);
830 job_info->selection_region =
831 ev_selection_get_selection_region (EV_SELECTION (pixbuf_cache->document),
832 rc, job_info->selection_style,
833 &(job_info->target_points));
835 gtk_widget_ensure_style (pixbuf_cache->view);
837 get_selection_colors (pixbuf_cache->view, &text, &base);
839 ev_selection_render_selection (EV_SELECTION (pixbuf_cache->document),
840 rc, &(job_info->selection),
841 &(job_info->target_points),
843 job_info->selection_style,
845 job_info->selection_points = job_info->target_points;
847 ev_document_doc_mutex_unlock ();
850 *region = job_info->selection_region;
851 return job_info->selection;
855 update_job_selection (CacheJobInfo *job_info,
856 EvViewSelection *selection)
858 job_info->points_set = TRUE;
859 job_info->target_points = selection->rect;
860 job_info->selection_style = selection->style;
864 clear_job_selection (CacheJobInfo *job_info)
866 job_info->points_set = FALSE;
867 job_info->selection_points.x1 = -1;
869 if (job_info->selection) {
870 cairo_surface_destroy (job_info->selection);
871 job_info->selection = NULL;
875 /* This function will reset the selection on pages that no longer have them, and
876 * will update the target_selection on those that need it. It will _not_ free
877 * the previous selection_list -- that's up to caller to do.
880 ev_pixbuf_cache_set_selection_list (EvPixbufCache *pixbuf_cache,
881 GList *selection_list)
883 EvViewSelection *selection;
884 GList *list = selection_list;
888 g_return_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache));
890 if (!EV_IS_SELECTION (pixbuf_cache->document))
893 /* We check each area to see what needs updating, and what needs freeing; */
894 page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size;
895 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
903 if (((EvViewSelection *)list->data)->page == page) {
904 selection = list->data;
906 } else if (((EvViewSelection *)list->data)->page > page)
912 update_job_selection (pixbuf_cache->prev_job + i, selection);
914 clear_job_selection (pixbuf_cache->prev_job + i);
918 page = pixbuf_cache->start_page;
919 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
922 if (((EvViewSelection *)list->data)->page == page) {
923 selection = list->data;
925 } else if (((EvViewSelection *)list->data)->page > page)
931 update_job_selection (pixbuf_cache->job_list + i, selection);
933 clear_job_selection (pixbuf_cache->job_list + i);
937 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
938 if (page >= ev_document_get_n_pages (pixbuf_cache->document))
943 if (((EvViewSelection *)list->data)->page == page) {
944 selection = list->data;
946 } else if (((EvViewSelection *)list->data)->page > page)
952 update_job_selection (pixbuf_cache->next_job + i, selection);
954 clear_job_selection (pixbuf_cache->next_job + i);
960 /* Returns what the pixbuf cache thinks is */
963 ev_pixbuf_cache_get_selection_list (EvPixbufCache *pixbuf_cache)
965 EvViewSelection *selection;
966 GList *retval = NULL;
970 g_return_val_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache), NULL);
972 /* We check each area to see what needs updating, and what needs freeing; */
973 page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size;
974 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
980 if (pixbuf_cache->prev_job[i].selection_points.x1 != -1) {
981 selection = g_new0 (EvViewSelection, 1);
982 selection->page = page;
983 selection->rect = pixbuf_cache->prev_job[i].selection_points;
984 if (pixbuf_cache->prev_job[i].selection_region)
985 selection->covered_region = gdk_region_copy (pixbuf_cache->prev_job[i].selection_region);
986 retval = g_list_append (retval, selection);
992 page = pixbuf_cache->start_page;
993 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
994 if (pixbuf_cache->job_list[i].selection_points.x1 != -1) {
995 selection = g_new0 (EvViewSelection, 1);
996 selection->page = page;
997 selection->rect = pixbuf_cache->job_list[i].selection_points;
998 if (pixbuf_cache->job_list[i].selection_region)
999 selection->covered_region = gdk_region_copy (pixbuf_cache->job_list[i].selection_region);
1000 retval = g_list_append (retval, selection);
1006 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
1007 if (page >= ev_document_get_n_pages (pixbuf_cache->document))
1010 if (pixbuf_cache->next_job[i].selection_points.x1 != -1) {
1011 selection = g_new0 (EvViewSelection, 1);
1012 selection->page = page;
1013 selection->rect = pixbuf_cache->next_job[i].selection_points;
1014 if (pixbuf_cache->next_job[i].selection_region)
1015 selection->covered_region = gdk_region_copy (pixbuf_cache->next_job[i].selection_region);
1016 retval = g_list_append (retval, selection);
1026 ev_pixbuf_cache_reload_page (EvPixbufCache *pixbuf_cache,
1032 CacheJobInfo *job_info;
1035 job_info = find_job_cache (pixbuf_cache, page);
1036 if (job_info == NULL)
1039 _get_page_size_for_scale_and_rotation (pixbuf_cache->document,
1040 page, scale, rotation,
1042 add_job (pixbuf_cache, job_info, region,
1043 width, height, page, rotation, scale,
1044 EV_JOB_PRIORITY_URGENT);