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 if (gtk_widget_has_focus (widget)) {
483 *text = &widget->style->text [GTK_STATE_SELECTED];
484 *base = &widget->style->base [GTK_STATE_SELECTED];
486 *text = &widget->style->text [GTK_STATE_ACTIVE];
487 *base = &widget->style->base [GTK_STATE_ACTIVE];
492 add_job (EvPixbufCache *pixbuf_cache,
493 CacheJobInfo *job_info,
500 EvJobPriority priority)
502 job_info->page_ready = FALSE;
504 if (job_info->region)
505 gdk_region_destroy (job_info->region);
506 job_info->region = region ? gdk_region_copy (region) : NULL;
508 job_info->job = ev_job_render_new (pixbuf_cache->document,
509 page, rotation, scale,
512 if (new_selection_surface_needed (pixbuf_cache, job_info, page, scale)) {
513 GdkColor *text, *base;
515 gtk_widget_ensure_style (pixbuf_cache->view);
516 get_selection_colors (pixbuf_cache->view, &text, &base);
517 ev_job_render_set_selection_info (EV_JOB_RENDER (job_info->job),
518 &(job_info->target_points),
519 job_info->selection_style,
523 g_signal_connect (job_info->job, "finished",
524 G_CALLBACK (job_finished_cb),
526 ev_job_scheduler_push_job (job_info->job, priority);
530 add_job_if_needed (EvPixbufCache *pixbuf_cache,
531 CacheJobInfo *job_info,
535 EvJobPriority priority)
542 _get_page_size_for_scale_and_rotation (pixbuf_cache->document,
543 page, scale, rotation,
546 if (job_info->surface &&
547 cairo_image_surface_get_width (job_info->surface) == width &&
548 cairo_image_surface_get_height (job_info->surface) == height)
551 add_job (pixbuf_cache, job_info, NULL,
552 width, height, page, rotation, scale,
557 ev_pixbuf_cache_add_jobs_if_needed (EvPixbufCache *pixbuf_cache,
561 CacheJobInfo *job_info;
565 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
566 job_info = (pixbuf_cache->job_list + i);
567 page = pixbuf_cache->start_page + i;
569 add_job_if_needed (pixbuf_cache, job_info,
570 page, rotation, scale,
571 EV_JOB_PRIORITY_URGENT);
574 for (i = FIRST_VISIBLE_PREV(pixbuf_cache); i < pixbuf_cache->preload_cache_size; i++) {
575 job_info = (pixbuf_cache->prev_job + i);
576 page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size + i;
578 add_job_if_needed (pixbuf_cache, job_info,
579 page, rotation, scale,
580 EV_JOB_PRIORITY_LOW);
583 for (i = 0; i < VISIBLE_NEXT_LEN(pixbuf_cache); i++) {
584 job_info = (pixbuf_cache->next_job + i);
585 page = pixbuf_cache->end_page + 1 + i;
587 add_job_if_needed (pixbuf_cache, job_info,
588 page, rotation, scale,
589 EV_JOB_PRIORITY_LOW);
595 ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache,
600 GList *selection_list)
602 g_return_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache));
604 g_return_if_fail (start_page >= 0 && start_page < ev_document_get_n_pages (pixbuf_cache->document));
605 g_return_if_fail (end_page >= 0 && end_page < ev_document_get_n_pages (pixbuf_cache->document));
606 g_return_if_fail (end_page >= start_page);
608 /* First, resize the page_range as needed. We cull old pages
610 ev_pixbuf_cache_update_range (pixbuf_cache, start_page, end_page);
612 /* Then, we update the current jobs to see if any of them are the wrong
613 * size, we remove them if we need to. */
614 ev_pixbuf_cache_clear_job_sizes (pixbuf_cache, scale);
616 /* Next, we update the target selection for our pages */
617 ev_pixbuf_cache_set_selection_list (pixbuf_cache, selection_list);
619 /* Finally, we add the new jobs for all the sizes that don't have a
621 ev_pixbuf_cache_add_jobs_if_needed (pixbuf_cache, rotation, scale);
625 ev_pixbuf_cache_set_inverted_colors (EvPixbufCache *pixbuf_cache,
626 gboolean inverted_colors)
630 if (pixbuf_cache->inverted_colors == inverted_colors)
633 pixbuf_cache->inverted_colors = inverted_colors;
635 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
636 CacheJobInfo *job_info;
638 job_info = pixbuf_cache->prev_job + i;
639 if (job_info->surface)
640 ev_document_misc_invert_surface (job_info->surface);
642 job_info = pixbuf_cache->next_job + i;
643 if (job_info->surface)
644 ev_document_misc_invert_surface (job_info->surface);
647 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
648 CacheJobInfo *job_info;
650 job_info = pixbuf_cache->job_list + i;
651 if (job_info->surface)
652 ev_document_misc_invert_surface (job_info->surface);
657 ev_pixbuf_cache_get_surface (EvPixbufCache *pixbuf_cache,
660 CacheJobInfo *job_info;
662 job_info = find_job_cache (pixbuf_cache, page);
663 if (job_info == NULL)
666 if (job_info->page_ready)
667 return job_info->surface;
669 /* We don't need to wait for the idle to handle the callback */
671 EV_JOB_RENDER (job_info->job)->page_ready) {
672 copy_job_to_job_info (EV_JOB_RENDER (job_info->job), job_info, pixbuf_cache);
673 g_signal_emit (pixbuf_cache, signals[JOB_FINISHED], 0, job_info->region);
676 return job_info->surface;
680 new_selection_surface_needed (EvPixbufCache *pixbuf_cache,
681 CacheJobInfo *job_info,
685 if (job_info->selection) {
687 gint selection_width, selection_height;
689 _get_page_size_for_scale_and_rotation (pixbuf_cache->document,
693 selection_width = cairo_image_surface_get_width (job_info->selection);
694 selection_height = cairo_image_surface_get_height (job_info->selection);
696 if (width != selection_width || height != selection_height)
699 if (job_info->points_set)
707 clear_selection_if_needed (EvPixbufCache *pixbuf_cache,
708 CacheJobInfo *job_info,
712 if (new_selection_surface_needed (pixbuf_cache, job_info, page, scale)) {
713 if (job_info->selection)
714 cairo_surface_destroy (job_info->selection);
715 job_info->selection = NULL;
716 job_info->selection_points.x1 = -1;
720 /* Clears the cache of jobs and pixbufs.
723 ev_pixbuf_cache_clear (EvPixbufCache *pixbuf_cache)
727 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
728 dispose_cache_job_info (pixbuf_cache->prev_job + i, pixbuf_cache);
729 dispose_cache_job_info (pixbuf_cache->next_job + i, pixbuf_cache);
732 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
733 dispose_cache_job_info (pixbuf_cache->job_list + i, pixbuf_cache);
739 ev_pixbuf_cache_style_changed (EvPixbufCache *pixbuf_cache)
743 /* FIXME: doesn't update running jobs. */
744 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
745 CacheJobInfo *job_info;
747 job_info = pixbuf_cache->prev_job + i;
748 if (job_info->selection) {
749 cairo_surface_destroy (job_info->selection);
750 job_info->selection = NULL;
753 job_info = pixbuf_cache->next_job + i;
754 if (job_info->selection) {
755 cairo_surface_destroy (job_info->selection);
756 job_info->selection = NULL;
760 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
761 CacheJobInfo *job_info;
763 job_info = pixbuf_cache->job_list + i;
764 if (job_info->selection) {
765 cairo_surface_destroy (job_info->selection);
766 job_info->selection = NULL;
772 ev_pixbuf_cache_get_selection_surface (EvPixbufCache *pixbuf_cache,
777 CacheJobInfo *job_info;
779 /* the document does not implement the selection interface */
780 if (!EV_IS_SELECTION (pixbuf_cache->document))
783 job_info = find_job_cache (pixbuf_cache, page);
784 if (job_info == NULL)
787 /* No selection on this page */
788 if (!job_info->points_set)
791 /* If we have a running job, we just return what we have under the
792 * assumption that it'll be updated later and we can scale it as need
794 if (job_info->job && EV_JOB_RENDER (job_info->job)->include_selection)
795 return job_info->selection;
797 /* Now, lets see if we need to resize the image. If we do, we clear the
799 clear_selection_if_needed (pixbuf_cache, job_info, page, scale);
801 /* Finally, we see if the two scales are the same, and get a new pixbuf
802 * if needed. We do this synchronously for now. At some point, we
803 * _should_ be able to get rid of the doc_mutex, so the synchronicity
804 * doesn't kill us. Rendering a few glyphs should really be fast.
806 if (ev_rect_cmp (&(job_info->target_points), &(job_info->selection_points))) {
807 EvRectangle *old_points;
808 GdkColor *text, *base;
812 /* we need to get a new selection pixbuf */
813 ev_document_doc_mutex_lock ();
814 if (job_info->selection_points.x1 < 0) {
815 g_assert (job_info->selection == NULL);
818 g_assert (job_info->selection != NULL);
819 old_points = &(job_info->selection_points);
822 ev_page = ev_document_get_page (pixbuf_cache->document, page);
823 rc = ev_render_context_new (ev_page, 0, scale);
824 g_object_unref (ev_page);
826 if (job_info->selection_region)
827 gdk_region_destroy (job_info->selection_region);
828 job_info->selection_region =
829 ev_selection_get_selection_region (EV_SELECTION (pixbuf_cache->document),
830 rc, job_info->selection_style,
831 &(job_info->target_points));
833 gtk_widget_ensure_style (pixbuf_cache->view);
835 get_selection_colors (pixbuf_cache->view, &text, &base);
837 ev_selection_render_selection (EV_SELECTION (pixbuf_cache->document),
838 rc, &(job_info->selection),
839 &(job_info->target_points),
841 job_info->selection_style,
843 job_info->selection_points = job_info->target_points;
845 ev_document_doc_mutex_unlock ();
848 *region = job_info->selection_region;
849 return job_info->selection;
853 update_job_selection (CacheJobInfo *job_info,
854 EvViewSelection *selection)
856 job_info->points_set = TRUE;
857 job_info->target_points = selection->rect;
858 job_info->selection_style = selection->style;
862 clear_job_selection (CacheJobInfo *job_info)
864 job_info->points_set = FALSE;
865 job_info->selection_points.x1 = -1;
867 if (job_info->selection) {
868 cairo_surface_destroy (job_info->selection);
869 job_info->selection = NULL;
873 /* This function will reset the selection on pages that no longer have them, and
874 * will update the target_selection on those that need it. It will _not_ free
875 * the previous selection_list -- that's up to caller to do.
878 ev_pixbuf_cache_set_selection_list (EvPixbufCache *pixbuf_cache,
879 GList *selection_list)
881 EvViewSelection *selection;
882 GList *list = selection_list;
886 g_return_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache));
888 if (!EV_IS_SELECTION (pixbuf_cache->document))
891 /* We check each area to see what needs updating, and what needs freeing; */
892 page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size;
893 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
901 if (((EvViewSelection *)list->data)->page == page) {
902 selection = list->data;
904 } else if (((EvViewSelection *)list->data)->page > page)
910 update_job_selection (pixbuf_cache->prev_job + i, selection);
912 clear_job_selection (pixbuf_cache->prev_job + i);
916 page = pixbuf_cache->start_page;
917 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
920 if (((EvViewSelection *)list->data)->page == page) {
921 selection = list->data;
923 } else if (((EvViewSelection *)list->data)->page > page)
929 update_job_selection (pixbuf_cache->job_list + i, selection);
931 clear_job_selection (pixbuf_cache->job_list + i);
935 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
936 if (page >= ev_document_get_n_pages (pixbuf_cache->document))
941 if (((EvViewSelection *)list->data)->page == page) {
942 selection = list->data;
944 } else if (((EvViewSelection *)list->data)->page > page)
950 update_job_selection (pixbuf_cache->next_job + i, selection);
952 clear_job_selection (pixbuf_cache->next_job + i);
958 /* Returns what the pixbuf cache thinks is */
961 ev_pixbuf_cache_get_selection_list (EvPixbufCache *pixbuf_cache)
963 EvViewSelection *selection;
964 GList *retval = NULL;
968 g_return_val_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache), NULL);
970 /* We check each area to see what needs updating, and what needs freeing; */
971 page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size;
972 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
978 if (pixbuf_cache->prev_job[i].selection_points.x1 != -1) {
979 selection = g_new0 (EvViewSelection, 1);
980 selection->page = page;
981 selection->rect = pixbuf_cache->prev_job[i].selection_points;
982 if (pixbuf_cache->prev_job[i].selection_region)
983 selection->covered_region = gdk_region_copy (pixbuf_cache->prev_job[i].selection_region);
984 retval = g_list_append (retval, selection);
990 page = pixbuf_cache->start_page;
991 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
992 if (pixbuf_cache->job_list[i].selection_points.x1 != -1) {
993 selection = g_new0 (EvViewSelection, 1);
994 selection->page = page;
995 selection->rect = pixbuf_cache->job_list[i].selection_points;
996 if (pixbuf_cache->job_list[i].selection_region)
997 selection->covered_region = gdk_region_copy (pixbuf_cache->job_list[i].selection_region);
998 retval = g_list_append (retval, selection);
1004 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
1005 if (page >= ev_document_get_n_pages (pixbuf_cache->document))
1008 if (pixbuf_cache->next_job[i].selection_points.x1 != -1) {
1009 selection = g_new0 (EvViewSelection, 1);
1010 selection->page = page;
1011 selection->rect = pixbuf_cache->next_job[i].selection_points;
1012 if (pixbuf_cache->next_job[i].selection_region)
1013 selection->covered_region = gdk_region_copy (pixbuf_cache->next_job[i].selection_region);
1014 retval = g_list_append (retval, selection);
1024 ev_pixbuf_cache_reload_page (EvPixbufCache *pixbuf_cache,
1030 CacheJobInfo *job_info;
1033 job_info = find_job_cache (pixbuf_cache, page);
1034 if (job_info == NULL)
1037 _get_page_size_for_scale_and_rotation (pixbuf_cache->document,
1038 page, scale, rotation,
1040 add_job (pixbuf_cache, job_info, region,
1041 width, height, page, rotation, scale,
1042 EV_JOB_PRIORITY_URGENT);