1 #include "ev-pixbuf-cache.h"
2 #include "ev-job-queue.h"
3 #include "ev-page-cache.h"
4 #include "ev-document-images.h"
5 #include "ev-document-forms.h"
7 #include "ev-form-field.h"
9 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 GList *form_field_mapping;
23 GdkRegion *text_mapping;
26 * Selection_points are the coordinates encapsulated in selection.
27 * target_points is the target selection size. */
28 EvRectangle selection_points;
29 EvRectangle target_points;
30 EvSelectionStyle selection_style;
33 cairo_surface_t *selection;
34 GdkRegion *selection_region;
41 /* We keep a link to our containing view just for style information. */
47 /* preload_cache_size is the number of pages prior to the current
48 * visible area that we cache. It's normally 1, but could be 2 in the
51 int preload_cache_size;
52 CacheJobInfo *prev_job;
53 CacheJobInfo *job_list;
54 CacheJobInfo *next_job;
57 struct _EvPixbufCacheClass
59 GObjectClass parent_class;
61 void (* job_finished) (EvPixbufCache *pixbuf_cache);
71 static guint signals[N_SIGNALS] = {0, };
73 static void ev_pixbuf_cache_init (EvPixbufCache *pixbuf_cache);
74 static void ev_pixbuf_cache_class_init (EvPixbufCacheClass *pixbuf_cache);
75 static void ev_pixbuf_cache_finalize (GObject *object);
76 static void ev_pixbuf_cache_dispose (GObject *object);
77 static void job_page_ready_cb (EvJob *job,
78 EvPixbufCache *pixbuf_cache);
79 static void job_finished_cb (EvJob *job,
80 EvPixbufCache *pixbuf_cache);
81 static CacheJobInfo *find_job_cache (EvPixbufCache *pixbuf_cache,
83 static void copy_job_to_job_info (EvJobRender *job_render,
84 CacheJobInfo *job_info,
85 EvPixbufCache *pixbuf_cache);
86 static void copy_job_page_and_selection_to_job_info (EvJobRender *job_render,
87 CacheJobInfo *job_info,
88 EvPixbufCache *pixbuf_cache);
89 static gboolean new_selection_surface_needed(EvPixbufCache *pixbuf_cache,
90 CacheJobInfo *job_info,
95 /* These are used for iterating through the prev and next arrays */
96 #define FIRST_VISABLE_PREV(pixbuf_cache) \
97 (MAX (0, pixbuf_cache->preload_cache_size + 1 - pixbuf_cache->start_page))
98 #define VISIBLE_NEXT_LEN(pixbuf_cache, page_cache) \
99 (MIN(pixbuf_cache->preload_cache_size, ev_page_cache_get_n_pages (page_cache) - (1 + pixbuf_cache->end_page)))
100 #define PAGE_CACHE_LEN(pixbuf_cache) \
101 ((pixbuf_cache->end_page - pixbuf_cache->start_page) + 1)
103 G_DEFINE_TYPE (EvPixbufCache, ev_pixbuf_cache, G_TYPE_OBJECT)
106 ev_pixbuf_cache_init (EvPixbufCache *pixbuf_cache)
108 pixbuf_cache->start_page = 0;
109 pixbuf_cache->end_page = 0;
110 pixbuf_cache->job_list = g_new0 (CacheJobInfo, PAGE_CACHE_LEN (pixbuf_cache));
112 pixbuf_cache->preload_cache_size = 2;
113 pixbuf_cache->prev_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size);
114 pixbuf_cache->next_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size);
118 ev_pixbuf_cache_class_init (EvPixbufCacheClass *class)
120 GObjectClass *object_class;
122 object_class = G_OBJECT_CLASS (class);
124 object_class->finalize = ev_pixbuf_cache_finalize;
125 object_class->dispose = ev_pixbuf_cache_dispose;
127 signals[JOB_FINISHED] =
128 g_signal_new ("job-finished",
129 G_OBJECT_CLASS_TYPE (object_class),
130 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
131 G_STRUCT_OFFSET (EvPixbufCacheClass, job_finished),
133 g_cclosure_marshal_VOID__POINTER,
139 ev_pixbuf_cache_finalize (GObject *object)
141 EvPixbufCache *pixbuf_cache;
143 pixbuf_cache = EV_PIXBUF_CACHE (object);
145 g_free (pixbuf_cache->prev_job);
146 g_free (pixbuf_cache->job_list);
147 g_free (pixbuf_cache->next_job);
149 G_OBJECT_CLASS (ev_pixbuf_cache_parent_class)->finalize (object);
153 dispose_cache_job_info (CacheJobInfo *job_info,
156 if (job_info == NULL)
159 g_signal_handlers_disconnect_by_func (job_info->job,
160 G_CALLBACK (job_page_ready_cb),
162 g_signal_handlers_disconnect_by_func (job_info->job,
163 G_CALLBACK (job_finished_cb),
165 ev_job_queue_remove_job (job_info->job);
166 g_object_unref (G_OBJECT (job_info->job));
167 job_info->job = NULL;
169 if (job_info->surface) {
170 cairo_surface_destroy (job_info->surface);
171 job_info->surface = NULL;
173 if (job_info->region) {
174 gdk_region_destroy (job_info->region);
175 job_info->region = NULL;
177 if (job_info->link_mapping) {
178 ev_link_mapping_free (job_info->link_mapping);
179 job_info->link_mapping = NULL;
181 if (job_info->image_mapping) {
182 ev_image_mapping_free (job_info->image_mapping);
183 job_info->image_mapping = NULL;
185 if (job_info->form_field_mapping) {
186 ev_form_field_mapping_free (job_info->form_field_mapping);
187 job_info->form_field_mapping = NULL;
189 if (job_info->text_mapping) {
190 gdk_region_destroy (job_info->text_mapping);
191 job_info->text_mapping = NULL;
193 if (job_info->selection) {
194 cairo_surface_destroy (job_info->selection);
195 job_info->selection = NULL;
197 if (job_info->selection_region) {
198 gdk_region_destroy (job_info->selection_region);
199 job_info->selection_region = NULL;
202 g_object_unref (G_OBJECT (job_info->rc));
206 job_info->points_set = FALSE;
210 ev_pixbuf_cache_dispose (GObject *object)
212 EvPixbufCache *pixbuf_cache;
215 pixbuf_cache = EV_PIXBUF_CACHE (object);
217 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
218 dispose_cache_job_info (pixbuf_cache->prev_job + i, pixbuf_cache);
219 dispose_cache_job_info (pixbuf_cache->next_job + i, pixbuf_cache);
222 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
223 dispose_cache_job_info (pixbuf_cache->job_list + i, pixbuf_cache);
226 G_OBJECT_CLASS (ev_pixbuf_cache_parent_class)->dispose (object);
231 ev_pixbuf_cache_new (GtkWidget *view,
232 EvDocument *document)
234 EvPixbufCache *pixbuf_cache;
236 pixbuf_cache = (EvPixbufCache *) g_object_new (EV_TYPE_PIXBUF_CACHE, NULL);
237 /* This is a backlink, so we don't ref this */
238 pixbuf_cache->view = view;
239 pixbuf_cache->document = document;
245 job_page_ready_cb (EvJob *job,
246 EvPixbufCache *pixbuf_cache)
248 CacheJobInfo *job_info;
249 EvJobRender *job_render = EV_JOB_RENDER (job);
251 /* If the job is outside of our interest, we silently discard it */
252 if ((job_render->rc->page < (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size)) ||
253 (job_render->rc->page > (pixbuf_cache->end_page + pixbuf_cache->preload_cache_size))) {
254 g_object_unref (job);
258 job_info = find_job_cache (pixbuf_cache, job_render->rc->page);
260 copy_job_page_and_selection_to_job_info (job_render, job_info, pixbuf_cache);
261 g_signal_emit (pixbuf_cache, signals[JOB_FINISHED], 0, job_info->region);
265 job_finished_cb (EvJob *job,
266 EvPixbufCache *pixbuf_cache)
268 CacheJobInfo *job_info;
269 EvJobRender *job_render = EV_JOB_RENDER (job);
271 /* If the job is outside of our interest, we silently discard it */
272 if ((job_render->rc->page < (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size)) ||
273 (job_render->rc->page > (pixbuf_cache->end_page + pixbuf_cache->preload_cache_size))) {
274 g_object_unref (job);
278 job_info = find_job_cache (pixbuf_cache, job_render->rc->page);
279 copy_job_to_job_info (job_render, job_info, pixbuf_cache);
282 /* This checks a job to see if the job would generate the right sized pixbuf
283 * given a scale. If it won't, it removes the job and clears it to NULL.
286 check_job_size_and_unref (EvPixbufCache *pixbuf_cache,
287 CacheJobInfo *job_info,
288 EvPageCache *page_cache,
296 if (job_info->job == NULL)
299 ev_page_cache_get_size (page_cache,
300 EV_JOB_RENDER (job_info->job)->rc->page,
301 EV_JOB_RENDER (job_info->job)->rc->rotation,
305 if (width == EV_JOB_RENDER (job_info->job)->target_width &&
306 height == EV_JOB_RENDER (job_info->job)->target_height)
309 g_signal_handlers_disconnect_by_func (job_info->job,
310 G_CALLBACK (job_page_ready_cb),
312 g_signal_handlers_disconnect_by_func (job_info->job,
313 G_CALLBACK (job_finished_cb),
315 ev_job_queue_remove_job (job_info->job);
316 g_object_unref (job_info->job);
317 job_info->job = NULL;
320 /* Do all function that copies a job from an older cache to it's position in the
321 * new cache. It clears the old job if it doesn't have a place.
324 move_one_job (CacheJobInfo *job_info,
325 EvPixbufCache *pixbuf_cache,
327 CacheJobInfo *new_job_list,
328 CacheJobInfo *new_prev_job,
329 CacheJobInfo *new_next_job,
332 EvJobPriority priority)
334 CacheJobInfo *target_page = NULL;
336 EvJobPriority new_priority;
338 if (page < (start_page - pixbuf_cache->preload_cache_size) ||
339 page > (end_page + pixbuf_cache->preload_cache_size)) {
340 dispose_cache_job_info (job_info, pixbuf_cache);
344 /* find the target page to copy it over to. */
345 if (page < start_page) {
346 page_offset = (page - (start_page - pixbuf_cache->preload_cache_size));
348 g_assert (page_offset >= 0 &&
349 page_offset < pixbuf_cache->preload_cache_size);
350 target_page = new_prev_job + page_offset;
351 new_priority = EV_JOB_PRIORITY_LOW;
352 } else if (page > end_page) {
353 page_offset = (page - (end_page + 1));
355 g_assert (page_offset >= 0 &&
356 page_offset < pixbuf_cache->preload_cache_size);
357 target_page = new_next_job + page_offset;
358 new_priority = EV_JOB_PRIORITY_LOW;
360 page_offset = page - start_page;
361 g_assert (page_offset >= 0 &&
362 page_offset <= ((end_page - start_page) + 1));
363 new_priority = EV_JOB_PRIORITY_HIGH;
364 target_page = new_job_list + page_offset;
367 *target_page = *job_info;
368 job_info->job = NULL;
369 job_info->region = NULL;
370 job_info->surface = NULL;
371 job_info->link_mapping = NULL;
372 job_info->image_mapping = NULL;
373 job_info->form_field_mapping = NULL;
375 if (new_priority != priority && target_page->job) {
376 ev_job_queue_update_job (target_page->job, new_priority);
381 ev_pixbuf_cache_update_range (EvPixbufCache *pixbuf_cache,
385 CacheJobInfo *new_job_list;
386 CacheJobInfo *new_prev_job;
387 CacheJobInfo *new_next_job;
388 EvPageCache *page_cache;
391 if (pixbuf_cache->start_page == start_page &&
392 pixbuf_cache->end_page == end_page)
395 page_cache = ev_page_cache_get (pixbuf_cache->document);
397 new_job_list = g_new0 (CacheJobInfo, (end_page - start_page) + 1);
398 new_prev_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size);
399 new_next_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size);
401 /* We go through each job in the old cache and either clear it or move
402 * it to a new location. */
404 /* Start with the prev cache. */
405 page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size;
406 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
408 dispose_cache_job_info (pixbuf_cache->prev_job + i, pixbuf_cache);
410 move_one_job (pixbuf_cache->prev_job + i,
412 new_job_list, new_prev_job, new_next_job,
413 start_page, end_page, EV_JOB_PRIORITY_LOW);
418 page = pixbuf_cache->start_page;
419 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
420 move_one_job (pixbuf_cache->job_list + i,
422 new_job_list, new_prev_job, new_next_job,
423 start_page, end_page, EV_JOB_PRIORITY_HIGH);
427 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
428 if (page >= ev_page_cache_get_n_pages (page_cache)) {
429 dispose_cache_job_info (pixbuf_cache->next_job + i, pixbuf_cache);
431 move_one_job (pixbuf_cache->next_job + i,
433 new_job_list, new_prev_job, new_next_job,
434 start_page, end_page, EV_JOB_PRIORITY_LOW);
439 g_free (pixbuf_cache->job_list);
440 g_free (pixbuf_cache->prev_job);
441 g_free (pixbuf_cache->next_job);
443 pixbuf_cache->job_list = new_job_list;
444 pixbuf_cache->prev_job = new_prev_job;
445 pixbuf_cache->next_job = new_next_job;
447 pixbuf_cache->start_page = start_page;
448 pixbuf_cache->end_page = end_page;
452 copy_job_page_and_selection_to_job_info (EvJobRender *job_render,
453 CacheJobInfo *job_info,
454 EvPixbufCache *pixbuf_cache)
456 if (job_info->surface) {
457 cairo_surface_destroy (job_info->surface);
459 job_info->surface = cairo_surface_reference (job_render->surface);
462 g_object_unref (G_OBJECT (job_info->rc));
464 job_info->rc = g_object_ref (job_render->rc);
466 job_info->points_set = FALSE;
467 if (job_render->include_selection) {
468 if (job_info->selection) {
469 cairo_surface_destroy (job_info->selection);
470 job_info->selection = NULL;
472 if (job_info->selection_region) {
473 gdk_region_destroy (job_info->selection_region);
474 job_info->selection_region = NULL;
477 job_info->selection_points = job_render->selection_points;
478 job_info->selection_region = gdk_region_copy (job_render->selection_region);
479 job_info->selection = cairo_surface_reference (job_render->selection);
480 g_assert (job_info->selection_points.x1 >= 0);
481 job_info->points_set = TRUE;
485 g_signal_handlers_disconnect_by_func (job_info->job,
486 G_CALLBACK (job_page_ready_cb),
490 job_info->page_ready = TRUE;
494 copy_job_to_job_info (EvJobRender *job_render,
495 CacheJobInfo *job_info,
496 EvPixbufCache *pixbuf_cache)
498 if (job_render->include_links) {
499 if (job_info->link_mapping)
500 ev_link_mapping_free (job_info->link_mapping);
501 job_info->link_mapping = job_render->link_mapping;
504 if (job_render->include_images) {
505 if (job_info->image_mapping)
506 ev_image_mapping_free (job_info->image_mapping);
507 job_info->image_mapping = job_render->image_mapping;
510 if (job_render->include_forms) {
511 if (job_info->form_field_mapping)
512 ev_form_field_mapping_free (job_info->form_field_mapping);
513 job_info->form_field_mapping = job_render->form_field_mapping;
516 if (job_render->include_text) {
517 if (job_info->text_mapping)
518 gdk_region_destroy (job_info->text_mapping);
519 job_info->text_mapping = job_render->text_mapping;
523 g_signal_handlers_disconnect_by_func (job_info->job,
524 G_CALLBACK (job_finished_cb),
526 ev_job_queue_remove_job (job_info->job);
527 g_object_unref (G_OBJECT (job_info->job));
528 job_info->job = NULL;
532 static CacheJobInfo *
533 find_job_cache (EvPixbufCache *pixbuf_cache,
538 if (page < (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size) ||
539 page > (pixbuf_cache->end_page + pixbuf_cache->preload_cache_size))
542 if (page < pixbuf_cache->start_page) {
543 page_offset = (page - (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size));
545 g_assert (page_offset >= 0 &&
546 page_offset < pixbuf_cache->preload_cache_size);
547 return pixbuf_cache->prev_job + page_offset;
550 if (page > pixbuf_cache->end_page) {
551 page_offset = (page - (pixbuf_cache->end_page + 1));
553 g_assert (page_offset >= 0 &&
554 page_offset < pixbuf_cache->preload_cache_size);
555 return pixbuf_cache->next_job + page_offset;
558 page_offset = page - pixbuf_cache->start_page;
559 g_assert (page_offset >= 0 &&
560 page_offset <= PAGE_CACHE_LEN(pixbuf_cache));
561 return pixbuf_cache->job_list + page_offset;
565 ev_pixbuf_cache_clear_job_sizes (EvPixbufCache *pixbuf_cache,
568 EvPageCache *page_cache;
571 page_cache = ev_page_cache_get (pixbuf_cache->document);
573 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
574 check_job_size_and_unref (pixbuf_cache, pixbuf_cache->job_list + i, page_cache, scale);
577 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
578 check_job_size_and_unref (pixbuf_cache, pixbuf_cache->prev_job + i, page_cache, scale);
579 check_job_size_and_unref (pixbuf_cache, pixbuf_cache->next_job + i, page_cache, scale);
583 #define FIRST_VISABLE_PREV(pixbuf_cache) \
584 (MAX (0, pixbuf_cache->preload_cache_size + 1 - pixbuf_cache->start_page))
587 get_selection_colors (GtkWidget *widget, GdkColor **text, GdkColor **base)
589 if (GTK_WIDGET_HAS_FOCUS (widget)) {
590 *text = &widget->style->text [GTK_STATE_SELECTED];
591 *base = &widget->style->base [GTK_STATE_SELECTED];
593 *text = &widget->style->text [GTK_STATE_ACTIVE];
594 *base = &widget->style->base [GTK_STATE_ACTIVE];
599 add_job (EvPixbufCache *pixbuf_cache,
600 CacheJobInfo *job_info,
601 EvPageCache *page_cache,
608 EvJobPriority priority)
610 gboolean include_links = FALSE;
611 gboolean include_text = FALSE;
612 gboolean include_selection = FALSE;
613 gboolean include_images = TRUE;
614 gboolean include_forms = FALSE;
615 GdkColor *text, *base;
617 job_info->page_ready = FALSE;
619 if (job_info->rc == NULL) {
620 job_info->rc = ev_render_context_new (rotation, page, scale);
622 ev_render_context_set_rotation (job_info->rc, rotation);
623 ev_render_context_set_page (job_info->rc, page);
624 ev_render_context_set_scale (job_info->rc, scale);
627 if (job_info->region)
628 gdk_region_destroy (job_info->region);
629 job_info->region = region ? gdk_region_copy (region) : NULL;
631 /* Figure out what else we need for this job */
632 if (job_info->link_mapping == NULL)
633 include_links = TRUE;
634 if (job_info->image_mapping == NULL)
635 include_images = TRUE;
636 if (job_info->form_field_mapping == NULL)
637 include_forms = TRUE;
638 if (job_info->text_mapping == NULL)
640 if (new_selection_surface_needed (pixbuf_cache, job_info, page, scale)) {
641 include_selection = TRUE;
644 gtk_widget_ensure_style (pixbuf_cache->view);
646 get_selection_colors (pixbuf_cache->view, &text, &base);
648 job_info->job = ev_job_render_new (pixbuf_cache->document,
651 &(job_info->target_points),
652 job_info->selection_style,
659 ev_job_queue_add_job (job_info->job, priority);
660 g_signal_connect (G_OBJECT (job_info->job), "page-ready",
661 G_CALLBACK (job_page_ready_cb),
663 g_signal_connect (G_OBJECT (job_info->job), "finished",
664 G_CALLBACK (job_finished_cb),
669 add_job_if_needed (EvPixbufCache *pixbuf_cache,
670 CacheJobInfo *job_info,
671 EvPageCache *page_cache,
675 EvJobPriority priority)
682 ev_page_cache_get_size (page_cache, page, rotation,
683 scale, &width, &height);
685 if (job_info->surface &&
686 cairo_image_surface_get_width (job_info->surface) == width &&
687 cairo_image_surface_get_height (job_info->surface) == height)
690 add_job (pixbuf_cache, job_info, page_cache, NULL,
691 width, height, page, rotation, scale,
696 ev_pixbuf_cache_add_jobs_if_needed (EvPixbufCache *pixbuf_cache,
700 EvPageCache *page_cache;
701 CacheJobInfo *job_info;
705 page_cache = ev_page_cache_get (pixbuf_cache->document);
707 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
708 job_info = (pixbuf_cache->job_list + i);
709 page = pixbuf_cache->start_page + i;
711 add_job_if_needed (pixbuf_cache, job_info,
712 page_cache, page, rotation, scale,
713 EV_JOB_PRIORITY_HIGH);
716 for (i = FIRST_VISABLE_PREV(pixbuf_cache); i < pixbuf_cache->preload_cache_size; i++) {
717 job_info = (pixbuf_cache->prev_job + i);
718 page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size + i;
720 add_job_if_needed (pixbuf_cache, job_info,
721 page_cache, page, rotation, scale,
722 EV_JOB_PRIORITY_LOW);
725 for (i = 0; i < VISIBLE_NEXT_LEN(pixbuf_cache, page_cache); i++) {
726 job_info = (pixbuf_cache->next_job + i);
727 page = pixbuf_cache->end_page + 1 + i;
729 add_job_if_needed (pixbuf_cache, job_info,
730 page_cache, page, rotation, scale,
731 EV_JOB_PRIORITY_LOW);
737 ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache,
742 GList *selection_list)
744 EvPageCache *page_cache;
746 g_return_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache));
748 page_cache = ev_page_cache_get (pixbuf_cache->document);
750 g_return_if_fail (start_page >= 0 && start_page < ev_page_cache_get_n_pages (page_cache));
751 g_return_if_fail (end_page >= 0 && end_page < ev_page_cache_get_n_pages (page_cache));
752 g_return_if_fail (end_page >= start_page);
754 /* First, resize the page_range as needed. We cull old pages
756 ev_pixbuf_cache_update_range (pixbuf_cache, start_page, end_page);
758 /* Then, we update the current jobs to see if any of them are the wrong
759 * size, we remove them if we need to. */
760 ev_pixbuf_cache_clear_job_sizes (pixbuf_cache, scale);
762 /* Next, we update the target selection for our pages */
763 ev_pixbuf_cache_set_selection_list (pixbuf_cache, selection_list);
765 /* Finally, we add the new jobs for all the sizes that don't have a
767 ev_pixbuf_cache_add_jobs_if_needed (pixbuf_cache, rotation, scale);
771 ev_pixbuf_cache_get_surface (EvPixbufCache *pixbuf_cache,
774 CacheJobInfo *job_info;
776 job_info = find_job_cache (pixbuf_cache, page);
777 if (job_info == NULL)
780 if (job_info->page_ready)
781 return job_info->surface;
783 /* We don't need to wait for the idle to handle the callback */
785 EV_JOB_RENDER (job_info->job)->page_ready) {
786 copy_job_page_and_selection_to_job_info (EV_JOB_RENDER (job_info->job), job_info, pixbuf_cache);
787 g_signal_emit (pixbuf_cache, signals[JOB_FINISHED], 0, job_info->region);
790 return job_info->surface;
794 ev_pixbuf_cache_get_link_mapping (EvPixbufCache *pixbuf_cache,
797 CacheJobInfo *job_info;
799 job_info = find_job_cache (pixbuf_cache, page);
800 if (job_info == NULL)
803 /* We don't need to wait for the idle to handle the callback */
805 EV_JOB (job_info->job)->finished) {
806 copy_job_to_job_info (EV_JOB_RENDER (job_info->job), job_info, pixbuf_cache);
809 return job_info->link_mapping;
813 ev_pixbuf_cache_get_image_mapping (EvPixbufCache *pixbuf_cache,
816 CacheJobInfo *job_info;
818 if (!EV_IS_DOCUMENT_IMAGES (pixbuf_cache->document))
821 job_info = find_job_cache (pixbuf_cache, page);
822 if (job_info == NULL)
825 /* We don't need to wait for the idle to handle the callback */
827 EV_JOB (job_info->job)->finished) {
828 copy_job_to_job_info (EV_JOB_RENDER (job_info->job), job_info, pixbuf_cache);
831 return job_info->image_mapping;
835 ev_pixbuf_cache_get_form_field_mapping (EvPixbufCache *pixbuf_cache,
838 CacheJobInfo *job_info;
840 if (!EV_IS_DOCUMENT_FORMS (pixbuf_cache->document))
843 job_info = find_job_cache (pixbuf_cache, page);
844 if (job_info == NULL)
847 /* We don't need to wait for the idle to handle the callback */
849 EV_JOB (job_info->job)->finished) {
850 copy_job_to_job_info (EV_JOB_RENDER(job_info->job), job_info, pixbuf_cache);
853 return job_info->form_field_mapping;
857 new_selection_surface_needed (EvPixbufCache *pixbuf_cache,
858 CacheJobInfo *job_info,
862 EvPageCache *page_cache;
864 if (job_info->selection) {
866 gint selection_width, selection_height;
868 page_cache = ev_page_cache_get (pixbuf_cache->document);
869 ev_page_cache_get_size (page_cache, page,
870 job_info->rc->rotation,
871 scale, &width, &height);
873 selection_width = cairo_image_surface_get_width (job_info->selection);
874 selection_height = cairo_image_surface_get_height (job_info->selection);
876 if (width != selection_width || height != selection_height)
879 if (job_info->points_set)
887 clear_selection_if_needed (EvPixbufCache *pixbuf_cache,
888 CacheJobInfo *job_info,
892 if (new_selection_surface_needed (pixbuf_cache, job_info, page, scale)) {
893 if (job_info->selection)
894 cairo_surface_destroy (job_info->selection);
895 job_info->selection = NULL;
896 job_info->selection_points.x1 = -1;
901 ev_pixbuf_cache_get_text_mapping (EvPixbufCache *pixbuf_cache,
904 CacheJobInfo *job_info;
906 job_info = find_job_cache (pixbuf_cache, page);
907 if (job_info == NULL)
910 /* We don't need to wait for the idle to handle the callback */
912 EV_JOB (job_info->job)->finished) {
913 copy_job_to_job_info (EV_JOB_RENDER (job_info->job), job_info, pixbuf_cache);
916 return job_info->text_mapping;
919 /* Clears the cache of jobs and pixbufs.
922 ev_pixbuf_cache_clear (EvPixbufCache *pixbuf_cache)
926 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
927 dispose_cache_job_info (pixbuf_cache->prev_job + i, pixbuf_cache);
928 dispose_cache_job_info (pixbuf_cache->next_job + i, pixbuf_cache);
931 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
932 dispose_cache_job_info (pixbuf_cache->job_list + i, pixbuf_cache);
938 ev_pixbuf_cache_style_changed (EvPixbufCache *pixbuf_cache)
942 /* FIXME: doesn't update running jobs. */
943 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
944 CacheJobInfo *job_info;
946 job_info = pixbuf_cache->prev_job + i;
947 if (job_info->selection) {
948 cairo_surface_destroy (job_info->selection);
949 job_info->selection = NULL;
952 job_info = pixbuf_cache->next_job + i;
953 if (job_info->selection) {
954 cairo_surface_destroy (job_info->selection);
955 job_info->selection = NULL;
959 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
960 CacheJobInfo *job_info;
962 job_info = pixbuf_cache->job_list + i;
963 if (job_info->selection) {
964 cairo_surface_destroy (job_info->selection);
965 job_info->selection = NULL;
971 ev_pixbuf_cache_get_selection_surface (EvPixbufCache *pixbuf_cache,
976 CacheJobInfo *job_info;
978 /* the document does not implement the selection interface */
979 if (!EV_IS_SELECTION (pixbuf_cache->document))
982 job_info = find_job_cache (pixbuf_cache, page);
983 if (job_info == NULL)
986 /* No selection on this page */
987 if (!job_info->points_set)
991 g_assert (job_info->rc);
992 ev_render_context_set_scale (job_info->rc, scale);
994 /* If we have a running job, we just return what we have under the
995 * assumption that it'll be updated later and we can scale it as need
997 if (job_info->job && EV_JOB_RENDER (job_info->job)->include_selection)
998 return job_info->selection;
1000 /* Now, lets see if we need to resize the image. If we do, we clear the
1002 clear_selection_if_needed (pixbuf_cache, job_info, page, scale);
1004 /* Finally, we see if the two scales are the same, and get a new pixbuf
1005 * if needed. We do this synchronously for now. At some point, we
1006 * _should_ be able to get rid of the doc_mutex, so the synchronicity
1007 * doesn't kill us. Rendering a few glyphs should really be fast.
1009 if (ev_rect_cmp (&(job_info->target_points), &(job_info->selection_points))) {
1010 EvRectangle *old_points;
1011 GdkColor *text, *base;
1013 /* we need to get a new selection pixbuf */
1014 ev_document_doc_mutex_lock ();
1015 if (job_info->selection_points.x1 < 0) {
1016 g_assert (job_info->selection == NULL);
1019 g_assert (job_info->selection != NULL);
1020 old_points = &(job_info->selection_points);
1023 if (job_info->selection_region)
1024 gdk_region_destroy (job_info->selection_region);
1025 job_info->selection_region =
1026 ev_selection_get_selection_region (EV_SELECTION (pixbuf_cache->document),
1028 job_info->selection_style,
1029 &(job_info->target_points));
1031 gtk_widget_ensure_style (pixbuf_cache->view);
1033 get_selection_colors (pixbuf_cache->view, &text, &base);
1035 ev_selection_render_selection (EV_SELECTION (pixbuf_cache->document),
1036 job_info->rc, &(job_info->selection),
1037 &(job_info->target_points),
1039 job_info->selection_style,
1041 job_info->selection_points = job_info->target_points;
1042 ev_document_doc_mutex_unlock ();
1045 *region = job_info->selection_region;
1046 return job_info->selection;
1050 update_job_selection (CacheJobInfo *job_info,
1051 EvViewSelection *selection)
1053 job_info->points_set = TRUE;
1054 job_info->target_points = selection->rect;
1055 job_info->selection_style = selection->style;
1059 clear_job_selection (CacheJobInfo *job_info)
1061 job_info->points_set = FALSE;
1062 job_info->selection_points.x1 = -1;
1064 if (job_info->selection) {
1065 cairo_surface_destroy (job_info->selection);
1066 job_info->selection = NULL;
1070 /* This function will reset the selection on pages that no longer have them, and
1071 * will update the target_selection on those that need it. It will _not_ free
1072 * the previous selection_list -- that's up to caller to do.
1075 ev_pixbuf_cache_set_selection_list (EvPixbufCache *pixbuf_cache,
1076 GList *selection_list)
1078 EvPageCache *page_cache;
1079 EvViewSelection *selection;
1080 GList *list = selection_list;
1084 g_return_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache));
1086 if (!EV_IS_SELECTION (pixbuf_cache->document))
1089 page_cache = ev_page_cache_get (pixbuf_cache->document);
1091 /* We check each area to see what needs updating, and what needs freeing; */
1092 page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size;
1093 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
1101 if (((EvViewSelection *)list->data)->page == page) {
1102 selection = list->data;
1104 } else if (((EvViewSelection *)list->data)->page > page)
1110 update_job_selection (pixbuf_cache->prev_job + i, selection);
1112 clear_job_selection (pixbuf_cache->prev_job + i);
1116 page = pixbuf_cache->start_page;
1117 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
1120 if (((EvViewSelection *)list->data)->page == page) {
1121 selection = list->data;
1123 } else if (((EvViewSelection *)list->data)->page > page)
1129 update_job_selection (pixbuf_cache->job_list + i, selection);
1131 clear_job_selection (pixbuf_cache->job_list + i);
1135 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
1136 if (page >= ev_page_cache_get_n_pages (page_cache))
1141 if (((EvViewSelection *)list->data)->page == page) {
1142 selection = list->data;
1144 } else if (((EvViewSelection *)list->data)->page > page)
1150 update_job_selection (pixbuf_cache->next_job + i, selection);
1152 clear_job_selection (pixbuf_cache->next_job + i);
1158 /* Returns what the pixbuf cache thinks is */
1161 ev_pixbuf_cache_get_selection_list (EvPixbufCache *pixbuf_cache)
1163 EvPageCache *page_cache;
1164 EvViewSelection *selection;
1165 GList *retval = NULL;
1169 g_return_val_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache), NULL);
1171 page_cache = ev_page_cache_get (pixbuf_cache->document);
1173 /* We check each area to see what needs updating, and what needs freeing; */
1174 page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size;
1175 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
1181 if (pixbuf_cache->prev_job[i].selection_points.x1 != -1) {
1182 selection = g_new0 (EvViewSelection, 1);
1183 selection->page = page;
1184 selection->rect = pixbuf_cache->prev_job[i].selection_points;
1185 if (pixbuf_cache->prev_job[i].selection_region)
1186 selection->covered_region = gdk_region_copy (pixbuf_cache->prev_job[i].selection_region);
1187 retval = g_list_append (retval, selection);
1193 page = pixbuf_cache->start_page;
1194 for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
1195 if (pixbuf_cache->job_list[i].selection_points.x1 != -1) {
1196 selection = g_new0 (EvViewSelection, 1);
1197 selection->page = page;
1198 selection->rect = pixbuf_cache->job_list[i].selection_points;
1199 if (pixbuf_cache->job_list[i].selection_region)
1200 selection->covered_region = gdk_region_copy (pixbuf_cache->job_list[i].selection_region);
1201 retval = g_list_append (retval, selection);
1207 for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
1208 if (page >= ev_page_cache_get_n_pages (page_cache))
1211 if (pixbuf_cache->next_job[i].selection_points.x1 != -1) {
1212 selection = g_new0 (EvViewSelection, 1);
1213 selection->page = page;
1214 selection->rect = pixbuf_cache->next_job[i].selection_points;
1215 if (pixbuf_cache->next_job[i].selection_region)
1216 selection->covered_region = gdk_region_copy (pixbuf_cache->next_job[i].selection_region);
1217 retval = g_list_append (retval, selection);
1227 ev_pixbuf_cache_reload_page (EvPixbufCache *pixbuf_cache,
1233 CacheJobInfo *job_info;
1234 EvPageCache *page_cache;
1237 job_info = find_job_cache (pixbuf_cache, page);
1238 if (job_info == NULL)
1241 page_cache = ev_page_cache_get (pixbuf_cache->document);
1242 ev_page_cache_get_size (page_cache, page, rotation, scale,
1245 add_job (pixbuf_cache, job_info, page_cache, region,
1246 width, height, page, rotation, scale,
1247 EV_JOB_PRIORITY_HIGH);