1 /* this file is part of xreader, a mate document viewer
2  *
3  *  Copyright (C) 2008 Carlos Garcia Campos <carlosgc@gnome.org>
4  *  Copyright (C) 2005 Red Hat, Inc
5  *
6  * Xreader is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Xreader is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20 
21 #include <config.h>
22 
23 #include "ev-jobs.h"
24 #include "ev-document-thumbnails.h"
25 #include "ev-document-links.h"
26 #include "ev-document-images.h"
27 #include "ev-job-scheduler.h"
28 #include "ev-document-forms.h"
29 #include "ev-file-exporter.h"
30 #include "ev-document-factory.h"
31 #include "ev-document-misc.h"
32 #include "ev-file-helpers.h"
33 #include "ev-document-fonts.h"
34 #include "ev-document-security.h"
35 #include "ev-document-find.h"
36 #include "ev-document-layers.h"
37 #include "ev-document-print.h"
38 #include "ev-document-annotations.h"
39 #include "ev-document-attachments.h"
40 #include "ev-document-text.h"
41 #include "ev-debug.h"
42 
43 #include <gtk/gtk.h>
44 #if ENABLE_EPUB
45 #include <webkit2/webkit2.h>
46 #endif
47 #include <errno.h>
48 #include <glib/gstdio.h>
49 #include <glib/gi18n-lib.h>
50 #include <unistd.h>
51 
52 static void ev_job_init                   (EvJob                 *job);
53 static void ev_job_class_init             (EvJobClass            *class);
54 static void ev_job_links_init             (EvJobLinks            *job);
55 static void ev_job_links_class_init       (EvJobLinksClass       *class);
56 static void ev_job_attachments_init       (EvJobAttachments      *job);
57 static void ev_job_attachments_class_init (EvJobAttachmentsClass *class);
58 static void ev_job_annots_init            (EvJobAnnots           *job);
59 static void ev_job_annots_class_init      (EvJobAnnotsClass      *class);
60 static void ev_job_render_init            (EvJobRender           *job);
61 static void ev_job_render_class_init      (EvJobRenderClass      *class);
62 static void ev_job_page_data_init         (EvJobPageData         *job);
63 static void ev_job_page_data_class_init   (EvJobPageDataClass    *class);
64 static void ev_job_thumbnail_init         (EvJobThumbnail        *job);
65 static void ev_job_thumbnail_class_init   (EvJobThumbnailClass   *class);
66 static void ev_job_load_init              (EvJobLoad	         *job);
67 static void ev_job_load_class_init 	      (EvJobLoadClass	     *class);
68 static void ev_job_save_init              (EvJobSave             *job);
69 static void ev_job_save_class_init        (EvJobSaveClass        *class);
70 static void ev_job_find_init              (EvJobFind             *job);
71 static void ev_job_find_class_init        (EvJobFindClass        *class);
72 static void ev_job_layers_init            (EvJobLayers           *job);
73 static void ev_job_layers_class_init      (EvJobLayersClass      *class);
74 static void ev_job_export_init            (EvJobExport           *job);
75 static void ev_job_export_class_init      (EvJobExportClass      *class);
76 static void ev_job_print_init             (EvJobPrint            *job);
77 static void ev_job_print_class_init       (EvJobPrintClass       *class);
78 
79 enum {
80 	CANCELLED,
81 	FINISHED,
82 	LAST_SIGNAL
83 };
84 
85 enum {
86 	FONTS_UPDATED,
87 	FONTS_LAST_SIGNAL
88 };
89 
90 enum {
91 	FIND_UPDATED,
92 	FIND_LAST_SIGNAL
93 };
94 
95 static guint job_signals[LAST_SIGNAL] = { 0 };
96 static guint job_fonts_signals[FONTS_LAST_SIGNAL] = { 0 };
97 static guint job_find_signals[FIND_LAST_SIGNAL] = { 0 };
98 
G_DEFINE_ABSTRACT_TYPE(EvJob,ev_job,G_TYPE_OBJECT)99 G_DEFINE_ABSTRACT_TYPE (EvJob, ev_job, G_TYPE_OBJECT)
100 G_DEFINE_TYPE (EvJobLinks, ev_job_links, EV_TYPE_JOB)
101 G_DEFINE_TYPE (EvJobAttachments, ev_job_attachments, EV_TYPE_JOB)
102 G_DEFINE_TYPE (EvJobAnnots, ev_job_annots, EV_TYPE_JOB)
103 G_DEFINE_TYPE (EvJobRender, ev_job_render, EV_TYPE_JOB)
104 G_DEFINE_TYPE (EvJobPageData, ev_job_page_data, EV_TYPE_JOB)
105 G_DEFINE_TYPE (EvJobThumbnail, ev_job_thumbnail, EV_TYPE_JOB)
106 G_DEFINE_TYPE (EvJobFonts, ev_job_fonts, EV_TYPE_JOB)
107 G_DEFINE_TYPE (EvJobLoad, ev_job_load, EV_TYPE_JOB)
108 G_DEFINE_TYPE (EvJobSave, ev_job_save, EV_TYPE_JOB)
109 G_DEFINE_TYPE (EvJobFind, ev_job_find, EV_TYPE_JOB)
110 G_DEFINE_TYPE (EvJobLayers, ev_job_layers, EV_TYPE_JOB)
111 G_DEFINE_TYPE (EvJobExport, ev_job_export, EV_TYPE_JOB)
112 G_DEFINE_TYPE (EvJobPrint, ev_job_print, EV_TYPE_JOB)
113 
114 /* EvJob */
115 static void
116 ev_job_init (EvJob *job)
117 {
118 	job->cancellable = g_cancellable_new ();
119 }
120 
121 static void
ev_job_dispose(GObject * object)122 ev_job_dispose (GObject *object)
123 {
124 	EvJob *job;
125 
126 	job = EV_JOB (object);
127 
128 	if (job->document) {
129 		g_object_unref (job->document);
130 		job->document = NULL;
131 	}
132 
133 	if (job->cancellable) {
134 		g_object_unref (job->cancellable);
135 		job->cancellable = NULL;
136 	}
137 
138 	if (job->error) {
139 		g_error_free (job->error);
140 		job->error = NULL;
141 	}
142 
143 	(* G_OBJECT_CLASS (ev_job_parent_class)->dispose) (object);
144 }
145 
146 static void
ev_job_class_init(EvJobClass * class)147 ev_job_class_init (EvJobClass *class)
148 {
149 	GObjectClass *oclass;
150 
151 	oclass = G_OBJECT_CLASS (class);
152 
153 	oclass->dispose = ev_job_dispose;
154 
155 	job_signals[CANCELLED] =
156 		g_signal_new ("cancelled",
157 			      EV_TYPE_JOB,
158 			      G_SIGNAL_RUN_LAST,
159 			      G_STRUCT_OFFSET (EvJobClass, cancelled),
160 			      NULL, NULL,
161 			      g_cclosure_marshal_VOID__VOID,
162 			      G_TYPE_NONE, 0);
163 	job_signals [FINISHED] =
164 		g_signal_new ("finished",
165 			      EV_TYPE_JOB,
166 			      G_SIGNAL_RUN_FIRST,
167 			      G_STRUCT_OFFSET (EvJobClass, finished),
168 			      NULL, NULL,
169 			      g_cclosure_marshal_VOID__VOID,
170 			      G_TYPE_NONE, 0);
171 }
172 
173 static gboolean
emit_finished(EvJob * job)174 emit_finished (EvJob *job)
175 {
176 	ev_debug_message (DEBUG_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
177 
178 	job->idle_finished_id = 0;
179 
180 	if (job->cancelled) {
181 		ev_debug_message (DEBUG_JOBS, "%s (%p) job was cancelled, do not emit finished", EV_GET_TYPE_NAME (job), job);
182 	} else {
183 		ev_profiler_stop (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
184 		g_signal_emit (job, job_signals[FINISHED], 0);
185 	}
186 
187 	return FALSE;
188 }
189 
190 static void
ev_job_emit_finished(EvJob * job)191 ev_job_emit_finished (EvJob *job)
192 {
193 	ev_debug_message (DEBUG_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
194 
195 	if (g_cancellable_is_cancelled (job->cancellable)) {
196 		ev_debug_message (DEBUG_JOBS, "%s (%p) job was cancelled, returning", EV_GET_TYPE_NAME (job), job);
197 		return;
198 	}
199 
200 	job->finished = TRUE;
201 
202 	if (job->run_mode == EV_JOB_RUN_THREAD) {
203 		job->idle_finished_id =
204 			g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
205 					 (GSourceFunc)emit_finished,
206 					 g_object_ref (job),
207 					 (GDestroyNotify)g_object_unref);
208 	} else {
209 		ev_profiler_stop (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
210 		g_signal_emit (job, job_signals[FINISHED], 0);
211 	}
212 }
213 
214 gboolean
ev_job_run(EvJob * job)215 ev_job_run (EvJob *job)
216 {
217 	EvJobClass *class = EV_JOB_GET_CLASS (job);
218 
219 	return class->  run (job);
220 }
221 
222 void
ev_job_cancel(EvJob * job)223 ev_job_cancel (EvJob *job)
224 {
225 	if (job->cancelled)
226 		return;
227 
228 	ev_debug_message (DEBUG_JOBS, "job %s (%p) cancelled", EV_GET_TYPE_NAME (job), job);
229 	ev_profiler_stop (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
230 
231 	/* This should never be called from a thread */
232 	job->cancelled = TRUE;
233 	g_cancellable_cancel (job->cancellable);
234 
235         if (job->finished && job->idle_finished_id == 0)
236                 return;
237 
238 	g_signal_emit (job, job_signals[CANCELLED], 0);
239 }
240 
241 void
ev_job_failed(EvJob * job,GQuark domain,gint code,const gchar * format,...)242 ev_job_failed (EvJob       *job,
243 	       GQuark       domain,
244 	       gint         code,
245 	       const gchar *format,
246 	       ...)
247 {
248 	va_list args;
249 	gchar  *message;
250 
251 	if (job->failed || job->finished)
252 		return;
253 
254 	ev_debug_message (DEBUG_JOBS, "job %s (%p) failed", EV_GET_TYPE_NAME (job), job);
255 
256 	job->failed = TRUE;
257 
258 	va_start (args, format);
259 	message = g_strdup_vprintf (format, args);
260 	va_end (args);
261 
262 	job->error = g_error_new_literal (domain, code, message);
263 	g_free (message);
264 
265 	ev_job_emit_finished (job);
266 }
267 
268 void
ev_job_failed_from_error(EvJob * job,GError * error)269 ev_job_failed_from_error (EvJob  *job,
270 			  GError *error)
271 {
272 	if (job->failed || job->finished)
273 		return;
274 
275 	ev_debug_message (DEBUG_JOBS, "job %s (%p) failed", EV_GET_TYPE_NAME (job), job);
276 
277 	job->failed = TRUE;
278 	job->error = g_error_copy (error);
279 
280 	ev_job_emit_finished (job);
281 }
282 
283 void
ev_job_succeeded(EvJob * job)284 ev_job_succeeded (EvJob *job)
285 {
286 	if (job->finished)
287 		return;
288 
289 	ev_debug_message (DEBUG_JOBS, "job %s (%p) succeeded", EV_GET_TYPE_NAME (job), job);
290 
291 	job->failed = FALSE;
292 	ev_job_emit_finished (job);
293 }
294 
295 gboolean
ev_job_is_finished(EvJob * job)296 ev_job_is_finished (EvJob *job)
297 {
298 	return job->finished;
299 }
300 
301 gboolean
ev_job_is_failed(EvJob * job)302 ev_job_is_failed (EvJob *job)
303 {
304 	return job->failed;
305 }
306 
307 EvJobRunMode
ev_job_get_run_mode(EvJob * job)308 ev_job_get_run_mode (EvJob *job)
309 {
310 	return job->run_mode;
311 }
312 
313 void
ev_job_set_run_mode(EvJob * job,EvJobRunMode run_mode)314 ev_job_set_run_mode (EvJob       *job,
315 		     EvJobRunMode run_mode)
316 {
317 	job->run_mode = run_mode;
318 }
319 
320 /* EvJobLinks */
321 static void
ev_job_links_init(EvJobLinks * job)322 ev_job_links_init (EvJobLinks *job)
323 {
324 	EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
325 }
326 
327 static void
ev_job_links_dispose(GObject * object)328 ev_job_links_dispose (GObject *object)
329 {
330 	EvJobLinks *job;
331 
332 	ev_debug_message (DEBUG_JOBS, NULL);
333 
334 	job = EV_JOB_LINKS (object);
335 
336 	if (job->model) {
337 		g_object_unref (job->model);
338 		job->model = NULL;
339 	}
340 
341 	(* G_OBJECT_CLASS (ev_job_links_parent_class)->dispose) (object);
342 }
343 
344 static gboolean
fill_page_labels(GtkTreeModel * tree_model,GtkTreePath * path,GtkTreeIter * iter,EvJob * job)345 fill_page_labels (GtkTreeModel   *tree_model,
346 		  GtkTreePath    *path,
347 		  GtkTreeIter    *iter,
348 		  EvJob          *job)
349 {
350 	EvDocumentLinks *document_links;
351 	EvLink          *link;
352 	gchar           *page_label;
353 
354 	gtk_tree_model_get (tree_model, iter,
355 			    EV_DOCUMENT_LINKS_COLUMN_LINK, &link,
356 			    -1);
357 
358 	if (!link)
359 		return FALSE;
360 
361 	document_links = EV_DOCUMENT_LINKS (job->document);
362 	page_label = ev_document_links_get_link_page_label (document_links, link);
363 	if (!page_label)
364 		return FALSE;
365 
366 	gtk_tree_store_set (GTK_TREE_STORE (tree_model), iter,
367 			    EV_DOCUMENT_LINKS_COLUMN_PAGE_LABEL, page_label,
368 			    -1);
369 
370 	g_free (page_label);
371 	g_object_unref (link);
372 
373 	return FALSE;
374 }
375 
376 static gboolean
ev_job_links_run(EvJob * job)377 ev_job_links_run (EvJob *job)
378 {
379 	EvJobLinks *job_links = EV_JOB_LINKS (job);
380 
381 	ev_debug_message (DEBUG_JOBS, NULL);
382 	ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
383 
384 	ev_document_doc_mutex_lock ();
385 	job_links->model = ev_document_links_get_links_model (EV_DOCUMENT_LINKS (job->document));
386 	ev_document_doc_mutex_unlock ();
387 
388 	gtk_tree_model_foreach (job_links->model, (GtkTreeModelForeachFunc)fill_page_labels, job);
389 
390 	ev_job_succeeded (job);
391 
392 	return FALSE;
393 }
394 
395 static void
ev_job_links_class_init(EvJobLinksClass * class)396 ev_job_links_class_init (EvJobLinksClass *class)
397 {
398 	GObjectClass *oclass = G_OBJECT_CLASS (class);
399 	EvJobClass   *job_class = EV_JOB_CLASS (class);
400 
401 	oclass->dispose = ev_job_links_dispose;
402 	job_class->run = ev_job_links_run;
403 }
404 
405 EvJob *
ev_job_links_new(EvDocument * document)406 ev_job_links_new (EvDocument *document)
407 {
408 	EvJob *job;
409 
410 	ev_debug_message (DEBUG_JOBS, NULL);
411 
412 	job = g_object_new (EV_TYPE_JOB_LINKS, NULL);
413 	job->document = g_object_ref (document);
414 
415 	return job;
416 }
417 
418 /* EvJobAttachments */
419 static void
ev_job_attachments_init(EvJobAttachments * job)420 ev_job_attachments_init (EvJobAttachments *job)
421 {
422 	EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
423 }
424 
425 static void
ev_job_attachments_dispose(GObject * object)426 ev_job_attachments_dispose (GObject *object)
427 {
428 	EvJobAttachments *job;
429 
430 	ev_debug_message (DEBUG_JOBS, NULL);
431 
432 	job = EV_JOB_ATTACHMENTS (object);
433 
434 	if (job->attachments) {
435 		g_list_foreach (job->attachments, (GFunc)g_object_unref, NULL);
436 		g_list_free (job->attachments);
437 		job->attachments = NULL;
438 	}
439 
440 	(* G_OBJECT_CLASS (ev_job_attachments_parent_class)->dispose) (object);
441 }
442 
443 static gboolean
ev_job_attachments_run(EvJob * job)444 ev_job_attachments_run (EvJob *job)
445 {
446 	EvJobAttachments *job_attachments = EV_JOB_ATTACHMENTS (job);
447 
448 	ev_debug_message (DEBUG_JOBS, NULL);
449 	ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
450 
451 	ev_document_doc_mutex_lock ();
452 	job_attachments->attachments =
453 		ev_document_attachments_get_attachments (EV_DOCUMENT_ATTACHMENTS (job->document));
454 	ev_document_doc_mutex_unlock ();
455 
456 	ev_job_succeeded (job);
457 
458 	return FALSE;
459 }
460 
461 static void
ev_job_attachments_class_init(EvJobAttachmentsClass * class)462 ev_job_attachments_class_init (EvJobAttachmentsClass *class)
463 {
464 	GObjectClass *oclass = G_OBJECT_CLASS (class);
465 	EvJobClass   *job_class = EV_JOB_CLASS (class);
466 
467 	oclass->dispose = ev_job_attachments_dispose;
468 	job_class->run = ev_job_attachments_run;
469 }
470 
471 EvJob *
ev_job_attachments_new(EvDocument * document)472 ev_job_attachments_new (EvDocument *document)
473 {
474 	EvJob *job;
475 
476 	ev_debug_message (DEBUG_JOBS, NULL);
477 
478 	job = g_object_new (EV_TYPE_JOB_ATTACHMENTS, NULL);
479 	job->document = g_object_ref (document);
480 
481 	return job;
482 }
483 
484 /* EvJobAnnots */
485 static void
ev_job_annots_init(EvJobAnnots * job)486 ev_job_annots_init (EvJobAnnots *job)
487 {
488 	EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
489 }
490 
491 static void
ev_job_annots_dispose(GObject * object)492 ev_job_annots_dispose (GObject *object)
493 {
494 	EvJobAnnots *job;
495 
496 	ev_debug_message (DEBUG_JOBS, NULL);
497 
498 	job = EV_JOB_ANNOTS (object);
499 
500 	if (job->annots) {
501 		g_list_foreach (job->annots, (GFunc)ev_mapping_list_unref, NULL);
502 		g_list_free (job->annots);
503 		job->annots = NULL;
504 	}
505 
506 	G_OBJECT_CLASS (ev_job_annots_parent_class)->dispose (object);
507 }
508 
509 static gboolean
ev_job_annots_run(EvJob * job)510 ev_job_annots_run (EvJob *job)
511 {
512 	EvJobAnnots *job_annots = EV_JOB_ANNOTS (job);
513 	gint         i;
514 
515 	ev_debug_message (DEBUG_JOBS, NULL);
516 	ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
517 
518 	ev_document_doc_mutex_lock ();
519 	for (i = 0; i < ev_document_get_n_pages (job->document); i++) {
520 		EvMappingList *mapping_list;
521 		EvPage        *page;
522 
523 		page = ev_document_get_page (job->document, i);
524 		mapping_list = ev_document_annotations_get_annotations (EV_DOCUMENT_ANNOTATIONS (job->document),
525 									page);
526 		g_object_unref (page);
527 
528 		if (mapping_list)
529 			job_annots->annots = g_list_prepend (job_annots->annots, mapping_list);
530 	}
531 	ev_document_doc_mutex_unlock ();
532 
533 	job_annots->annots = g_list_reverse (job_annots->annots);
534 
535 	ev_job_succeeded (job);
536 
537 	return FALSE;
538 }
539 
540 static void
ev_job_annots_class_init(EvJobAnnotsClass * class)541 ev_job_annots_class_init (EvJobAnnotsClass *class)
542 {
543 	GObjectClass *oclass = G_OBJECT_CLASS (class);
544 	EvJobClass   *job_class = EV_JOB_CLASS (class);
545 
546 	oclass->dispose = ev_job_annots_dispose;
547 	job_class->run = ev_job_annots_run;
548 }
549 
550 EvJob *
ev_job_annots_new(EvDocument * document)551 ev_job_annots_new (EvDocument *document)
552 {
553 	EvJob *job;
554 
555 	ev_debug_message (DEBUG_JOBS, NULL);
556 
557 	job = g_object_new (EV_TYPE_JOB_ANNOTS, NULL);
558 	job->document = g_object_ref (document);
559 
560 	return job;
561 }
562 
563 /* EvJobRender */
564 static void
ev_job_render_init(EvJobRender * job)565 ev_job_render_init (EvJobRender *job)
566 {
567 	EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
568 }
569 
570 static void
ev_job_render_dispose(GObject * object)571 ev_job_render_dispose (GObject *object)
572 {
573 	EvJobRender *job;
574 
575 	job = EV_JOB_RENDER (object);
576 
577 	ev_debug_message (DEBUG_JOBS, "page: %d (%p)", job->page, job);
578 
579 	if (job->surface) {
580 		cairo_surface_destroy (job->surface);
581 		job->surface = NULL;
582 	}
583 
584 	if (job->selection) {
585 		cairo_surface_destroy (job->selection);
586 		job->selection = NULL;
587 	}
588 
589 	if (job->selection_region) {
590 		cairo_region_destroy (job->selection_region);
591 		job->selection_region = NULL;
592 	}
593 
594 	(* G_OBJECT_CLASS (ev_job_render_parent_class)->dispose) (object);
595 }
596 
597 static gboolean
ev_job_render_run(EvJob * job)598 ev_job_render_run (EvJob *job)
599 {
600 	EvJobRender     *job_render = EV_JOB_RENDER (job);
601 	EvPage          *ev_page;
602 	EvRenderContext *rc;
603 
604 	ev_debug_message (DEBUG_JOBS, "page: %d (%p)", job_render->page, job);
605 	ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
606 
607 	ev_document_doc_mutex_lock ();
608 
609 	ev_profiler_start (EV_PROFILE_JOBS, "Rendering page %d", job_render->page);
610 
611 	ev_document_fc_mutex_lock ();
612 
613 	ev_page = ev_document_get_page (job->document, job_render->page);
614 
615 	if ( job->document->iswebdocument == TRUE )
616 	{
617 		return TRUE;
618 
619 		if (g_cancellable_is_cancelled (job->cancellable)) {
620 		ev_document_fc_mutex_unlock ();
621 		ev_document_doc_mutex_unlock ();
622 		g_object_unref (rc);
623 
624 		return FALSE;
625 		}
626 
627 		ev_document_fc_mutex_unlock ();
628 		ev_document_doc_mutex_unlock ();
629 		ev_job_succeeded (job);
630 		return FALSE;
631 	}
632 	rc = ev_render_context_new (ev_page, job_render->rotation, job_render->scale);
633 	g_object_unref (ev_page);
634 
635 	job_render->surface = ev_document_render (job->document, rc);
636 	/* If job was cancelled during the page rendering,
637 	 * we return now, so that the thread is finished ASAP
638 	 */
639 	if (g_cancellable_is_cancelled (job->cancellable)) {
640 		ev_document_fc_mutex_unlock ();
641 		ev_document_doc_mutex_unlock ();
642 		g_object_unref (rc);
643 
644 		return FALSE;
645 	}
646 
647 	if (job_render->include_selection && EV_IS_SELECTION (job->document)) {
648 		ev_selection_render_selection (EV_SELECTION (job->document),
649 					       rc,
650 					       &(job_render->selection),
651 					       &(job_render->selection_points),
652 					       NULL,
653 					       job_render->selection_style,
654 					       &(job_render->text), &(job_render->base));
655 		job_render->selection_region =
656 			ev_selection_get_selection_region (EV_SELECTION (job->document),
657 							   rc,
658 							   job_render->selection_style,
659 							   &(job_render->selection_points));
660 	}
661 
662 	g_object_unref (rc);
663 
664 	ev_document_fc_mutex_unlock ();
665 	ev_document_doc_mutex_unlock ();
666 
667 	ev_job_succeeded (job);
668 
669 	return FALSE;
670 }
671 
672 static void
ev_job_render_class_init(EvJobRenderClass * class)673 ev_job_render_class_init (EvJobRenderClass *class)
674 {
675 	GObjectClass *oclass = G_OBJECT_CLASS (class);
676 	EvJobClass   *job_class = EV_JOB_CLASS (class);
677 
678 	oclass->dispose = ev_job_render_dispose;
679 	job_class->run = ev_job_render_run;
680 }
681 
682 EvJob *
ev_job_render_new(EvDocument * document,gint page,gint rotation,gdouble scale,gint width,gint height)683 ev_job_render_new (EvDocument   *document,
684 		   gint          page,
685 		   gint          rotation,
686 		   gdouble       scale,
687 		   gint          width,
688 		   gint          height)
689 {
690 	EvJobRender *job;
691 
692 	ev_debug_message (DEBUG_JOBS, "page: %d", page);
693 
694 	job = g_object_new (EV_TYPE_JOB_RENDER, NULL);
695 
696 	EV_JOB (job)->document = g_object_ref (document);
697 	job->page = page;
698 	job->rotation = rotation;
699 	job->scale = scale;
700 	job->target_width = width;
701 	job->target_height = height;
702 
703 	return EV_JOB (job);
704 }
705 
706 void
ev_job_render_set_selection_info(EvJobRender * job,EvRectangle * selection_points,EvSelectionStyle selection_style,GdkColor * text,GdkColor * base)707 ev_job_render_set_selection_info (EvJobRender     *job,
708 				  EvRectangle     *selection_points,
709 				  EvSelectionStyle selection_style,
710 				  GdkColor        *text,
711 				  GdkColor        *base)
712 {
713 	job->include_selection = TRUE;
714 
715 	job->selection_points = *selection_points;
716 	job->selection_style = selection_style;
717 	job->text = *text;
718 	job->base = *base;
719 }
720 
721 /* EvJobPageData */
722 static void
ev_job_page_data_init(EvJobPageData * job)723 ev_job_page_data_init (EvJobPageData *job)
724 {
725 	EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
726 }
727 
728 static gboolean
ev_job_page_data_run(EvJob * job)729 ev_job_page_data_run (EvJob *job)
730 {
731 	EvJobPageData *job_pd = EV_JOB_PAGE_DATA (job);
732 	EvPage        *ev_page;
733 
734 	ev_debug_message (DEBUG_JOBS, "page: %d (%p)", job_pd->page, job);
735 	ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
736 
737 	ev_document_doc_mutex_lock ();
738 	ev_page = ev_document_get_page (job->document, job_pd->page);
739 
740 	if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_TEXT_MAPPING) && EV_IS_DOCUMENT_TEXT (job->document))
741 		job_pd->text_mapping =
742 			ev_document_text_get_text_mapping (EV_DOCUMENT_TEXT (job->document), ev_page);
743 	if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_TEXT) && EV_IS_DOCUMENT_TEXT (job->document))
744 		job_pd->text =
745 			ev_document_text_get_text (EV_DOCUMENT_TEXT (job->document), ev_page);
746 	if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_TEXT_LAYOUT) && EV_IS_DOCUMENT_TEXT (job->document))
747 		ev_document_text_get_text_layout (EV_DOCUMENT_TEXT (job->document),
748 						  ev_page,
749 						  &(job_pd->text_layout),
750 						  &(job_pd->text_layout_length));
751 	if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_LINKS) && EV_IS_DOCUMENT_LINKS (job->document))
752 		job_pd->link_mapping =
753 			ev_document_links_get_links (EV_DOCUMENT_LINKS (job->document), ev_page);
754 	if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_FORMS) && EV_IS_DOCUMENT_FORMS (job->document))
755 		job_pd->form_field_mapping =
756 			ev_document_forms_get_form_fields (EV_DOCUMENT_FORMS (job->document),
757 							   ev_page);
758 	if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_IMAGES) && EV_IS_DOCUMENT_IMAGES (job->document))
759 		job_pd->image_mapping =
760 			ev_document_images_get_image_mapping (EV_DOCUMENT_IMAGES (job->document),
761 							      ev_page);
762 	if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_ANNOTS) && EV_IS_DOCUMENT_ANNOTATIONS (job->document))
763 		job_pd->annot_mapping =
764 			ev_document_annotations_get_annotations (EV_DOCUMENT_ANNOTATIONS (job->document),
765 								 ev_page);
766 	g_object_unref (ev_page);
767 	ev_document_doc_mutex_unlock ();
768 
769 	ev_job_succeeded (job);
770 
771 	return FALSE;
772 }
773 
774 static void
ev_job_page_data_class_init(EvJobPageDataClass * class)775 ev_job_page_data_class_init (EvJobPageDataClass *class)
776 {
777 	EvJobClass *job_class = EV_JOB_CLASS (class);
778 
779 	job_class->run = ev_job_page_data_run;
780 }
781 
782 EvJob *
ev_job_page_data_new(EvDocument * document,gint page,EvJobPageDataFlags flags)783 ev_job_page_data_new (EvDocument        *document,
784 		      gint               page,
785 		      EvJobPageDataFlags flags)
786 {
787 	EvJobPageData *job;
788 
789 	ev_debug_message (DEBUG_JOBS, "%d", page);
790 
791 	job = g_object_new (EV_TYPE_JOB_PAGE_DATA, NULL);
792 
793 	EV_JOB (job)->document = g_object_ref (document);
794 	job->page = page;
795 	job->flags = flags;
796 
797 	return EV_JOB (job);
798 }
799 
800 /* EvJobThumbnail */
801 static void
ev_job_thumbnail_init(EvJobThumbnail * job)802 ev_job_thumbnail_init (EvJobThumbnail *job)
803 {
804 		EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
805 }
806 
807 static void
ev_job_thumbnail_dispose(GObject * object)808 ev_job_thumbnail_dispose (GObject *object)
809 {
810 	EvJobThumbnail *job;
811 
812 	job = EV_JOB_THUMBNAIL (object);
813 
814 	ev_debug_message (DEBUG_JOBS, "%d (%p)", job->page, job);
815 
816 	if (job->thumbnail) {
817 		g_object_unref (job->thumbnail);
818 		job->thumbnail = NULL;
819 	}
820 
821 	(* G_OBJECT_CLASS (ev_job_thumbnail_parent_class)->dispose) (object);
822 }
823 
824 #if ENABLE_EPUB
825 
826 static void
snapshot_callback(WebKitWebView * webview,GAsyncResult * results,EvJobThumbnail * job_thumb)827 snapshot_callback(WebKitWebView *webview,
828                   GAsyncResult  *results,
829                   EvJobThumbnail *job_thumb)
830 {
831 	GError *error = NULL;
832 
833 	ev_document_doc_mutex_lock ();
834 
835 	EvPage *page = ev_document_get_page (EV_JOB(job_thumb)->document, job_thumb->page);
836 	job_thumb->surface = webkit_web_view_get_snapshot_finish (webview,
837 	                                                          results,
838 	                                                          &error);
839 
840 	if (error) {
841 		g_warning ("Error retrieving a snapshot: %s", error->message);
842 	}
843 
844 	EvRenderContext *rc = ev_render_context_new (page, job_thumb->rotation, job_thumb->scale);
845 	EvPage *screenshotpage;
846 	screenshotpage = ev_page_new(job_thumb->page);
847 	screenshotpage->backend_page = (EvBackendPage)job_thumb->surface;
848 	screenshotpage->backend_destroy_func = (EvBackendPageDestroyFunc)cairo_surface_destroy;
849 	ev_render_context_set_page(rc,screenshotpage);
850 
851 	job_thumb->thumbnail = ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (EV_JOB(job_thumb)->document),
852 	                                                             rc, TRUE);
853 	g_object_unref(screenshotpage);
854 	g_object_unref(rc);
855 
856 	ev_document_doc_mutex_unlock ();
857 	ev_job_succeeded (EV_JOB(job_thumb));
858 
859 	gtk_widget_destroy (gtk_widget_get_toplevel (GTK_WIDGET (webview)));
860 }
861 
862 
863 static void
web_thumbnail_get_screenshot_cb(WebKitWebView * webview,WebKitLoadEvent event,EvJobThumbnail * job_thumb)864 web_thumbnail_get_screenshot_cb (WebKitWebView  *webview,
865                                  WebKitLoadEvent event,
866                                  EvJobThumbnail *job_thumb)
867 {
868 	if (event != WEBKIT_LOAD_FINISHED || ev_job_is_failed (EV_JOB(job_thumb))) {
869 		return;
870 	}
871 
872 	webkit_web_view_get_snapshot (webview,
873 	                              WEBKIT_SNAPSHOT_REGION_VISIBLE,
874 	                              WEBKIT_SNAPSHOT_OPTIONS_NONE,
875 	                              NULL,
876 	                              (GAsyncReadyCallback)snapshot_callback,
877 	                              g_object_ref (job_thumb));
878 }
879 
880 static gboolean
webview_load_failed_cb(WebKitWebView * webview,WebKitLoadEvent event,gchar * failing_uri,gpointer error,EvJobThumbnail * job_thumb)881 webview_load_failed_cb (WebKitWebView  *webview,
882                         WebKitLoadEvent event,
883                         gchar          *failing_uri,
884                         gpointer        error,
885                         EvJobThumbnail *job_thumb)
886 {
887 	GError *e = (GError *) error;
888 	g_warning ("Error loading data from %s: %s", failing_uri, e->message);
889 	ev_job_failed_from_error (EV_JOB(job_thumb), e);
890 
891 	gtk_widget_destroy (gtk_widget_get_toplevel (GTK_WIDGET (webview)));
892 
893 	return TRUE;
894 }
895 
896 #endif  /* ENABLE_EPUB */
897 
898 static gboolean
ev_job_thumbnail_run(EvJob * job)899 ev_job_thumbnail_run (EvJob *job)
900 {
901 	EvJobThumbnail  *job_thumb = EV_JOB_THUMBNAIL (job);
902 	EvRenderContext *rc;
903 	EvPage          *page;
904 	ev_debug_message (DEBUG_JOBS, "%d (%p)", job_thumb->page, job);
905 	ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
906 
907 	if (job->document->iswebdocument) {
908 		/* Do not block the main loop */
909 		if (!ev_document_doc_mutex_trylock ())
910 			return TRUE;
911 	} else {
912 		ev_document_doc_mutex_lock ();
913 	}
914 
915 	page = ev_document_get_page (job->document, job_thumb->page);
916 	ev_document_doc_mutex_unlock ();
917 
918 	if (job->document->iswebdocument == TRUE ) {
919 		rc = ev_render_context_new (page, 0, job_thumb->scale);
920 	} else {
921 		rc = ev_render_context_new (page, job_thumb->rotation, job_thumb->scale);
922 	}
923 	g_object_unref (page);
924 
925 #if ENABLE_EPUB
926 	if (job->document->iswebdocument == TRUE) {
927 
928 		GtkWidget *webview;
929 		GtkWidget *offscreenwindow;
930 
931 		webview = webkit_web_view_new ();
932 		offscreenwindow = gtk_offscreen_window_new ();
933 
934 		gtk_container_add (GTK_CONTAINER(offscreenwindow), GTK_WIDGET (webview));
935 		gtk_window_set_default_size (GTK_WINDOW(offscreenwindow), 800, 1080);
936 		gtk_widget_show_all (offscreenwindow);
937 
938 		g_signal_connect (WEBKIT_WEB_VIEW (webview), "load-changed",
939 		                  G_CALLBACK (web_thumbnail_get_screenshot_cb),
940 		                  g_object_ref (job_thumb));
941 		g_signal_connect (WEBKIT_WEB_VIEW(webview), "load-failed",
942 		                  G_CALLBACK(webview_load_failed_cb),
943 		                  g_object_ref (job_thumb));
944 		webkit_web_view_load_uri (WEBKIT_WEB_VIEW(webview), (gchar*) rc->page->backend_page);
945 	}
946 	else
947 #endif  /* ENABLE_EPUB */
948 	{
949 		ev_document_doc_mutex_lock ();
950 		job_thumb->thumbnail = ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (job->document),
951 		                                                             rc, TRUE);
952 		ev_document_doc_mutex_unlock ();
953 		ev_job_succeeded (job);
954 	}
955 	g_object_unref (rc);
956 
957 	return FALSE;
958 }
959 
960 static void
ev_job_thumbnail_class_init(EvJobThumbnailClass * class)961 ev_job_thumbnail_class_init (EvJobThumbnailClass *class)
962 {
963 	GObjectClass *oclass = G_OBJECT_CLASS (class);
964 	EvJobClass   *job_class = EV_JOB_CLASS (class);
965 
966 	oclass->dispose = ev_job_thumbnail_dispose;
967 	job_class->run = ev_job_thumbnail_run;
968 }
969 
970 EvJob *
ev_job_thumbnail_new(EvDocument * document,gint page,gint rotation,gdouble scale)971 ev_job_thumbnail_new (EvDocument *document,
972 		      gint        page,
973 		      gint        rotation,
974 		      gdouble     scale)
975 {
976 	EvJobThumbnail *job;
977 
978 	ev_debug_message (DEBUG_JOBS, "%d", page);
979 
980 	job = g_object_new (EV_TYPE_JOB_THUMBNAIL, NULL);
981 
982 	EV_JOB (job)->document = g_object_ref (document);
983 	job->page = page;
984 	job->rotation = rotation;
985 	job->scale = scale;
986 
987 	return EV_JOB (job);
988 }
989 
990 /* EvJobFonts */
991 static void
ev_job_fonts_init(EvJobFonts * job)992 ev_job_fonts_init (EvJobFonts *job)
993 {
994 	EV_JOB (job)->run_mode = EV_JOB_RUN_MAIN_LOOP;
995 }
996 
997 static gboolean
ev_job_fonts_run(EvJob * job)998 ev_job_fonts_run (EvJob *job)
999 {
1000 	EvJobFonts      *job_fonts = EV_JOB_FONTS (job);
1001 	EvDocumentFonts *fonts = EV_DOCUMENT_FONTS (job->document);
1002 
1003 	ev_debug_message (DEBUG_JOBS, NULL);
1004 
1005 	/* Do not block the main loop */
1006 	if (!ev_document_doc_mutex_trylock ())
1007 		return TRUE;
1008 
1009 	if (!ev_document_fc_mutex_trylock ()) {
1010 		ev_document_doc_mutex_unlock ();
1011 		return TRUE;
1012 	}
1013 
1014 #ifdef EV_ENABLE_DEBUG
1015 	/* We use the #ifdef in this case because of the if */
1016 	if (ev_document_fonts_get_progress (fonts) == 0)
1017 		ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1018 #endif
1019 
1020 	job_fonts->scan_completed = !ev_document_fonts_scan (fonts, 20);
1021 	g_signal_emit (job_fonts, job_fonts_signals[FONTS_UPDATED], 0,
1022 		       ev_document_fonts_get_progress (fonts));
1023 
1024 	ev_document_fc_mutex_unlock ();
1025 	ev_document_doc_mutex_unlock ();
1026 
1027 	if (job_fonts->scan_completed)
1028 		ev_job_succeeded (job);
1029 
1030 	return !job_fonts->scan_completed;
1031 }
1032 
1033 static void
ev_job_fonts_class_init(EvJobFontsClass * class)1034 ev_job_fonts_class_init (EvJobFontsClass *class)
1035 {
1036 	EvJobClass *job_class = EV_JOB_CLASS (class);
1037 
1038 	job_class->run = ev_job_fonts_run;
1039 
1040 	job_fonts_signals[FONTS_UPDATED] =
1041 		g_signal_new ("updated",
1042 			      EV_TYPE_JOB_FONTS,
1043 			      G_SIGNAL_RUN_LAST,
1044 			      G_STRUCT_OFFSET (EvJobFontsClass, updated),
1045 			      NULL, NULL,
1046 			      g_cclosure_marshal_VOID__DOUBLE,
1047 			      G_TYPE_NONE,
1048 			      1, G_TYPE_DOUBLE);
1049 }
1050 
1051 EvJob *
ev_job_fonts_new(EvDocument * document)1052 ev_job_fonts_new (EvDocument *document)
1053 {
1054 	EvJobFonts *job;
1055 
1056 	ev_debug_message (DEBUG_JOBS, NULL);
1057 
1058 	job = g_object_new (EV_TYPE_JOB_FONTS, NULL);
1059 
1060 	EV_JOB (job)->document = g_object_ref (document);
1061 
1062 	return EV_JOB (job);
1063 }
1064 
1065 /* EvJobLoad */
1066 static void
ev_job_load_init(EvJobLoad * job)1067 ev_job_load_init (EvJobLoad *job)
1068 {
1069 	EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
1070 }
1071 
1072 static void
ev_job_load_dispose(GObject * object)1073 ev_job_load_dispose (GObject *object)
1074 {
1075 	EvJobLoad *job = EV_JOB_LOAD (object);
1076 
1077 	ev_debug_message (DEBUG_JOBS, "%s", job->uri);
1078 
1079 	if (job->uri) {
1080 		g_free (job->uri);
1081 		job->uri = NULL;
1082 	}
1083 
1084 	if (job->password) {
1085 		g_free (job->password);
1086 		job->password = NULL;
1087 	}
1088 
1089 	(* G_OBJECT_CLASS (ev_job_load_parent_class)->dispose) (object);
1090 }
1091 
1092 static gboolean
ev_job_load_run(EvJob * job)1093 ev_job_load_run (EvJob *job)
1094 {
1095 	EvJobLoad *job_load = EV_JOB_LOAD (job);
1096 	GError    *error = NULL;
1097 
1098 	ev_debug_message (DEBUG_JOBS, "%s", job_load->uri);
1099 	ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1100 
1101 	ev_document_fc_mutex_lock ();
1102 
1103 	/* This job may already have a document even if the job didn't complete
1104 	   because, e.g., a password is required - if so, just reload rather than
1105 	   creating a new instance */
1106 	if (job->document) {
1107 		const gchar *uncompressed_uri;
1108 
1109 		if (job_load->password) {
1110 			ev_document_security_set_password (EV_DOCUMENT_SECURITY (job->document),
1111 							   job_load->password);
1112 		}
1113 
1114 		job->failed = FALSE;
1115 		job->finished = FALSE;
1116 		g_clear_error (&job->error);
1117 
1118 		uncompressed_uri = g_object_get_data (G_OBJECT (job->document),
1119 						      "uri-uncompressed");
1120 		ev_document_load (job->document,
1121 				  uncompressed_uri ? uncompressed_uri : job_load->uri,
1122 				  &error);
1123 	} else {
1124 		job->document = ev_document_factory_get_document (job_load->uri,
1125 								  &error);
1126 	}
1127 
1128 	ev_document_fc_mutex_unlock ();
1129 
1130 	if (error) {
1131 		ev_job_failed_from_error (job, error);
1132 		g_error_free (error);
1133 	} else {
1134 		ev_job_succeeded (job);
1135 	}
1136 
1137 	return FALSE;
1138 }
1139 
1140 static void
ev_job_load_class_init(EvJobLoadClass * class)1141 ev_job_load_class_init (EvJobLoadClass *class)
1142 {
1143 	GObjectClass *oclass = G_OBJECT_CLASS (class);
1144 	EvJobClass   *job_class = EV_JOB_CLASS (class);
1145 
1146 	oclass->dispose = ev_job_load_dispose;
1147 	job_class->run = ev_job_load_run;
1148 }
1149 
1150 EvJob *
ev_job_load_new(const gchar * uri)1151 ev_job_load_new (const gchar *uri)
1152 {
1153 	EvJobLoad *job;
1154 
1155 	ev_debug_message (DEBUG_JOBS, "%s", uri);
1156 
1157 	job = g_object_new (EV_TYPE_JOB_LOAD, NULL);
1158 	job->uri = g_strdup (uri);
1159 
1160 	return EV_JOB (job);
1161 }
1162 
1163 void
ev_job_load_set_uri(EvJobLoad * job,const gchar * uri)1164 ev_job_load_set_uri (EvJobLoad *job, const gchar *uri)
1165 {
1166 	ev_debug_message (DEBUG_JOBS, "%s", uri);
1167 
1168 	if (job->uri)
1169 		g_free (job->uri);
1170 	job->uri = g_strdup (uri);
1171 }
1172 
1173 void
ev_job_load_set_password(EvJobLoad * job,const gchar * password)1174 ev_job_load_set_password (EvJobLoad *job, const gchar *password)
1175 {
1176 	ev_debug_message (DEBUG_JOBS, NULL);
1177 
1178 	if (job->password)
1179 		g_free (job->password);
1180 	job->password = password ? g_strdup (password) : NULL;
1181 }
1182 
1183 /* EvJobSave */
1184 static void
ev_job_save_init(EvJobSave * job)1185 ev_job_save_init (EvJobSave *job)
1186 {
1187 	EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
1188 }
1189 
1190 static void
ev_job_save_dispose(GObject * object)1191 ev_job_save_dispose (GObject *object)
1192 {
1193 	EvJobSave *job = EV_JOB_SAVE (object);
1194 
1195 	ev_debug_message (DEBUG_JOBS, "%s", job->uri);
1196 
1197 	if (job->uri) {
1198 		g_free (job->uri);
1199 		job->uri = NULL;
1200 	}
1201 
1202 	if (job->document_uri) {
1203 		g_free (job->document_uri);
1204 		job->document_uri = NULL;
1205 	}
1206 
1207 	(* G_OBJECT_CLASS (ev_job_save_parent_class)->dispose) (object);
1208 }
1209 
1210 static gboolean
ev_job_save_run(EvJob * job)1211 ev_job_save_run (EvJob *job)
1212 {
1213 	EvJobSave *job_save = EV_JOB_SAVE (job);
1214 	gint       fd;
1215 	gchar     *tmp_filename = NULL;
1216 	gchar     *local_uri;
1217 	GError    *error = NULL;
1218 
1219 	ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", job_save->uri, job_save->document_uri);
1220 	ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1221 
1222         fd = ev_mkstemp ("saveacopy.XXXXXX", &tmp_filename, &error);
1223         if (fd == -1) {
1224                 ev_job_failed_from_error (job, error);
1225                 g_error_free (error);
1226 
1227 		return FALSE;
1228 	}
1229 
1230 	ev_document_doc_mutex_lock ();
1231 
1232 	/* Save document to temp filename */
1233 	local_uri = g_filename_to_uri (tmp_filename, NULL, &error);
1234         if (local_uri != NULL) {
1235                 ev_document_save (job->document, local_uri, &error);
1236         }
1237 
1238 	close (fd);
1239 
1240 	ev_document_doc_mutex_unlock ();
1241 
1242 	if (error) {
1243 		g_free (local_uri);
1244 		ev_job_failed_from_error (job, error);
1245 		g_error_free (error);
1246 
1247 		return FALSE;
1248 	}
1249 
1250 	/* If original document was compressed,
1251 	 * compress it again before saving
1252 	 */
1253 	if (g_object_get_data (G_OBJECT (job->document), "uri-uncompressed")) {
1254 		EvCompressionType ctype = EV_COMPRESSION_NONE;
1255 		const gchar      *ext;
1256 		gchar            *uri_comp;
1257 
1258 		ext = g_strrstr (job_save->document_uri, ".gz");
1259 		if (ext && g_ascii_strcasecmp (ext, ".gz") == 0)
1260 			ctype = EV_COMPRESSION_GZIP;
1261 
1262 		ext = g_strrstr (job_save->document_uri, ".bz2");
1263 		if (ext && g_ascii_strcasecmp (ext, ".bz2") == 0)
1264 			ctype = EV_COMPRESSION_BZIP2;
1265 
1266 		uri_comp = ev_file_compress (local_uri, ctype, &error);
1267 		g_free (local_uri);
1268 		g_unlink (tmp_filename);
1269 
1270 		if (!uri_comp || error) {
1271 			local_uri = NULL;
1272 		} else {
1273 			local_uri = uri_comp;
1274 		}
1275 	}
1276 
1277 	g_free (tmp_filename);
1278 
1279 	if (error) {
1280 		g_free (local_uri);
1281 		ev_job_failed_from_error (job, error);
1282 		g_error_free (error);
1283 
1284 		return FALSE;
1285 	}
1286 
1287 	if (!local_uri)
1288 		return FALSE;
1289 
1290 	ev_xfer_uri_simple (local_uri, job_save->uri, &error);
1291 	ev_tmp_uri_unlink (local_uri);
1292 
1293 	if (error) {
1294 		ev_job_failed_from_error (job, error);
1295 		g_error_free (error);
1296 	} else {
1297 		ev_job_succeeded (job);
1298 	}
1299 
1300 	return FALSE;
1301 }
1302 
1303 static void
ev_job_save_class_init(EvJobSaveClass * class)1304 ev_job_save_class_init (EvJobSaveClass *class)
1305 {
1306 	GObjectClass *oclass = G_OBJECT_CLASS (class);
1307 	EvJobClass   *job_class = EV_JOB_CLASS (class);
1308 
1309 	oclass->dispose = ev_job_save_dispose;
1310 	job_class->run = ev_job_save_run;
1311 }
1312 
1313 EvJob *
ev_job_save_new(EvDocument * document,const gchar * uri,const gchar * document_uri)1314 ev_job_save_new (EvDocument  *document,
1315 		 const gchar *uri,
1316 		 const gchar *document_uri)
1317 {
1318 	EvJobSave *job;
1319 
1320 	ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", uri, document_uri);
1321 
1322 	job = g_object_new (EV_TYPE_JOB_SAVE, NULL);
1323 
1324 	EV_JOB (job)->document = g_object_ref (document);
1325 	job->uri = g_strdup (uri);
1326 	job->document_uri = g_strdup (document_uri);
1327 
1328 	return EV_JOB (job);
1329 }
1330 
1331 /* EvJobFind */
1332 static void
ev_job_find_init(EvJobFind * job)1333 ev_job_find_init (EvJobFind *job)
1334 {
1335 	EV_JOB (job)->run_mode = EV_JOB_RUN_MAIN_LOOP;
1336 }
1337 
1338 static void
ev_job_find_dispose(GObject * object)1339 ev_job_find_dispose (GObject *object)
1340 {
1341 	EvJobFind *job = EV_JOB_FIND (object);
1342 
1343 	ev_debug_message (DEBUG_JOBS, NULL);
1344 
1345 	if (job->text) {
1346 		g_free (job->text);
1347 		job->text = NULL;
1348 	}
1349 
1350 	if (job->pages) {
1351 		gint i;
1352 
1353 		for (i = 0; i < job->n_pages; i++) {
1354 			g_list_foreach (job->pages[i], (GFunc)ev_rectangle_free, NULL);
1355 			g_list_free (job->pages[i]);
1356 		}
1357 
1358 		g_free (job->pages);
1359 		job->pages = NULL;
1360 	}
1361 
1362 	if (job->results) {
1363 		g_free(job->results);
1364 	}
1365 
1366 	(* G_OBJECT_CLASS (ev_job_find_parent_class)->dispose) (object);
1367 }
1368 
1369 static gboolean
ev_job_find_run(EvJob * job)1370 ev_job_find_run (EvJob *job)
1371 {
1372 	EvJobFind      *job_find = EV_JOB_FIND (job);
1373 	EvDocumentFind *find = EV_DOCUMENT_FIND (job->document);
1374 	EvPage         *ev_page;
1375 	GList          *matches;
1376 	ev_debug_message (DEBUG_JOBS, NULL);
1377 
1378 	/* Do not block the main loop */
1379 	if (!ev_document_doc_mutex_trylock ())
1380 		return TRUE;
1381 
1382 #ifdef EV_ENABLE_DEBUG
1383 	/* We use the #ifdef in this case because of the if */
1384 	if (job_find->current_page == job_find->start_page)
1385 		ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1386 #endif
1387 
1388 	ev_page = ev_document_get_page (job->document, job_find->current_page);
1389 
1390 	if (job->document->iswebdocument) {
1391 		job_find->results[job_find->current_page] = ev_document_find_check_for_hits(find, ev_page, job_find->text,
1392 		                                                        job_find->case_sensitive);
1393 	}else {
1394 		matches = ev_document_find_find_text (find, ev_page, job_find->text,
1395 					      job_find->case_sensitive);
1396 	}
1397 
1398 	g_object_unref (ev_page);
1399 
1400 	ev_document_doc_mutex_unlock ();
1401 
1402 	if (!job_find->has_results && !job->document->iswebdocument) {
1403 		job_find->has_results = (matches != NULL);
1404 	}
1405 	else if (!job_find->has_results && job->document->iswebdocument){
1406 		job_find->has_results = (job_find->results[job_find->current_page] > 0);
1407 	}
1408 
1409 	if (job->document->iswebdocument == FALSE) {
1410 		job_find->pages[job_find->current_page] = matches;
1411 	}
1412 
1413 	job_find->total_count += g_list_length(job_find->pages[job_find->current_page]);
1414 
1415 	g_signal_emit (job_find, job_find_signals[FIND_UPDATED], 0, job_find->current_page);
1416 
1417 	job_find->current_page = (job_find->current_page + 1) % job_find->n_pages;
1418 	if (job_find->current_page == job_find->start_page) {
1419 		ev_job_succeeded (job);
1420 
1421 		return FALSE;
1422 	}
1423 
1424 	return TRUE;
1425 }
1426 
1427 static void
ev_job_find_class_init(EvJobFindClass * class)1428 ev_job_find_class_init (EvJobFindClass *class)
1429 {
1430 	EvJobClass   *job_class = EV_JOB_CLASS (class);
1431 	GObjectClass *gobject_class = G_OBJECT_CLASS (class);
1432 
1433 	job_class->run = ev_job_find_run;
1434 	gobject_class->dispose = ev_job_find_dispose;
1435 
1436 	job_find_signals[FIND_UPDATED] =
1437 		g_signal_new ("updated",
1438 			      EV_TYPE_JOB_FIND,
1439 			      G_SIGNAL_RUN_LAST,
1440 			      G_STRUCT_OFFSET (EvJobFindClass, updated),
1441 			      NULL, NULL,
1442 			      g_cclosure_marshal_VOID__INT,
1443 			      G_TYPE_NONE,
1444 			      1, G_TYPE_INT);
1445 }
1446 
1447 EvJob *
ev_job_find_new(EvDocument * document,gint start_page,gint n_pages,const gchar * text,gboolean case_sensitive)1448 ev_job_find_new (EvDocument  *document,
1449 		 gint         start_page,
1450 		 gint         n_pages,
1451 		 const gchar *text,
1452 		 gboolean     case_sensitive)
1453 {
1454 	EvJobFind *job;
1455 
1456 	ev_debug_message (DEBUG_JOBS, NULL);
1457 
1458 	job = g_object_new (EV_TYPE_JOB_FIND, NULL);
1459 
1460 	EV_JOB (job)->document = g_object_ref (document);
1461 	job->start_page = start_page;
1462 	job->current_page = start_page;
1463 	job->n_pages = n_pages;
1464 
1465 	if (document->iswebdocument) {
1466 		job->results = g_malloc0 (sizeof(guint) *n_pages);
1467 	}
1468 	else {
1469 		job->pages = g_new0 (GList *, n_pages);
1470 	}
1471 	job->text = g_strdup (text);
1472 	job->case_sensitive = case_sensitive;
1473 	job->has_results = FALSE;
1474 
1475 	return EV_JOB (job);
1476 }
1477 
1478 gint
ev_job_find_get_n_results(EvJobFind * job,gint page)1479 ev_job_find_get_n_results (EvJobFind *job,
1480 			   gint       page)
1481 {
1482 	if (EV_JOB(job)->document->iswebdocument) {
1483 		return job->results[page];
1484 	}
1485 	else {
1486 		return g_list_length (job->pages[page]);
1487 	}
1488 }
1489 
1490 const gchar *
ev_job_find_get_text(EvJobFind * job)1491 ev_job_find_get_text (EvJobFind *job)
1492 {
1493 	return job->text;
1494 }
1495 
1496 gdouble
ev_job_find_get_progress(EvJobFind * job)1497 ev_job_find_get_progress (EvJobFind *job)
1498 {
1499 	gint pages_done;
1500 
1501 	if (ev_job_is_finished (EV_JOB (job)))
1502 		return 1.0;
1503 
1504 	if (job->current_page > job->start_page) {
1505 		pages_done = job->current_page - job->start_page + 1;
1506 	} else if (job->current_page == job->start_page) {
1507 		pages_done = job->n_pages;
1508 	} else {
1509 		pages_done = job->n_pages - job->start_page + job->current_page;
1510 	}
1511 
1512 	return pages_done / (gdouble) job->n_pages;
1513 }
1514 
1515 gboolean
ev_job_find_has_results(EvJobFind * job)1516 ev_job_find_has_results (EvJobFind *job)
1517 {
1518 	return job->has_results;
1519 }
1520 
1521 GList **
ev_job_find_get_results(EvJobFind * job)1522 ev_job_find_get_results (EvJobFind *job)
1523 {
1524 	return job->pages;
1525 }
1526 
1527 /* EvJobLayers */
1528 static void
ev_job_layers_init(EvJobLayers * job)1529 ev_job_layers_init (EvJobLayers *job)
1530 {
1531 	EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
1532 }
1533 
1534 static void
ev_job_layers_dispose(GObject * object)1535 ev_job_layers_dispose (GObject *object)
1536 {
1537 	EvJobLayers *job;
1538 
1539 	ev_debug_message (DEBUG_JOBS, NULL);
1540 
1541 	job = EV_JOB_LAYERS (object);
1542 
1543 	if (job->model) {
1544 		g_object_unref (job->model);
1545 		job->model = NULL;
1546 	}
1547 
1548 	(* G_OBJECT_CLASS (ev_job_layers_parent_class)->dispose) (object);
1549 }
1550 
1551 static gboolean
ev_job_layers_run(EvJob * job)1552 ev_job_layers_run (EvJob *job)
1553 {
1554 	EvJobLayers *job_layers = EV_JOB_LAYERS (job);
1555 
1556 	ev_debug_message (DEBUG_JOBS, NULL);
1557 	ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1558 
1559 	ev_document_doc_mutex_lock ();
1560 	job_layers->model = ev_document_layers_get_layers (EV_DOCUMENT_LAYERS (job->document));
1561 	ev_document_doc_mutex_unlock ();
1562 
1563 	ev_job_succeeded (job);
1564 
1565 	return FALSE;
1566 }
1567 
1568 static void
ev_job_layers_class_init(EvJobLayersClass * class)1569 ev_job_layers_class_init (EvJobLayersClass *class)
1570 {
1571 	GObjectClass *oclass = G_OBJECT_CLASS (class);
1572 	EvJobClass   *job_class = EV_JOB_CLASS (class);
1573 
1574 	oclass->dispose = ev_job_layers_dispose;
1575 	job_class->run = ev_job_layers_run;
1576 }
1577 
1578 EvJob *
ev_job_layers_new(EvDocument * document)1579 ev_job_layers_new (EvDocument *document)
1580 {
1581 	EvJob *job;
1582 
1583 	ev_debug_message (DEBUG_JOBS, NULL);
1584 
1585 	job = g_object_new (EV_TYPE_JOB_LAYERS, NULL);
1586 	job->document = g_object_ref (document);
1587 
1588 	return job;
1589 }
1590 
1591 /* EvJobExport */
1592 static void
ev_job_export_init(EvJobExport * job)1593 ev_job_export_init (EvJobExport *job)
1594 {
1595 	EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
1596 	job->page = -1;
1597 }
1598 
1599 static void
ev_job_export_dispose(GObject * object)1600 ev_job_export_dispose (GObject *object)
1601 {
1602 	EvJobExport *job;
1603 
1604 	ev_debug_message (DEBUG_JOBS, NULL);
1605 
1606 	job = EV_JOB_EXPORT (object);
1607 
1608 	if (job->rc) {
1609 		g_object_unref (job->rc);
1610 		job->rc = NULL;
1611 	}
1612 
1613 	(* G_OBJECT_CLASS (ev_job_export_parent_class)->dispose) (object);
1614 }
1615 
1616 static gboolean
ev_job_export_run(EvJob * job)1617 ev_job_export_run (EvJob *job)
1618 {
1619 	EvJobExport *job_export = EV_JOB_EXPORT (job);
1620 	EvPage      *ev_page;
1621 
1622 	g_assert (job_export->page != -1);
1623 
1624 	ev_debug_message (DEBUG_JOBS, NULL);
1625 	ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1626 
1627 	ev_document_doc_mutex_lock ();
1628 
1629 	ev_page = ev_document_get_page (job->document, job_export->page);
1630 	if (job_export->rc) {
1631 		job->failed = FALSE;
1632 		job->finished = FALSE;
1633 		g_clear_error (&job->error);
1634 
1635 		ev_render_context_set_page (job_export->rc, ev_page);
1636 	} else {
1637 		job_export->rc = ev_render_context_new (ev_page, 0, 1.0);
1638 	}
1639 	g_object_unref (ev_page);
1640 
1641 	ev_file_exporter_do_page (EV_FILE_EXPORTER (job->document), job_export->rc);
1642 
1643 	ev_document_doc_mutex_unlock ();
1644 
1645 	ev_job_succeeded (job);
1646 
1647 	return FALSE;
1648 }
1649 
1650 static void
ev_job_export_class_init(EvJobExportClass * class)1651 ev_job_export_class_init (EvJobExportClass *class)
1652 {
1653 	GObjectClass *oclass = G_OBJECT_CLASS (class);
1654 	EvJobClass   *job_class = EV_JOB_CLASS (class);
1655 
1656 	oclass->dispose = ev_job_export_dispose;
1657 	job_class->run = ev_job_export_run;
1658 }
1659 
1660 EvJob *
ev_job_export_new(EvDocument * document)1661 ev_job_export_new (EvDocument *document)
1662 {
1663 	EvJob *job;
1664 
1665 	ev_debug_message (DEBUG_JOBS, NULL);
1666 
1667 	job = g_object_new (EV_TYPE_JOB_EXPORT, NULL);
1668 	job->document = g_object_ref (document);
1669 
1670 	return job;
1671 }
1672 
1673 void
ev_job_export_set_page(EvJobExport * job,gint page)1674 ev_job_export_set_page (EvJobExport *job,
1675 			gint         page)
1676 {
1677 	job->page = page;
1678 }
1679 
1680 /* EvJobPrint */
1681 static void
ev_job_print_init(EvJobPrint * job)1682 ev_job_print_init (EvJobPrint *job)
1683 {
1684 	EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
1685 	job->page = -1;
1686 }
1687 
1688 static void
ev_job_print_dispose(GObject * object)1689 ev_job_print_dispose (GObject *object)
1690 {
1691 	EvJobPrint *job;
1692 
1693 	ev_debug_message (DEBUG_JOBS, NULL);
1694 
1695 	job = EV_JOB_PRINT (object);
1696 
1697 	if (job->cr) {
1698 		cairo_destroy (job->cr);
1699 		job->cr = NULL;
1700 	}
1701 
1702 	(* G_OBJECT_CLASS (ev_job_print_parent_class)->dispose) (object);
1703 }
1704 
1705 static gboolean
ev_job_print_run(EvJob * job)1706 ev_job_print_run (EvJob *job)
1707 {
1708 	EvJobPrint     *job_print = EV_JOB_PRINT (job);
1709 	EvPage         *ev_page;
1710 	cairo_status_t  cr_status;
1711 
1712 	g_assert (job_print->page != -1);
1713 	g_assert (job_print->cr != NULL);
1714 
1715 	ev_debug_message (DEBUG_JOBS, NULL);
1716 	ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1717 
1718 	job->failed = FALSE;
1719 	job->finished = FALSE;
1720 	g_clear_error (&job->error);
1721 
1722 	ev_document_doc_mutex_lock ();
1723 
1724 	ev_page = ev_document_get_page (job->document, job_print->page);
1725 	ev_document_print_print_page (EV_DOCUMENT_PRINT (job->document),
1726 				      ev_page, job_print->cr);
1727 	g_object_unref (ev_page);
1728 
1729 	ev_document_doc_mutex_unlock ();
1730 
1731         if (g_cancellable_is_cancelled (job->cancellable))
1732                 return FALSE;
1733 
1734 	cr_status = cairo_status (job_print->cr);
1735 	if (cr_status == CAIRO_STATUS_SUCCESS) {
1736 		ev_job_succeeded (job);
1737 	} else {
1738 		ev_job_failed (job,
1739 			       GTK_PRINT_ERROR,
1740 			       GTK_PRINT_ERROR_GENERAL,
1741 			       _("Failed to print page %d: %s"),
1742 			       job_print->page,
1743 			       cairo_status_to_string (cr_status));
1744 	}
1745 
1746 	return FALSE;
1747 }
1748 
1749 static void
ev_job_print_class_init(EvJobPrintClass * class)1750 ev_job_print_class_init (EvJobPrintClass *class)
1751 {
1752 	GObjectClass *oclass = G_OBJECT_CLASS (class);
1753 	EvJobClass   *job_class = EV_JOB_CLASS (class);
1754 
1755 	oclass->dispose = ev_job_print_dispose;
1756 	job_class->run = ev_job_print_run;
1757 }
1758 
1759 EvJob *
ev_job_print_new(EvDocument * document)1760 ev_job_print_new (EvDocument *document)
1761 {
1762 	EvJob *job;
1763 
1764 	ev_debug_message (DEBUG_JOBS, NULL);
1765 
1766 	job = g_object_new (EV_TYPE_JOB_PRINT, NULL);
1767 	job->document = g_object_ref (document);
1768 
1769 	return job;
1770 }
1771 
1772 void
ev_job_print_set_page(EvJobPrint * job,gint page)1773 ev_job_print_set_page (EvJobPrint *job,
1774 		       gint        page)
1775 {
1776 	job->page = page;
1777 }
1778 
1779 void
ev_job_print_set_cairo(EvJobPrint * job,cairo_t * cr)1780 ev_job_print_set_cairo (EvJobPrint *job,
1781 			cairo_t    *cr)
1782 {
1783 	if (job->cr == cr)
1784 		return;
1785 
1786 	if (job->cr)
1787 		cairo_destroy (job->cr);
1788 	job->cr = cr ? cairo_reference (cr) : NULL;
1789 }
1790