Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7638 views
1
#include "pdfapp.h"
2
#include "curl_stream.h"
3
4
#include <ctype.h> /* for tolower() */
5
6
#define BEYOND_THRESHHOLD 40
7
#ifndef PATH_MAX
8
#define PATH_MAX (1024)
9
#endif
10
11
#ifndef MAX
12
#define MAX(a,b) ((a) > (b) ? (a) : (b))
13
#endif
14
15
enum panning
16
{
17
DONT_PAN = 0,
18
PAN_TO_TOP,
19
PAN_TO_BOTTOM
20
};
21
22
enum
23
{
24
PDFAPP_OUTLINE_DEFERRED = 1,
25
PDFAPP_OUTLINE_LOAD_NOW = 2
26
};
27
28
static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint, int transition, int searching);
29
static void pdfapp_updatepage(pdfapp_t *app);
30
31
static const int zoomlist[] = { 18, 24, 36, 54, 72, 96, 120, 144, 180, 216, 288, 360, 480, 576 };
32
33
static int zoom_in(int oldres)
34
{
35
int i;
36
for (i = 0; i < nelem(zoomlist) - 1; ++i)
37
if (zoomlist[i] <= oldres && zoomlist[i+1] > oldres)
38
return zoomlist[i+1];
39
return zoomlist[i];
40
}
41
42
static int zoom_out(int oldres)
43
{
44
int i;
45
for (i = 0; i < nelem(zoomlist) - 1; ++i)
46
if (zoomlist[i] < oldres && zoomlist[i+1] >= oldres)
47
return zoomlist[i];
48
return zoomlist[0];
49
}
50
51
static void pdfapp_warn(pdfapp_t *app, const char *fmt, ...)
52
{
53
char buf[1024];
54
va_list ap;
55
va_start(ap, fmt);
56
vsnprintf(buf, sizeof(buf), fmt, ap);
57
va_end(ap);
58
buf[sizeof(buf)-1] = 0;
59
winwarn(app, buf);
60
}
61
62
static void pdfapp_error(pdfapp_t *app, char *msg)
63
{
64
winerror(app, msg);
65
}
66
67
char *pdfapp_version(pdfapp_t *app)
68
{
69
return
70
"MuPDF " FZ_VERSION "\n"
71
"Copyright 2006-2014 Artifex Software, Inc.\n";
72
}
73
74
char *pdfapp_usage(pdfapp_t *app)
75
{
76
return
77
"L\t\t-- rotate left\n"
78
"R\t\t-- rotate right\n"
79
"h\t\t-- scroll left\n"
80
"j down\t\t-- scroll down\n"
81
"k up\t\t-- scroll up\n"
82
"l\t\t-- scroll right\n"
83
"+\t\t-- zoom in\n"
84
"-\t\t-- zoom out\n"
85
"W\t\t-- zoom to fit window width\n"
86
"H\t\t-- zoom to fit window height\n"
87
"Z\t\t-- zoom to fit page\n"
88
"w\t\t-- shrinkwrap\n"
89
"f\t\t-- fullscreen\n"
90
"r\t\t-- reload file\n"
91
". pgdn right spc\t-- next page\n"
92
", pgup left b bkspc\t-- previous page\n"
93
">\t\t-- next 10 pages\n"
94
"<\t\t-- back 10 pages\n"
95
"m\t\t-- mark page for snap back\n"
96
"t\t\t-- pop back to latest mark\n"
97
"1m\t\t-- mark page in register 1\n"
98
"1t\t\t-- go to page in register 1\n"
99
"G\t\t-- go to last page\n"
100
"123g\t\t-- go to page 123\n"
101
"/\t\t-- search forwards for text\n"
102
"?\t\t-- search backwards for text\n"
103
"n\t\t-- find next search result\n"
104
"N\t\t-- find previous search result\n"
105
"c\t\t-- toggle between color and grayscale\n"
106
"i\t\t-- toggle inverted color mode\n"
107
"q\t\t-- quit\n"
108
;
109
}
110
111
void pdfapp_init(fz_context *ctx, pdfapp_t *app)
112
{
113
memset(app, 0, sizeof(pdfapp_t));
114
app->scrw = 640;
115
app->scrh = 480;
116
app->resolution = 72;
117
app->ctx = ctx;
118
119
app->layout_w = 450;
120
app->layout_h = 600;
121
app->layout_em = 12;
122
123
app->transition.duration = 0.25;
124
app->transition.type = FZ_TRANSITION_FADE;
125
#if defined(_WIN32) || defined(_WIN64)
126
app->colorspace = fz_device_bgr(ctx);
127
#else
128
app->colorspace = fz_device_rgb(ctx);
129
#endif
130
app->tint_r = 255;
131
app->tint_g = 250;
132
app->tint_b = 240;
133
}
134
135
void pdfapp_invert(pdfapp_t *app, const fz_rect *rect)
136
{
137
fz_irect b;
138
fz_invert_pixmap_rect(app->ctx, app->image, fz_round_rect(&b, rect));
139
}
140
141
void pdfapp_reloadfile(pdfapp_t *app)
142
{
143
fz_context *ctx = app->ctx;
144
char *filename = app->docpath;
145
146
app->docpath = NULL;
147
pdfapp_close(app);
148
pdfapp_open(app, filename, 1);
149
fz_free(ctx, filename);
150
}
151
152
static void event_cb(fz_context *ctx, pdf_document *doc, pdf_doc_event *event, void *data)
153
{
154
pdfapp_t *app = (pdfapp_t *)data;
155
156
switch (event->type)
157
{
158
case PDF_DOCUMENT_EVENT_ALERT:
159
{
160
pdf_alert_event *alert = pdf_access_alert_event(ctx, event);
161
winalert(app, alert);
162
}
163
break;
164
165
case PDF_DOCUMENT_EVENT_PRINT:
166
winprint(app);
167
break;
168
169
case PDF_DOCUMENT_EVENT_EXEC_MENU_ITEM:
170
{
171
char *item = pdf_access_exec_menu_item_event(ctx, event);
172
173
if (!strcmp(item, "Print"))
174
winprint(app);
175
else
176
pdfapp_warn(app, "The document attempted to execute menu item: %s. (Not supported)", item);
177
}
178
break;
179
180
case PDF_DOCUMENT_EVENT_EXEC_DIALOG:
181
pdfapp_warn(app, "The document attempted to open a dialog box. (Not supported)");
182
break;
183
184
case PDF_DOCUMENT_EVENT_LAUNCH_URL:
185
{
186
pdf_launch_url_event *launch_url = pdf_access_launch_url_event(ctx, event);
187
188
pdfapp_warn(app, "The document attempted to open url: %s. (Not supported by app)", launch_url->url);
189
}
190
break;
191
192
case PDF_DOCUMENT_EVENT_MAIL_DOC:
193
{
194
pdf_mail_doc_event *mail_doc = pdf_access_mail_doc_event(ctx, event);
195
196
pdfapp_warn(app, "The document attmepted to mail the document%s%s%s%s%s%s%s%s (Not supported)",
197
mail_doc->to[0]?", To: ":"", mail_doc->to,
198
mail_doc->cc[0]?", Cc: ":"", mail_doc->cc,
199
mail_doc->bcc[0]?", Bcc: ":"", mail_doc->bcc,
200
mail_doc->subject[0]?", Subject: ":"", mail_doc->subject);
201
}
202
break;
203
}
204
}
205
206
void pdfapp_open(pdfapp_t *app, char *filename, int reload)
207
{
208
pdfapp_open_progressive(app, filename, reload, 0);
209
}
210
211
#ifdef HAVE_CURL
212
static void
213
pdfapp_more_data(void *app_, int complete)
214
{
215
pdfapp_t *app = (pdfapp_t *)app_;
216
217
if (complete && app->outline_deferred == PDFAPP_OUTLINE_DEFERRED)
218
{
219
app->outline_deferred = PDFAPP_OUTLINE_LOAD_NOW;
220
winreloadpage(app);
221
}
222
else if (app->incomplete)
223
winreloadpage(app);
224
}
225
#endif
226
227
static int make_fake_doc(pdfapp_t *app)
228
{
229
fz_context *ctx = app->ctx;
230
fz_matrix ctm = { 1, 0, 0, 1, 0, 0 };
231
fz_rect bounds;
232
pdf_page *newpage = NULL;
233
pdf_document *pdf = NULL;
234
fz_device *dev = NULL;
235
fz_path *path = NULL;
236
fz_stroke_state stroke = fz_default_stroke_state;
237
float red[3] = { 1, 0, 0 };
238
int i;
239
240
fz_var(pdf);
241
fz_var(dev);
242
fz_var(newpage);
243
244
fz_try(ctx)
245
{
246
pdf = pdf_create_document(ctx);
247
app->doc = &pdf->super;
248
bounds.x0 = 0;
249
bounds.y0 = 0;
250
bounds.x1 = app->winw;
251
bounds.y1 = app->winh;
252
253
newpage = pdf_create_page(ctx, pdf, bounds, 72, 0);
254
255
dev = pdf_page_write(ctx, pdf, newpage);
256
257
/* Now the page content */
258
fz_begin_page(ctx, dev, &bounds, &ctm);
259
260
path = fz_new_path(ctx);
261
fz_moveto(ctx, path, 0, 0);
262
fz_lineto(ctx, path, bounds.x1, bounds.y1);
263
fz_moveto(ctx, path, 0, bounds.y1);
264
fz_lineto(ctx, path, bounds.x1, 0);
265
266
stroke.linewidth = fz_min(bounds.x1, bounds.y1)/4;
267
268
fz_stroke_path(ctx, dev, path, &stroke, &ctm, fz_device_rgb(ctx), red, 1);
269
270
fz_end_page(ctx, dev);
271
272
fz_drop_device(ctx, dev);
273
dev = NULL;
274
275
/* Create enough copies of our blank(ish) page so that the
276
* page number is preserved if and when a subsequent load
277
* works. */
278
for (i = 0; i < app->pagecount; i++)
279
pdf_insert_page(ctx, pdf, newpage, INT_MAX);
280
}
281
fz_always(ctx)
282
{
283
fz_drop_path(ctx, path);
284
pdf_drop_page(ctx, newpage);
285
fz_drop_device(ctx, dev);
286
dev = NULL;
287
}
288
fz_catch(ctx)
289
{
290
fz_rethrow(ctx);
291
}
292
293
return 0;
294
}
295
296
void pdfapp_open_progressive(pdfapp_t *app, char *filename, int reload, int bps)
297
{
298
fz_context *ctx = app->ctx;
299
char *password = "";
300
301
fz_try(ctx)
302
{
303
fz_register_document_handlers(ctx);
304
305
#ifdef HAVE_CURL
306
if (!strncmp(filename, "http://", 7))
307
{
308
app->stream = fz_stream_from_curl(ctx, filename, pdfapp_more_data, app);
309
while (1)
310
{
311
fz_try(ctx)
312
{
313
fz_seek(ctx, app->stream, 0, SEEK_SET);
314
app->doc = fz_open_document_with_stream(ctx, filename, app->stream);
315
}
316
fz_catch(ctx)
317
{
318
if (fz_caught(ctx) == FZ_ERROR_TRYLATER)
319
{
320
pdfapp_warn(app, "not enough data to open yet");
321
continue;
322
}
323
fz_rethrow(ctx);
324
}
325
break;
326
}
327
}
328
else
329
#endif
330
if (bps == 0)
331
{
332
app->doc = fz_open_document(ctx, filename);
333
}
334
else
335
{
336
fz_stream *stream = fz_open_file_progressive(ctx, filename, bps);
337
while (1)
338
{
339
fz_try(ctx)
340
{
341
fz_seek(ctx, stream, 0, SEEK_SET);
342
app->doc = fz_open_document_with_stream(ctx, filename, stream);
343
}
344
fz_catch(ctx)
345
{
346
if (fz_caught(ctx) == FZ_ERROR_TRYLATER)
347
{
348
pdfapp_warn(app, "not enough data to open yet");
349
continue;
350
}
351
fz_rethrow(ctx);
352
}
353
break;
354
}
355
}
356
}
357
fz_catch(ctx)
358
{
359
if (!reload || make_fake_doc(app))
360
pdfapp_error(app, "cannot open document");
361
}
362
363
fz_try(ctx)
364
{
365
pdf_document *idoc;
366
367
idoc = pdf_specifics(app->ctx, app->doc);
368
369
if (idoc)
370
{
371
pdf_enable_js(ctx, idoc);
372
pdf_set_doc_event_callback(ctx, idoc, event_cb, app);
373
}
374
375
if (fz_needs_password(app->ctx, app->doc))
376
{
377
int okay = fz_authenticate_password(app->ctx, app->doc, password);
378
while (!okay)
379
{
380
password = winpassword(app, filename);
381
if (!password)
382
fz_throw(ctx, FZ_ERROR_GENERIC, "Needs a password");
383
okay = fz_authenticate_password(app->ctx, app->doc, password);
384
if (!okay)
385
pdfapp_warn(app, "Invalid password.");
386
}
387
}
388
389
app->docpath = fz_strdup(ctx, filename);
390
app->doctitle = filename;
391
if (strrchr(app->doctitle, '\\'))
392
app->doctitle = strrchr(app->doctitle, '\\') + 1;
393
if (strrchr(app->doctitle, '/'))
394
app->doctitle = strrchr(app->doctitle, '/') + 1;
395
app->doctitle = fz_strdup(ctx, app->doctitle);
396
397
fz_layout_document(app->ctx, app->doc, app->layout_w, app->layout_h, app->layout_em);
398
399
while (1)
400
{
401
fz_try(ctx)
402
{
403
app->pagecount = fz_count_pages(app->ctx, app->doc);
404
if (app->pagecount <= 0)
405
fz_throw(ctx, FZ_ERROR_GENERIC, "No pages in document");
406
}
407
fz_catch(ctx)
408
{
409
if (fz_caught(ctx) == FZ_ERROR_TRYLATER)
410
{
411
pdfapp_warn(app, "not enough data to count pages yet");
412
continue;
413
}
414
fz_rethrow(ctx);
415
}
416
break;
417
}
418
while (1)
419
{
420
fz_try(ctx)
421
{
422
app->outline = fz_load_outline(app->ctx, app->doc);
423
}
424
fz_catch(ctx)
425
{
426
if (fz_caught(ctx) == FZ_ERROR_TRYLATER)
427
{
428
app->outline_deferred = PDFAPP_OUTLINE_DEFERRED;
429
}
430
else
431
fz_rethrow(ctx);
432
}
433
break;
434
}
435
}
436
fz_catch(ctx)
437
{
438
pdfapp_error(app, "cannot open document");
439
}
440
441
if (app->pageno < 1)
442
app->pageno = 1;
443
if (app->pageno > app->pagecount)
444
app->pageno = app->pagecount;
445
if (app->resolution < MINRES)
446
app->resolution = MINRES;
447
if (app->resolution > MAXRES)
448
app->resolution = MAXRES;
449
450
if (!reload)
451
{
452
app->shrinkwrap = 1;
453
app->rotate = 0;
454
app->panx = 0;
455
app->pany = 0;
456
}
457
458
pdfapp_showpage(app, 1, 1, 1, 0, 0);
459
}
460
461
void pdfapp_close(pdfapp_t *app)
462
{
463
fz_drop_display_list(app->ctx, app->page_list);
464
app->page_list = NULL;
465
466
fz_drop_display_list(app->ctx, app->annotations_list);
467
app->annotations_list = NULL;
468
469
fz_drop_text_page(app->ctx, app->page_text);
470
app->page_text = NULL;
471
472
fz_drop_text_sheet(app->ctx, app->page_sheet);
473
app->page_sheet = NULL;
474
475
fz_drop_link(app->ctx, app->page_links);
476
app->page_links = NULL;
477
478
fz_free(app->ctx, app->doctitle);
479
app->doctitle = NULL;
480
481
fz_free(app->ctx, app->docpath);
482
app->docpath = NULL;
483
484
fz_drop_pixmap(app->ctx, app->image);
485
app->image = NULL;
486
487
fz_drop_pixmap(app->ctx, app->new_image);
488
app->new_image = NULL;
489
490
fz_drop_pixmap(app->ctx, app->old_image);
491
app->old_image = NULL;
492
493
fz_drop_outline(app->ctx, app->outline);
494
app->outline = NULL;
495
496
fz_drop_page(app->ctx, app->page);
497
app->page = NULL;
498
499
fz_drop_document(app->ctx, app->doc);
500
app->doc = NULL;
501
502
#ifdef HAVE_CURL
503
fz_drop_stream(app->ctx, app->stream);
504
#endif
505
506
fz_flush_warnings(app->ctx);
507
}
508
509
static int gen_tmp_file(char *buf, int len)
510
{
511
int i;
512
char *name = strrchr(buf, '/');
513
514
if (name == NULL)
515
name = strrchr(buf, '\\');
516
517
if (name != NULL)
518
name++;
519
else
520
name = buf;
521
522
for (i = 0; i < 10000; i++)
523
{
524
FILE *f;
525
snprintf(name, buf+len-name, "tmp%04d", i);
526
f = fopen(buf, "r");
527
if (f == NULL)
528
return 1;
529
fclose(f);
530
}
531
532
return 0;
533
}
534
535
static int pdfapp_save(pdfapp_t *app)
536
{
537
char buf[PATH_MAX];
538
539
if (wingetsavepath(app, buf, PATH_MAX))
540
{
541
fz_write_options opts;
542
543
opts.do_incremental = 1;
544
opts.do_ascii = 0;
545
opts.do_expand = 0;
546
opts.do_garbage = 0;
547
opts.do_linear = 0;
548
549
if (strcmp(buf, app->docpath) != 0)
550
{
551
wincopyfile(app->docpath, buf);
552
fz_write_document(app->ctx, app->doc, buf, &opts);
553
return 1;
554
}
555
556
if (gen_tmp_file(buf, PATH_MAX))
557
{
558
int written = 0;
559
560
fz_try(app->ctx)
561
{
562
wincopyfile(app->docpath, buf);
563
fz_write_document(app->ctx, app->doc, buf, &opts);
564
written = 1;
565
}
566
fz_catch(app->ctx)
567
{
568
}
569
570
if (written)
571
{
572
char buf2[PATH_MAX];
573
fz_strlcpy(buf2, app->docpath, PATH_MAX);
574
pdfapp_close(app);
575
winreplacefile(buf, buf2);
576
pdfapp_open(app, buf2, 1);
577
578
return written;
579
}
580
}
581
}
582
583
return 0;
584
}
585
586
int pdfapp_preclose(pdfapp_t *app)
587
{
588
pdf_document *idoc = pdf_specifics(app->ctx, app->doc);
589
590
if (idoc && pdf_has_unsaved_changes(app->ctx, idoc))
591
{
592
switch (winsavequery(app))
593
{
594
case DISCARD:
595
return 1;
596
597
case CANCEL:
598
return 0;
599
600
case SAVE:
601
return pdfapp_save(app);
602
}
603
}
604
605
return 1;
606
}
607
608
static void pdfapp_viewctm(fz_matrix *mat, pdfapp_t *app)
609
{
610
fz_pre_rotate(fz_scale(mat, app->resolution/72.0f, app->resolution/72.0f), app->rotate);
611
}
612
613
static void pdfapp_panview(pdfapp_t *app, int newx, int newy)
614
{
615
int image_w = fz_pixmap_width(app->ctx, app->image);
616
int image_h = fz_pixmap_height(app->ctx, app->image);
617
618
if (newx > 0)
619
newx = 0;
620
if (newy > 0)
621
newy = 0;
622
623
if (newx + image_w < app->winw)
624
newx = app->winw - image_w;
625
if (newy + image_h < app->winh)
626
newy = app->winh - image_h;
627
628
if (app->winw >= image_w)
629
newx = (app->winw - image_w) / 2;
630
if (app->winh >= image_h)
631
newy = (app->winh - image_h) / 2;
632
633
if (newx != app->panx || newy != app->pany)
634
winrepaint(app);
635
636
app->panx = newx;
637
app->pany = newy;
638
}
639
640
static void pdfapp_loadpage(pdfapp_t *app, int no_cache)
641
{
642
fz_device *mdev = NULL;
643
int errored = 0;
644
fz_cookie cookie = { 0 };
645
646
fz_var(mdev);
647
648
fz_drop_display_list(app->ctx, app->page_list);
649
fz_drop_display_list(app->ctx, app->annotations_list);
650
fz_drop_text_page(app->ctx, app->page_text);
651
fz_drop_text_sheet(app->ctx, app->page_sheet);
652
fz_drop_link(app->ctx, app->page_links);
653
fz_drop_page(app->ctx, app->page);
654
655
app->page_list = NULL;
656
app->annotations_list = NULL;
657
app->page_text = NULL;
658
app->page_sheet = NULL;
659
app->page_links = NULL;
660
app->page = NULL;
661
app->page_bbox.x0 = 0;
662
app->page_bbox.y0 = 0;
663
app->page_bbox.x1 = 100;
664
app->page_bbox.y1 = 100;
665
666
app->incomplete = 0;
667
668
fz_try(app->ctx)
669
{
670
app->page = fz_load_page(app->ctx, app->doc, app->pageno - 1);
671
672
fz_bound_page(app->ctx, app->page, &app->page_bbox);
673
}
674
fz_catch(app->ctx)
675
{
676
if (fz_caught(app->ctx) == FZ_ERROR_TRYLATER)
677
app->incomplete = 1;
678
else
679
pdfapp_warn(app, "Cannot load page");
680
return;
681
}
682
683
fz_try(app->ctx)
684
{
685
fz_annot *annot;
686
/* Create display lists */
687
app->page_list = fz_new_display_list(app->ctx);
688
mdev = fz_new_list_device(app->ctx, app->page_list);
689
if (no_cache)
690
fz_enable_device_hints(app->ctx, mdev, FZ_NO_CACHE);
691
cookie.incomplete_ok = 1;
692
fz_run_page_contents(app->ctx, app->page, mdev, &fz_identity, &cookie);
693
fz_drop_device(app->ctx, mdev);
694
mdev = NULL;
695
app->annotations_list = fz_new_display_list(app->ctx);
696
mdev = fz_new_list_device(app->ctx, app->annotations_list);
697
for (annot = fz_first_annot(app->ctx, app->page); annot; annot = fz_next_annot(app->ctx, app->page, annot))
698
fz_run_annot(app->ctx, app->page, annot, mdev, &fz_identity, &cookie);
699
if (cookie.incomplete)
700
{
701
app->incomplete = 1;
702
//pdfapp_warn(app, "Incomplete page rendering");
703
}
704
else if (cookie.errors)
705
{
706
pdfapp_warn(app, "Errors found on page");
707
errored = 1;
708
}
709
}
710
fz_always(app->ctx)
711
{
712
fz_drop_device(app->ctx, mdev);
713
}
714
fz_catch(app->ctx)
715
{
716
if (fz_caught(app->ctx) == FZ_ERROR_TRYLATER)
717
app->incomplete = 1;
718
else
719
{
720
pdfapp_warn(app, "Cannot load page");
721
errored = 1;
722
}
723
}
724
725
fz_try(app->ctx)
726
{
727
app->page_links = fz_load_links(app->ctx, app->page);
728
}
729
fz_catch(app->ctx)
730
{
731
if (fz_caught(app->ctx) == FZ_ERROR_TRYLATER)
732
app->incomplete = 1;
733
else if (!errored)
734
pdfapp_warn(app, "Cannot load page");
735
}
736
737
app->errored = errored;
738
}
739
740
static void pdfapp_recreate_annotationslist(pdfapp_t *app)
741
{
742
fz_device *mdev = NULL;
743
int errored = 0;
744
fz_cookie cookie = { 0 };
745
746
fz_var(mdev);
747
748
fz_drop_display_list(app->ctx, app->annotations_list);
749
app->annotations_list = NULL;
750
751
fz_try(app->ctx)
752
{
753
fz_annot *annot;
754
/* Create display list */
755
app->annotations_list = fz_new_display_list(app->ctx);
756
mdev = fz_new_list_device(app->ctx, app->annotations_list);
757
for (annot = fz_first_annot(app->ctx, app->page); annot; annot = fz_next_annot(app->ctx, app->page, annot))
758
fz_run_annot(app->ctx, app->page, annot, mdev, &fz_identity, &cookie);
759
if (cookie.incomplete)
760
{
761
app->incomplete = 1;
762
//pdfapp_warn(app, "Incomplete page rendering");
763
}
764
else if (cookie.errors)
765
{
766
pdfapp_warn(app, "Errors found on page");
767
errored = 1;
768
}
769
}
770
fz_always(app->ctx)
771
{
772
fz_drop_device(app->ctx, mdev);
773
}
774
fz_catch(app->ctx)
775
{
776
pdfapp_warn(app, "Cannot load page");
777
errored = 1;
778
}
779
780
app->errored = errored;
781
}
782
783
static void pdfapp_runpage(pdfapp_t *app, fz_device *dev, const fz_matrix *ctm, const fz_rect *rect, fz_cookie *cookie)
784
{
785
fz_begin_page(app->ctx, dev, rect, ctm);
786
if (app->page_list)
787
fz_run_display_list(app->ctx, app->page_list, dev, ctm, rect, cookie);
788
if (app->annotations_list)
789
fz_run_display_list(app->ctx, app->annotations_list, dev, ctm, rect, cookie);
790
fz_end_page(app->ctx, dev);
791
}
792
793
#define MAX_TITLE 256
794
795
static void pdfapp_updatepage(pdfapp_t *app)
796
{
797
pdf_document *idoc = pdf_specifics(app->ctx, app->doc);
798
fz_device *idev;
799
fz_matrix ctm;
800
fz_annot *annot;
801
802
pdfapp_viewctm(&ctm, app);
803
pdf_update_page(app->ctx, idoc, (pdf_page *)app->page);
804
pdfapp_recreate_annotationslist(app);
805
806
while ((annot = (fz_annot *)pdf_poll_changed_annot(app->ctx, idoc, (pdf_page *)app->page)) != NULL)
807
{
808
fz_rect bounds;
809
fz_irect ibounds;
810
fz_transform_rect(fz_bound_annot(app->ctx, app->page, annot, &bounds), &ctm);
811
fz_rect_from_irect(&bounds, fz_round_rect(&ibounds, &bounds));
812
fz_clear_pixmap_rect_with_value(app->ctx, app->image, 255, &ibounds);
813
idev = fz_new_draw_device_with_bbox(app->ctx, app->image, &ibounds);
814
pdfapp_runpage(app, idev, &ctm, &bounds, NULL);
815
fz_drop_device(app->ctx, idev);
816
}
817
818
pdfapp_showpage(app, 0, 0, 1, 0, 0);
819
}
820
821
void pdfapp_reloadpage(pdfapp_t *app)
822
{
823
if (app->outline_deferred == PDFAPP_OUTLINE_LOAD_NOW)
824
{
825
fz_try(app->ctx)
826
{
827
app->outline = fz_load_outline(app->ctx, app->doc);
828
}
829
fz_catch(app->ctx)
830
{
831
/* Ignore any error now */
832
}
833
app->outline_deferred = 0;
834
}
835
pdfapp_showpage(app, 1, 1, 1, 0, 0);
836
}
837
838
static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint, int transition, int searching)
839
{
840
char buf[MAX_TITLE];
841
fz_device *idev;
842
fz_device *tdev;
843
fz_colorspace *colorspace;
844
fz_matrix ctm;
845
fz_rect bounds;
846
fz_irect ibounds;
847
fz_cookie cookie = { 0 };
848
849
if (!app->nowaitcursor)
850
wincursor(app, WAIT);
851
852
if (!app->transitions_enabled || !app->presentation_mode)
853
transition = 0;
854
855
if (transition)
856
{
857
app->old_image = app->image;
858
app->image = NULL;
859
}
860
861
if (loadpage)
862
{
863
pdfapp_loadpage(app, searching);
864
865
/* Zero search hit position */
866
app->hit_count = 0;
867
868
/* Extract text */
869
app->page_sheet = fz_new_text_sheet(app->ctx);
870
app->page_text = fz_new_text_page(app->ctx);
871
872
if (app->page_list || app->annotations_list)
873
{
874
tdev = fz_new_text_device(app->ctx, app->page_sheet, app->page_text);
875
pdfapp_runpage(app, tdev, &fz_identity, &fz_infinite_rect, &cookie);
876
fz_drop_device(app->ctx, tdev);
877
}
878
}
879
880
if (drawpage)
881
{
882
char buf2[64];
883
int len;
884
885
sprintf(buf2, " - %d/%d (%d dpi)",
886
app->pageno, app->pagecount, app->resolution);
887
len = MAX_TITLE-strlen(buf2);
888
if ((int)strlen(app->doctitle) > len)
889
{
890
snprintf(buf, len-3, "%s", app->doctitle);
891
strcat(buf, "...");
892
strcat(buf, buf2);
893
}
894
else
895
sprintf(buf, "%s%s", app->doctitle, buf2);
896
wintitle(app, buf);
897
898
pdfapp_viewctm(&ctm, app);
899
bounds = app->page_bbox;
900
fz_round_rect(&ibounds, fz_transform_rect(&bounds, &ctm));
901
fz_rect_from_irect(&bounds, &ibounds);
902
903
/* Draw */
904
if (app->image)
905
fz_drop_pixmap(app->ctx, app->image);
906
if (app->grayscale)
907
colorspace = fz_device_gray(app->ctx);
908
else
909
colorspace = app->colorspace;
910
app->image = NULL;
911
app->image = fz_new_pixmap_with_bbox(app->ctx, colorspace, &ibounds);
912
fz_clear_pixmap_with_value(app->ctx, app->image, 255);
913
if (app->page_list || app->annotations_list)
914
{
915
idev = fz_new_draw_device(app->ctx, app->image);
916
pdfapp_runpage(app, idev, &ctm, &bounds, &cookie);
917
fz_drop_device(app->ctx, idev);
918
}
919
if (app->invert)
920
fz_invert_pixmap(app->ctx, app->image);
921
if (app->tint)
922
fz_tint_pixmap(app->ctx, app->image, app->tint_r, app->tint_g, app->tint_b);
923
}
924
925
if (transition)
926
{
927
fz_transition *new_trans;
928
app->new_image = app->image;
929
app->image = NULL;
930
if (app->grayscale)
931
colorspace = fz_device_gray(app->ctx);
932
else
933
colorspace = app->colorspace;
934
app->image = fz_new_pixmap_with_bbox(app->ctx, colorspace, &ibounds);
935
app->duration = 0;
936
new_trans = fz_page_presentation(app->ctx, app->page, &app->duration);
937
if (new_trans)
938
app->transition = *new_trans;
939
if (app->duration == 0)
940
app->duration = 5;
941
app->in_transit = fz_generate_transition(app->ctx, app->image, app->old_image, app->new_image, 0, &app->transition);
942
if (!app->in_transit)
943
{
944
if (app->duration != 0)
945
winadvancetimer(app, app->duration);
946
}
947
app->start_time = clock();
948
}
949
950
if (repaint)
951
{
952
pdfapp_panview(app, app->panx, app->pany);
953
954
if (app->shrinkwrap)
955
{
956
int w = fz_pixmap_width(app->ctx, app->image);
957
int h = fz_pixmap_height(app->ctx, app->image);
958
if (app->winw == w)
959
app->panx = 0;
960
if (app->winh == h)
961
app->pany = 0;
962
if (w > app->scrw * 90 / 100)
963
w = app->scrw * 90 / 100;
964
if (h > app->scrh * 90 / 100)
965
h = app->scrh * 90 / 100;
966
if (w != app->winw || h != app->winh)
967
winresize(app, w, h);
968
}
969
970
winrepaint(app);
971
972
wincursor(app, ARROW);
973
}
974
975
if (cookie.errors && app->errored == 0)
976
{
977
app->errored = 1;
978
pdfapp_warn(app, "Errors found on page. Page rendering may be incomplete.");
979
}
980
981
fz_flush_warnings(app->ctx);
982
}
983
984
static void pdfapp_gotouri(pdfapp_t *app, char *uri)
985
{
986
winopenuri(app, uri);
987
}
988
989
void pdfapp_gotopage(pdfapp_t *app, int number)
990
{
991
app->issearching = 0;
992
winrepaint(app);
993
994
if (number < 1)
995
number = 1;
996
if (number > app->pagecount)
997
number = app->pagecount;
998
999
if (number == app->pageno)
1000
return;
1001
1002
if (app->histlen + 1 == 256)
1003
{
1004
memmove(app->hist, app->hist + 1, sizeof(int) * 255);
1005
app->histlen --;
1006
}
1007
app->hist[app->histlen++] = app->pageno;
1008
app->pageno = number;
1009
pdfapp_showpage(app, 1, 1, 1, 0, 0);
1010
}
1011
1012
void pdfapp_inverthit(pdfapp_t *app)
1013
{
1014
fz_rect bbox;
1015
fz_matrix ctm;
1016
int i;
1017
1018
pdfapp_viewctm(&ctm, app);
1019
1020
for (i = 0; i < app->hit_count; i++)
1021
{
1022
bbox = app->hit_bbox[i];
1023
pdfapp_invert(app, fz_transform_rect(&bbox, &ctm));
1024
}
1025
}
1026
1027
static void pdfapp_search_in_direction(pdfapp_t *app, enum panning *panto, int dir)
1028
{
1029
int firstpage, page;
1030
1031
wincursor(app, WAIT);
1032
1033
firstpage = app->pageno;
1034
if (app->searchpage == app->pageno)
1035
page = app->pageno + dir;
1036
else
1037
page = app->pageno;
1038
1039
if (page < 1) page = app->pagecount;
1040
if (page > app->pagecount) page = 1;
1041
1042
do
1043
{
1044
if (page != app->pageno)
1045
{
1046
app->pageno = page;
1047
pdfapp_showpage(app, 1, 0, 0, 0, 1);
1048
}
1049
1050
app->hit_count = fz_search_text_page(app->ctx, app->page_text, app->search, app->hit_bbox, nelem(app->hit_bbox));
1051
if (app->hit_count > 0)
1052
{
1053
*panto = dir == 1 ? PAN_TO_TOP : PAN_TO_BOTTOM;
1054
app->searchpage = app->pageno;
1055
wincursor(app, HAND);
1056
winrepaint(app);
1057
return;
1058
}
1059
1060
page += dir;
1061
if (page < 1) page = app->pagecount;
1062
if (page > app->pagecount) page = 1;
1063
} while (page != firstpage);
1064
1065
pdfapp_warn(app, "String '%s' not found.", app->search);
1066
1067
app->pageno = firstpage;
1068
pdfapp_showpage(app, 1, 0, 0, 0, 0);
1069
wincursor(app, HAND);
1070
winrepaint(app);
1071
}
1072
1073
void pdfapp_onresize(pdfapp_t *app, int w, int h)
1074
{
1075
if (app->winw != w || app->winh != h)
1076
{
1077
app->winw = w;
1078
app->winh = h;
1079
pdfapp_panview(app, app->panx, app->pany);
1080
winrepaint(app);
1081
}
1082
}
1083
1084
void pdfapp_autozoom_vertical(pdfapp_t *app)
1085
{
1086
app->resolution *= (double) app->winh / (double) fz_pixmap_height(app->ctx, app->image);
1087
if (app->resolution > MAXRES)
1088
app->resolution = MAXRES;
1089
else if (app->resolution < MINRES)
1090
app->resolution = MINRES;
1091
pdfapp_showpage(app, 0, 1, 1, 0, 0);
1092
}
1093
1094
void pdfapp_autozoom_horizontal(pdfapp_t *app)
1095
{
1096
app->resolution *= (double) app->winw / (double) fz_pixmap_width(app->ctx, app->image);
1097
if (app->resolution > MAXRES)
1098
app->resolution = MAXRES;
1099
else if (app->resolution < MINRES)
1100
app->resolution = MINRES;
1101
pdfapp_showpage(app, 0, 1, 1, 0, 0);
1102
}
1103
1104
void pdfapp_autozoom(pdfapp_t *app)
1105
{
1106
float page_aspect = (float) fz_pixmap_width(app->ctx, app->image) / fz_pixmap_height(app->ctx, app->image);
1107
float win_aspect = (float) app->winw / app->winh;
1108
if (page_aspect > win_aspect)
1109
pdfapp_autozoom_horizontal(app);
1110
else
1111
pdfapp_autozoom_vertical(app);
1112
}
1113
1114
void pdfapp_onkey(pdfapp_t *app, int c, int modifiers)
1115
{
1116
int oldpage = app->pageno;
1117
enum panning panto = PAN_TO_TOP;
1118
int loadpage = 1;
1119
1120
if (app->issearching)
1121
{
1122
int n = strlen(app->search);
1123
if (c < ' ')
1124
{
1125
if (c == '\b' && n > 0)
1126
{
1127
app->search[n - 1] = 0;
1128
winrepaintsearch(app);
1129
}
1130
if (c == '\n' || c == '\r')
1131
{
1132
app->issearching = 0;
1133
if (n > 0)
1134
{
1135
winrepaintsearch(app);
1136
1137
if (app->searchdir < 0)
1138
{
1139
if (app->pageno == 1)
1140
app->pageno = app->pagecount;
1141
else
1142
app->pageno--;
1143
pdfapp_showpage(app, 1, 1, 0, 0, 1);
1144
}
1145
1146
pdfapp_onkey(app, 'n', 0);
1147
}
1148
else
1149
winrepaint(app);
1150
}
1151
if (c == '\033')
1152
{
1153
app->issearching = 0;
1154
winrepaint(app);
1155
}
1156
}
1157
else
1158
{
1159
if (n + 2 < sizeof app->search)
1160
{
1161
app->search[n] = c;
1162
app->search[n + 1] = 0;
1163
winrepaintsearch(app);
1164
}
1165
}
1166
return;
1167
}
1168
1169
/*
1170
* Save numbers typed for later
1171
*/
1172
1173
if (c >= '0' && c <= '9')
1174
{
1175
app->number[app->numberlen++] = c;
1176
app->number[app->numberlen] = '\0';
1177
}
1178
1179
switch (c)
1180
{
1181
1182
case 'q':
1183
winclose(app);
1184
break;
1185
1186
/*
1187
* Zoom and rotate
1188
*/
1189
1190
case '+':
1191
case '=':
1192
app->resolution = zoom_in(app->resolution);
1193
pdfapp_showpage(app, 0, 1, 1, 0, 0);
1194
break;
1195
case '-':
1196
app->resolution = zoom_out(app->resolution);
1197
pdfapp_showpage(app, 0, 1, 1, 0, 0);
1198
break;
1199
1200
case 'W':
1201
pdfapp_autozoom_horizontal(app);
1202
break;
1203
case 'H':
1204
pdfapp_autozoom_vertical(app);
1205
break;
1206
case 'Z':
1207
pdfapp_autozoom(app);
1208
break;
1209
1210
case 'L':
1211
app->rotate -= 90;
1212
pdfapp_showpage(app, 0, 1, 1, 0, 0);
1213
break;
1214
case 'R':
1215
app->rotate += 90;
1216
pdfapp_showpage(app, 0, 1, 1, 0, 0);
1217
break;
1218
1219
case 'C':
1220
app->tint ^= 1;
1221
pdfapp_showpage(app, 0, 1, 1, 0, 0);
1222
break;
1223
1224
case 'c':
1225
app->grayscale ^= 1;
1226
pdfapp_showpage(app, 0, 1, 1, 0, 0);
1227
break;
1228
1229
case 'i':
1230
app->invert ^= 1;
1231
pdfapp_showpage(app, 0, 1, 1, 0, 0);
1232
break;
1233
1234
#ifndef NDEBUG
1235
case 'a':
1236
app->rotate -= 15;
1237
pdfapp_showpage(app, 0, 1, 1, 0, 0);
1238
break;
1239
case 's':
1240
app->rotate += 15;
1241
pdfapp_showpage(app, 0, 1, 1, 0, 0);
1242
break;
1243
#endif
1244
1245
/*
1246
* Pan view, but don't need to repaint image
1247
*/
1248
1249
case 'f':
1250
app->shrinkwrap = 0;
1251
winfullscreen(app, !app->fullscreen);
1252
app->fullscreen = !app->fullscreen;
1253
break;
1254
1255
case 'w':
1256
if (app->fullscreen)
1257
{
1258
winfullscreen(app, 0);
1259
app->fullscreen = 0;
1260
}
1261
app->shrinkwrap = 1;
1262
app->panx = app->pany = 0;
1263
pdfapp_showpage(app, 0, 0, 1, 0, 0);
1264
break;
1265
1266
case 'h':
1267
app->panx += fz_pixmap_width(app->ctx, app->image) / 10;
1268
pdfapp_showpage(app, 0, 0, 1, 0, 0);
1269
break;
1270
1271
case 'j':
1272
{
1273
int h = fz_pixmap_height(app->ctx, app->image);
1274
if (h <= app->winh || app->pany <= app->winh - h)
1275
{
1276
panto = PAN_TO_TOP;
1277
app->pageno++;
1278
}
1279
else
1280
{
1281
app->pany -= h / 10;
1282
pdfapp_showpage(app, 0, 0, 1, 0, 0);
1283
}
1284
break;
1285
}
1286
1287
case 'k':
1288
{
1289
int h = fz_pixmap_height(app->ctx, app->image);
1290
if (h <= app->winh || app->pany == 0)
1291
{
1292
panto = PAN_TO_BOTTOM;
1293
app->pageno--;
1294
}
1295
else
1296
{
1297
app->pany += h / 10;
1298
pdfapp_showpage(app, 0, 0, 1, 0, 0);
1299
}
1300
break;
1301
}
1302
1303
case 'l':
1304
app->panx -= fz_pixmap_width(app->ctx, app->image) / 10;
1305
pdfapp_showpage(app, 0, 0, 1, 0, 0);
1306
break;
1307
1308
/*
1309
* Page navigation
1310
*/
1311
1312
case 'g':
1313
case '\n':
1314
case '\r':
1315
if (app->numberlen > 0)
1316
pdfapp_gotopage(app, atoi(app->number));
1317
else
1318
pdfapp_gotopage(app, 1);
1319
break;
1320
1321
case 'G':
1322
pdfapp_gotopage(app, app->pagecount);
1323
break;
1324
1325
case 'm':
1326
if (app->numberlen > 0)
1327
{
1328
int idx = atoi(app->number);
1329
if (idx >= 0 && idx < nelem(app->marks))
1330
app->marks[idx] = app->pageno;
1331
}
1332
else
1333
{
1334
if (app->histlen + 1 == 256)
1335
{
1336
memmove(app->hist, app->hist + 1, sizeof(int) * 255);
1337
app->histlen --;
1338
}
1339
app->hist[app->histlen++] = app->pageno;
1340
}
1341
break;
1342
1343
case 't':
1344
if (app->numberlen > 0)
1345
{
1346
int idx = atoi(app->number);
1347
1348
if (idx >= 0 && idx < nelem(app->marks))
1349
if (app->marks[idx] > 0)
1350
app->pageno = app->marks[idx];
1351
}
1352
else if (app->histlen > 0)
1353
app->pageno = app->hist[--app->histlen];
1354
break;
1355
1356
case 'p':
1357
app->presentation_mode = !app->presentation_mode;
1358
break;
1359
1360
/*
1361
* Back and forth ...
1362
*/
1363
1364
case ',':
1365
panto = PAN_TO_BOTTOM;
1366
if (app->numberlen > 0)
1367
app->pageno -= atoi(app->number);
1368
else
1369
app->pageno--;
1370
break;
1371
1372
case '.':
1373
panto = PAN_TO_TOP;
1374
if (app->numberlen > 0)
1375
app->pageno += atoi(app->number);
1376
else
1377
app->pageno++;
1378
break;
1379
1380
case '\b':
1381
case 'b':
1382
panto = DONT_PAN;
1383
if (app->numberlen > 0)
1384
app->pageno -= atoi(app->number);
1385
else
1386
app->pageno--;
1387
break;
1388
1389
case ' ':
1390
panto = DONT_PAN;
1391
if (modifiers & 1)
1392
{
1393
if (app->numberlen > 0)
1394
app->pageno -= atoi(app->number);
1395
else
1396
app->pageno--;
1397
}
1398
else
1399
{
1400
if (app->numberlen > 0)
1401
app->pageno += atoi(app->number);
1402
else
1403
app->pageno++;
1404
}
1405
break;
1406
1407
case '<':
1408
panto = PAN_TO_TOP;
1409
app->pageno -= 10;
1410
break;
1411
case '>':
1412
panto = PAN_TO_TOP;
1413
app->pageno += 10;
1414
break;
1415
1416
/*
1417
* Saving the file
1418
*/
1419
case 'S':
1420
pdfapp_save(app);
1421
break;
1422
1423
/*
1424
* Reloading the file...
1425
*/
1426
1427
case 'r':
1428
panto = DONT_PAN;
1429
oldpage = -1;
1430
pdfapp_reloadfile(app);
1431
break;
1432
1433
/*
1434
* Searching
1435
*/
1436
1437
case '?':
1438
app->issearching = 1;
1439
app->searchdir = -1;
1440
app->search[0] = 0;
1441
app->hit_count = 0;
1442
app->searchpage = -1;
1443
winrepaintsearch(app);
1444
break;
1445
1446
case '/':
1447
app->issearching = 1;
1448
app->searchdir = 1;
1449
app->search[0] = 0;
1450
app->hit_count = 0;
1451
app->searchpage = -1;
1452
winrepaintsearch(app);
1453
break;
1454
1455
case 'n':
1456
if (app->searchdir > 0)
1457
pdfapp_search_in_direction(app, &panto, 1);
1458
else
1459
pdfapp_search_in_direction(app, &panto, -1);
1460
loadpage = 0;
1461
break;
1462
1463
case 'N':
1464
if (app->searchdir > 0)
1465
pdfapp_search_in_direction(app, &panto, -1);
1466
else
1467
pdfapp_search_in_direction(app, &panto, 1);
1468
loadpage = 0;
1469
break;
1470
1471
}
1472
1473
if (c < '0' || c > '9')
1474
app->numberlen = 0;
1475
1476
if (app->pageno < 1)
1477
app->pageno = 1;
1478
if (app->pageno > app->pagecount)
1479
app->pageno = app->pagecount;
1480
1481
if (app->pageno != oldpage)
1482
{
1483
switch (panto)
1484
{
1485
case PAN_TO_TOP:
1486
app->pany = 0;
1487
break;
1488
case PAN_TO_BOTTOM:
1489
app->pany = -2000;
1490
break;
1491
case DONT_PAN:
1492
break;
1493
}
1494
pdfapp_showpage(app, loadpage, 1, 1, 1, 0);
1495
}
1496
}
1497
1498
static void handlescroll(pdfapp_t *app, int modifiers, int dir)
1499
{
1500
app->ispanning = app->iscopying = 0;
1501
if (modifiers & (1<<2))
1502
{
1503
/* zoom in/out if ctrl is pressed */
1504
if (dir < 0)
1505
app->resolution = zoom_in(app->resolution);
1506
else
1507
app->resolution = zoom_out(app->resolution);
1508
if (app->resolution > MAXRES)
1509
app->resolution = MAXRES;
1510
if (app->resolution < MINRES)
1511
app->resolution = MINRES;
1512
pdfapp_showpage(app, 0, 1, 1, 0, 0);
1513
}
1514
else
1515
{
1516
/* scroll up/down, or left/right if
1517
shift is pressed */
1518
int w = fz_pixmap_width(app->ctx, app->image);
1519
int h = fz_pixmap_height(app->ctx, app->image);
1520
int xstep = 0;
1521
int ystep = 0;
1522
int pagestep = 0;
1523
if (modifiers & (1<<0))
1524
{
1525
if (dir > 0 && app->panx >= 0)
1526
pagestep = -1;
1527
else if (dir < 0 && app->panx <= app->winw - w)
1528
pagestep = 1;
1529
else
1530
xstep = 20 * dir;
1531
}
1532
else
1533
{
1534
if (dir > 0 && app->pany >= 0)
1535
pagestep = -1;
1536
else if (dir < 0 && app->pany <= app->winh - h)
1537
pagestep = 1;
1538
else
1539
ystep = 20 * dir;
1540
}
1541
if (pagestep == 0)
1542
pdfapp_panview(app, app->panx + xstep, app->pany + ystep);
1543
else if (pagestep > 0 && app->pageno < app->pagecount)
1544
{
1545
app->pageno++;
1546
app->pany = 0;
1547
pdfapp_showpage(app, 1, 1, 1, 0, 0);
1548
}
1549
else if (pagestep < 0 && app->pageno > 1)
1550
{
1551
app->pageno--;
1552
app->pany = INT_MIN;
1553
pdfapp_showpage(app, 1, 1, 1, 0, 0);
1554
}
1555
}
1556
}
1557
1558
void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int state)
1559
{
1560
fz_context *ctx = app->ctx;
1561
fz_irect irect;
1562
fz_link *link;
1563
fz_matrix ctm;
1564
fz_point p;
1565
int processed = 0;
1566
1567
fz_pixmap_bbox(app->ctx, app->image, &irect);
1568
p.x = x - app->panx + irect.x0;
1569
p.y = y - app->pany + irect.y0;
1570
1571
pdfapp_viewctm(&ctm, app);
1572
fz_invert_matrix(&ctm, &ctm);
1573
1574
fz_transform_point(&p, &ctm);
1575
1576
if (btn == 1 && (state == 1 || state == -1))
1577
{
1578
pdf_ui_event event;
1579
pdf_document *idoc = pdf_specifics(app->ctx, app->doc);
1580
1581
event.etype = PDF_EVENT_TYPE_POINTER;
1582
event.event.pointer.pt = p;
1583
if (state == 1)
1584
event.event.pointer.ptype = PDF_POINTER_DOWN;
1585
else /* state == -1 */
1586
event.event.pointer.ptype = PDF_POINTER_UP;
1587
1588
if (idoc && pdf_pass_event(ctx, idoc, (pdf_page *)app->page, &event))
1589
{
1590
pdf_widget *widget;
1591
1592
widget = pdf_focused_widget(ctx, idoc);
1593
1594
app->nowaitcursor = 1;
1595
pdfapp_updatepage(app);
1596
1597
if (widget)
1598
{
1599
switch (pdf_widget_get_type(ctx, widget))
1600
{
1601
case PDF_WIDGET_TYPE_TEXT:
1602
{
1603
char *text = pdf_text_widget_text(ctx, idoc, widget);
1604
char *current_text = text;
1605
int retry = 0;
1606
1607
do
1608
{
1609
current_text = wintextinput(app, current_text, retry);
1610
retry = 1;
1611
}
1612
while (current_text && !pdf_text_widget_set_text(ctx, idoc, widget, current_text));
1613
1614
fz_free(app->ctx, text);
1615
pdfapp_updatepage(app);
1616
}
1617
break;
1618
1619
case PDF_WIDGET_TYPE_LISTBOX:
1620
case PDF_WIDGET_TYPE_COMBOBOX:
1621
{
1622
int nopts;
1623
int nvals;
1624
char **opts = NULL;
1625
char **vals = NULL;
1626
1627
fz_var(opts);
1628
fz_var(vals);
1629
1630
fz_try(ctx)
1631
{
1632
nopts = pdf_choice_widget_options(ctx, idoc, widget, NULL);
1633
opts = fz_malloc(ctx, nopts * sizeof(*opts));
1634
(void)pdf_choice_widget_options(ctx, idoc, widget, opts);
1635
1636
nvals = pdf_choice_widget_value(ctx, idoc, widget, NULL);
1637
vals = fz_malloc(ctx, MAX(nvals,nopts) * sizeof(*vals));
1638
(void)pdf_choice_widget_value(ctx, idoc, widget, vals);
1639
1640
if (winchoiceinput(app, nopts, opts, &nvals, vals))
1641
{
1642
pdf_choice_widget_set_value(ctx, idoc, widget, nvals, vals);
1643
pdfapp_updatepage(app);
1644
}
1645
}
1646
fz_always(ctx)
1647
{
1648
fz_free(ctx, opts);
1649
fz_free(ctx, vals);
1650
}
1651
fz_catch(ctx)
1652
{
1653
pdfapp_warn(app, "setting of choice failed");
1654
}
1655
}
1656
break;
1657
1658
case PDF_WIDGET_TYPE_SIGNATURE:
1659
{
1660
char ebuf[256];
1661
1662
ebuf[0] = 0;
1663
if (pdf_check_signature(ctx, idoc, widget, app->docpath, ebuf, sizeof(ebuf)))
1664
{
1665
winwarn(app, "Signature is valid");
1666
}
1667
else
1668
{
1669
if (ebuf[0] == 0)
1670
winwarn(app, "Signature check failed for unknown reason");
1671
else
1672
winwarn(app, ebuf);
1673
}
1674
}
1675
break;
1676
}
1677
}
1678
1679
app->nowaitcursor = 0;
1680
processed = 1;
1681
}
1682
}
1683
1684
for (link = app->page_links; link; link = link->next)
1685
{
1686
if (p.x >= link->rect.x0 && p.x <= link->rect.x1)
1687
if (p.y >= link->rect.y0 && p.y <= link->rect.y1)
1688
break;
1689
}
1690
1691
if (link)
1692
{
1693
wincursor(app, HAND);
1694
if (btn == 1 && state == 1 && !processed)
1695
{
1696
if (link->dest.kind == FZ_LINK_URI)
1697
pdfapp_gotouri(app, link->dest.ld.uri.uri);
1698
else if (link->dest.kind == FZ_LINK_GOTO)
1699
pdfapp_gotopage(app, link->dest.ld.gotor.page + 1);
1700
return;
1701
}
1702
}
1703
else
1704
{
1705
fz_annot *annot;
1706
for (annot = fz_first_annot(app->ctx, app->page); annot; annot = fz_next_annot(app->ctx, app->page, annot))
1707
{
1708
fz_rect rect;
1709
fz_bound_annot(app->ctx, app->page, annot, &rect);
1710
if (x >= rect.x0 && x < rect.x1)
1711
if (y >= rect.y0 && y < rect.y1)
1712
break;
1713
}
1714
if (annot)
1715
wincursor(app, CARET);
1716
else
1717
wincursor(app, ARROW);
1718
}
1719
1720
if (state == 1 && !processed)
1721
{
1722
if (btn == 1 && !app->iscopying)
1723
{
1724
app->ispanning = 1;
1725
app->selx = x;
1726
app->sely = y;
1727
app->beyondy = 0;
1728
}
1729
if (btn == 3 && !app->ispanning)
1730
{
1731
app->iscopying = 1;
1732
app->selx = x;
1733
app->sely = y;
1734
app->selr.x0 = x;
1735
app->selr.x1 = x;
1736
app->selr.y0 = y;
1737
app->selr.y1 = y;
1738
}
1739
if (btn == 4 || btn == 5) /* scroll wheel */
1740
{
1741
handlescroll(app, modifiers, btn == 4 ? 1 : -1);
1742
}
1743
if (btn == 6 || btn == 7) /* scroll wheel (horizontal) */
1744
{
1745
/* scroll left/right or up/down if shift is pressed */
1746
handlescroll(app, modifiers ^ (1<<0), btn == 6 ? 1 : -1);
1747
}
1748
if (app->presentation_mode)
1749
{
1750
if (btn == 1 && app->pageno < app->pagecount)
1751
{
1752
app->pageno++;
1753
pdfapp_showpage(app, 1, 1, 1, 0, 0);
1754
}
1755
if (btn == 3 && app->pageno > 1)
1756
{
1757
app->pageno--;
1758
pdfapp_showpage(app, 1, 1, 1, 0, 0);
1759
}
1760
}
1761
}
1762
1763
else if (state == -1)
1764
{
1765
if (app->iscopying)
1766
{
1767
app->iscopying = 0;
1768
app->selr.x0 = fz_mini(app->selx, x) - app->panx + irect.x0;
1769
app->selr.x1 = fz_maxi(app->selx, x) - app->panx + irect.x0;
1770
app->selr.y0 = fz_mini(app->sely, y) - app->pany + irect.y0;
1771
app->selr.y1 = fz_maxi(app->sely, y) - app->pany + irect.y0;
1772
winrepaint(app);
1773
if (app->selr.x0 < app->selr.x1 && app->selr.y0 < app->selr.y1)
1774
windocopy(app);
1775
}
1776
app->ispanning = 0;
1777
}
1778
1779
else if (app->ispanning)
1780
{
1781
int newx = app->panx + x - app->selx;
1782
int newy = app->pany + y - app->sely;
1783
/* Scrolling beyond limits implies flipping pages */
1784
/* Are we requested to scroll beyond limits? */
1785
if (newy + fz_pixmap_height(app->ctx, app->image) < app->winh || newy > 0)
1786
{
1787
/* Yes. We can assume that deltay != 0 */
1788
int deltay = y - app->sely;
1789
/* Check whether the panning has occurred in the
1790
* direction that we are already crossing the
1791
* limit it. If not, we can conclude that we
1792
* have switched ends of the page and will thus
1793
* start over counting.
1794
*/
1795
if( app->beyondy == 0 || (app->beyondy ^ deltay) >= 0 )
1796
{
1797
/* Updating how far we are beyond and
1798
* flipping pages if beyond threshold
1799
*/
1800
app->beyondy += deltay;
1801
if (app->beyondy > BEYOND_THRESHHOLD)
1802
{
1803
if( app->pageno > 1 )
1804
{
1805
app->pageno--;
1806
pdfapp_showpage(app, 1, 1, 1, 0, 0);
1807
newy = -fz_pixmap_height(app->ctx, app->image);
1808
}
1809
app->beyondy = 0;
1810
}
1811
else if (app->beyondy < -BEYOND_THRESHHOLD)
1812
{
1813
if( app->pageno < app->pagecount )
1814
{
1815
app->pageno++;
1816
pdfapp_showpage(app, 1, 1, 1, 0, 0);
1817
newy = 0;
1818
}
1819
app->beyondy = 0;
1820
}
1821
}
1822
else
1823
app->beyondy = 0;
1824
}
1825
/* Although at this point we've already determined that
1826
* or that no scrolling will be performed in
1827
* y-direction, the x-direction has not yet been taken
1828
* care off. Therefore
1829
*/
1830
pdfapp_panview(app, newx, newy);
1831
1832
app->selx = x;
1833
app->sely = y;
1834
}
1835
1836
else if (app->iscopying)
1837
{
1838
app->selr.x0 = fz_mini(app->selx, x) - app->panx + irect.x0;
1839
app->selr.x1 = fz_maxi(app->selx, x) - app->panx + irect.x0;
1840
app->selr.y0 = fz_mini(app->sely, y) - app->pany + irect.y0;
1841
app->selr.y1 = fz_maxi(app->sely, y) - app->pany + irect.y0;
1842
winrepaint(app);
1843
}
1844
1845
}
1846
1847
void pdfapp_oncopy(pdfapp_t *app, unsigned short *ucsbuf, int ucslen)
1848
{
1849
fz_rect hitbox;
1850
fz_matrix ctm;
1851
fz_text_page *page = app->page_text;
1852
int c, i, p, need_newline;
1853
int block_num;
1854
1855
int x0 = app->selr.x0;
1856
int x1 = app->selr.x1;
1857
int y0 = app->selr.y0;
1858
int y1 = app->selr.y1;
1859
1860
pdfapp_viewctm(&ctm, app);
1861
1862
p = 0;
1863
need_newline = 0;
1864
1865
for (block_num = 0; block_num < page->len; block_num++)
1866
{
1867
fz_text_line *line;
1868
fz_text_block *block;
1869
fz_text_span *span;
1870
1871
if (page->blocks[block_num].type != FZ_PAGE_BLOCK_TEXT)
1872
continue;
1873
block = page->blocks[block_num].u.text;
1874
1875
for (line = block->lines; line < block->lines + block->len; line++)
1876
{
1877
int saw_text = 0;
1878
1879
for (span = line->first_span; span; span = span->next)
1880
{
1881
for (i = 0; i < span->len; i++)
1882
{
1883
fz_text_char_bbox(app->ctx, &hitbox, span, i);
1884
fz_transform_rect(&hitbox, &ctm);
1885
c = span->text[i].c;
1886
if (c < 32)
1887
c = '?';
1888
if (hitbox.x1 >= x0 && hitbox.x0 <= x1 && hitbox.y1 >= y0 && hitbox.y0 <= y1)
1889
{
1890
saw_text = 1;
1891
1892
if (need_newline)
1893
{
1894
#if defined(_WIN32) || defined(_WIN64)
1895
if (p < ucslen - 1)
1896
ucsbuf[p++] = '\r';
1897
#endif
1898
if (p < ucslen - 1)
1899
ucsbuf[p++] = '\n';
1900
need_newline = 0;
1901
}
1902
1903
if (p < ucslen - 1)
1904
ucsbuf[p++] = c;
1905
}
1906
}
1907
}
1908
1909
if (saw_text)
1910
need_newline = 1;
1911
}
1912
}
1913
1914
ucsbuf[p] = 0;
1915
}
1916
1917
void pdfapp_postblit(pdfapp_t *app)
1918
{
1919
clock_t time;
1920
float seconds;
1921
int llama;
1922
1923
app->transitions_enabled = 1;
1924
if (!app->in_transit)
1925
return;
1926
time = clock();
1927
seconds = (float)(time - app->start_time) / CLOCKS_PER_SEC;
1928
llama = seconds * 256 / app->transition.duration;
1929
if (llama >= 256)
1930
{
1931
/* Completed. */
1932
fz_drop_pixmap(app->ctx, app->image);
1933
app->image = app->new_image;
1934
app->new_image = NULL;
1935
fz_drop_pixmap(app->ctx, app->old_image);
1936
app->old_image = NULL;
1937
if (app->duration != 0)
1938
winadvancetimer(app, app->duration);
1939
}
1940
else
1941
fz_generate_transition(app->ctx, app->image, app->old_image, app->new_image, llama, &app->transition);
1942
winrepaint(app);
1943
if (llama >= 256)
1944
{
1945
/* Completed. */
1946
app->in_transit = 0;
1947
}
1948
}
1949
1950