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