Rev 8438 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4680 | right-hear | 1 | #include "fitz.h" |
2 | #include "mupdf.h" |
||
3 | #include "pdfapp.h" |
||
8436 | maxcodehac | 4 | #include "kolibri.h" |
4680 | right-hear | 5 | |
6 | #include |
||
7 | |||
8 | #define ZOOMSTEP 1.142857 |
||
9 | #define BEYOND_THRESHHOLD 40 |
||
10 | |||
11 | enum panning |
||
12 | { |
||
13 | DONT_PAN = 0, |
||
14 | PAN_TO_TOP, |
||
15 | PAN_TO_BOTTOM |
||
16 | }; |
||
17 | |||
8461 | maxcodehac | 18 | void DrawPageSides(void); |
4680 | right-hear | 19 | static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint); |
20 | |||
21 | static void pdfapp_warn(pdfapp_t *app, const char *fmt, ...) |
||
22 | { |
||
23 | char buf[1024]; |
||
24 | va_list ap; |
||
25 | va_start(ap, fmt); |
||
26 | vsprintf(buf, fmt, ap); |
||
27 | va_end(ap); |
||
28 | winwarn(app, buf); |
||
29 | } |
||
30 | |||
31 | static void pdfapp_error(pdfapp_t *app, fz_error error) |
||
32 | { |
||
33 | winerror(app, error); |
||
34 | } |
||
35 | |||
36 | char *pdfapp_version(pdfapp_t *app) |
||
37 | { |
||
38 | return |
||
39 | "MuPDF 0.9\n" |
||
40 | "Copyright 2006-2011 Artifex Sofware, Inc.\n"; |
||
41 | } |
||
42 | |||
43 | char *pdfapp_usage(pdfapp_t *app) |
||
44 | { |
||
5821 | leency | 45 | return " "; |
46 | /* |
||
4680 | right-hear | 47 | "L\t\t-- rotate left\n" |
48 | "R\t\t-- rotate right\n" |
||
49 | "h\t\t-- scroll left\n" |
||
50 | "j down\t\t-- scroll down\n" |
||
51 | "k up\t\t-- scroll up\n" |
||
52 | "l\t\t-- scroll right\n" |
||
53 | "+\t\t-- zoom in\n" |
||
54 | "-\t\t-- zoom out\n" |
||
55 | "w\t\t-- shrinkwrap\n" |
||
56 | "r\t\t-- reload file\n" |
||
57 | ". pgdn right space\t-- next page\n" |
||
58 | ", pgup left b\t-- previous page\n" |
||
59 | ">\t\t-- next 10 pages\n" |
||
60 | "<\t\t-- back 10 pages\n" |
||
61 | "m\t\t-- mark page for snap back\n" |
||
62 | "t\t\t-- pop back to latest mark\n" |
||
63 | "1m\t\t-- mark page in register 1\n" |
||
64 | "1t\t\t-- go to page in register 1\n" |
||
65 | "123g\t\t-- go to page 123\n" |
||
66 | "/\t\t-- search for text\n" |
||
67 | "n\t\t-- find next search result\n" |
||
68 | "N\t\t-- find previous search result\n" |
||
69 | "c\t\t-- toggle between color and grayscale\n" |
||
7621 | leency | 70 | ; |
71 | */ |
||
4680 | right-hear | 72 | } |
73 | |||
74 | void pdfapp_init(pdfapp_t *app) |
||
75 | { |
||
76 | memset(app, 0, sizeof(pdfapp_t)); |
||
77 | app->scrw = 640; |
||
78 | app->scrh = 480; |
||
79 | app->resolution = 72; |
||
80 | } |
||
81 | |||
82 | void pdfapp_invert(pdfapp_t *app, fz_bbox rect) |
||
83 | { |
||
84 | unsigned char *p; |
||
85 | int x, y, n; |
||
86 | |||
87 | int x0 = CLAMP(rect.x0 - app->image->x, 0, app->image->w - 1); |
||
88 | int x1 = CLAMP(rect.x1 - app->image->x, 0, app->image->w - 1); |
||
89 | int y0 = CLAMP(rect.y0 - app->image->y, 0, app->image->h - 1); |
||
90 | int y1 = CLAMP(rect.y1 - app->image->y, 0, app->image->h - 1); |
||
91 | |||
92 | for (y = y0; y < y1; y++) |
||
93 | { |
||
94 | p = app->image->samples + (y * app->image->w + x0) * app->image->n; |
||
95 | for (x = x0; x < x1; x++) |
||
96 | { |
||
97 | for (n = app->image->n; n > 0; n--, p++) |
||
98 | *p = 255 - *p; |
||
99 | } |
||
100 | } |
||
101 | } |
||
102 | |||
103 | static void pdfapp_open_pdf(pdfapp_t *app, char *filename, int fd) |
||
104 | { |
||
105 | fz_error error; |
||
106 | fz_stream *file; |
||
107 | char *password = ""; |
||
108 | fz_obj *obj; |
||
109 | fz_obj *info; |
||
110 | |||
111 | /* |
||
112 | * Open PDF and load xref table |
||
113 | */ |
||
8436 | maxcodehac | 114 | kol_board_puts("FZ OPEN\n"); |
4680 | right-hear | 115 | //file = fz_open_fd(fd); |
8436 | maxcodehac | 116 | kol_board_puts("FZ ready\n"); |
4680 | right-hear | 117 | error = pdf_open_xref(&app->xref, filename, NULL); |
118 | if (error){ |
||
8436 | maxcodehac | 119 | kol_board_puts("FZ can't open\n"); |
4680 | right-hear | 120 | pdfapp_error(app, fz_rethrow(error, "cannot open document '%s'", filename));} |
121 | fz_close(file); |
||
122 | |||
123 | /* |
||
124 | * Handle encrypted PDF files |
||
125 | */ |
||
126 | /* |
||
127 | if (pdf_needs_password(app->xref)) |
||
128 | { |
||
129 | int okay = pdf_authenticate_password(app->xref, password); |
||
130 | while (!okay) |
||
131 | { |
||
132 | password = winpassword(app, filename); |
||
133 | if (!password) |
||
134 | exit(1); |
||
135 | okay = pdf_authenticate_password(app->xref, password); |
||
136 | if (!okay) |
||
137 | pdfapp_warn(app, "Invalid password."); |
||
138 | } |
||
139 | } |
||
140 | * */ |
||
141 | |||
142 | /* |
||
143 | * Load meta information |
||
144 | */ |
||
145 | |||
146 | /* |
||
147 | app->outline = pdf_load_outline(app->xref); |
||
148 | |||
149 | app->doctitle = filename; |
||
150 | if (strrchr(app->doctitle, '\\')) |
||
151 | app->doctitle = strrchr(app->doctitle, '\\') + 1; |
||
152 | if (strrchr(app->doctitle, '/')) |
||
153 | app->doctitle = strrchr(app->doctitle, '/') + 1; |
||
154 | info = fz_dict_gets(app->xref->trailer, "Info"); |
||
155 | if (info) |
||
156 | { |
||
157 | obj = fz_dict_gets(info, "Title"); |
||
158 | if (obj) |
||
159 | app->doctitle = pdf_to_utf8(obj); |
||
160 | } */ |
||
161 | |||
162 | /* |
||
163 | * Start at first page |
||
164 | */ |
||
8436 | maxcodehac | 165 | kol_board_puts("Start at first page\n"); |
4680 | right-hear | 166 | |
167 | error = pdf_load_page_tree(app->xref); |
||
168 | if (error) { |
||
8436 | maxcodehac | 169 | kol_board_puts("Can't load tree\n"); |
4680 | right-hear | 170 | pdfapp_error(app, fz_rethrow(error, "cannot load page tree"));} |
171 | |||
8436 | maxcodehac | 172 | kol_board_puts("Page counter\n"); |
4680 | right-hear | 173 | app->pagecount = pdf_count_pages(app->xref); |
8436 | maxcodehac | 174 | kol_board_puts("All is set!\n"); |
4680 | right-hear | 175 | } |
176 | |||
177 | void pdfapp_open(pdfapp_t *app, char *filename, int fd, int reload) |
||
178 | { |
||
7621 | leency | 179 | pdfapp_open_pdf(app, filename, fd); |
4680 | right-hear | 180 | |
181 | app->cache = fz_new_glyph_cache(); |
||
182 | |||
183 | if (app->pageno < 1) |
||
184 | app->pageno = 1; |
||
185 | if (app->pageno > app->pagecount) |
||
186 | app->pageno = app->pagecount; |
||
187 | if (app->resolution < MINRES) |
||
188 | app->resolution = MINRES; |
||
189 | if (app->resolution > MAXRES) |
||
190 | app->resolution = MAXRES; |
||
191 | |||
192 | if (!reload) |
||
193 | { |
||
194 | app->shrinkwrap = 1; |
||
195 | app->rotate = 0; |
||
196 | app->panx = 0; |
||
197 | app->pany = 0; |
||
198 | } |
||
199 | |||
200 | pdfapp_showpage(app, 1, 1, 1); |
||
201 | } |
||
202 | |||
203 | void pdfapp_close(pdfapp_t *app) |
||
204 | { |
||
205 | if (app->cache) |
||
206 | fz_free_glyph_cache(app->cache); |
||
207 | app->cache = NULL; |
||
208 | |||
209 | if (app->image) |
||
210 | fz_drop_pixmap(app->image); |
||
211 | app->image = NULL; |
||
212 | |||
213 | if (app->outline) |
||
214 | pdf_free_outline(app->outline); |
||
215 | app->outline = NULL; |
||
216 | |||
217 | if (app->xref) |
||
218 | { |
||
219 | if (app->xref->store) |
||
220 | pdf_free_store(app->xref->store); |
||
221 | app->xref->store = NULL; |
||
222 | |||
223 | pdf_free_xref(app->xref); |
||
224 | app->xref = NULL; |
||
225 | } |
||
226 | |||
227 | fz_flush_warnings(); |
||
228 | } |
||
229 | |||
230 | static fz_matrix pdfapp_viewctm(pdfapp_t *app) |
||
231 | { |
||
232 | fz_matrix ctm; |
||
233 | ctm = fz_identity; |
||
234 | ctm = fz_concat(ctm, fz_translate(0, -app->page_bbox.y1)); |
||
235 | if (app->xref) |
||
236 | ctm = fz_concat(ctm, fz_scale(app->resolution/72.0f, -app->resolution/72.0f)); |
||
237 | else |
||
238 | ctm = fz_concat(ctm, fz_scale(app->resolution/96.0f, app->resolution/96.0f)); |
||
239 | ctm = fz_concat(ctm, fz_rotate(app->rotate + app->page_rotate)); |
||
240 | return ctm; |
||
241 | } |
||
242 | |||
243 | static void pdfapp_panview(pdfapp_t *app, int newx, int newy) |
||
244 | { |
||
245 | if (newx < 0) |
||
246 | newx = 0; |
||
247 | if (newy < 0) |
||
248 | newy = 0; |
||
249 | |||
250 | if (newx + app->image->w < app->winw) |
||
251 | newx = app->winw - app->image->w; |
||
252 | if (newy + app->image->h < app->winh) |
||
253 | newy = app->winh - app->image->h; |
||
254 | |||
255 | if (app->winw >= app->image->w) |
||
256 | newx = (app->winw - app->image->w) / 2; |
||
257 | if (app->winh >= app->image->h) |
||
258 | newy = (app->winh - app->image->h) / 2; |
||
259 | |||
260 | if (newx != app->panx || newy != app->pany) |
||
261 | winrepaint(app); |
||
262 | |||
263 | if (newy > app->image->h) { |
||
264 | |||
265 | app->pageno++; |
||
266 | |||
267 | |||
268 | if (app->pageno > app->pagecount) |
||
269 | app->pageno = app->pagecount; |
||
270 | |||
271 | |||
272 | newy = 0; |
||
273 | app->pany = newy; |
||
274 | |||
275 | pdfapp_showpage(app, 1, 1, 1); |
||
276 | } |
||
277 | |||
278 | app->panx = newx; |
||
279 | app->pany = newy; |
||
280 | } |
||
281 | |||
282 | static void pdfapp_loadpage_pdf(pdfapp_t *app) |
||
283 | { |
||
284 | pdf_page *page; |
||
285 | fz_error error; |
||
286 | fz_device *mdev; |
||
287 | |||
288 | error = pdf_load_page(&page, app->xref, app->pageno - 1); |
||
289 | if (error) |
||
290 | pdfapp_error(app, error); |
||
291 | |||
292 | app->page_bbox = page->mediabox; |
||
293 | app->page_rotate = page->rotate; |
||
294 | app->page_links = page->links; |
||
295 | page->links = NULL; |
||
296 | |||
297 | /* Create display list */ |
||
298 | app->page_list = fz_new_display_list(); |
||
299 | mdev = fz_new_list_device(app->page_list); |
||
300 | error = pdf_run_page(app->xref, page, mdev, fz_identity); |
||
301 | if (error) |
||
302 | { |
||
303 | error = fz_rethrow(error, "cannot draw page %d in '%s'", app->pageno, app->doctitle); |
||
304 | pdfapp_error(app, error); |
||
305 | } |
||
306 | fz_free_device(mdev); |
||
307 | |||
308 | pdf_free_page(page); |
||
309 | |||
310 | pdf_age_store(app->xref->store, 3); |
||
311 | } |
||
312 | |||
313 | static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint) |
||
314 | { |
||
315 | char buf[256]; |
||
316 | fz_device *idev; |
||
317 | fz_device *tdev; |
||
318 | fz_colorspace *colorspace; |
||
319 | fz_matrix ctm; |
||
320 | fz_bbox bbox; |
||
321 | |||
322 | wincursor(app, WAIT); |
||
323 | |||
324 | if (loadpage) |
||
325 | { |
||
326 | if (app->page_list) |
||
327 | fz_free_display_list(app->page_list); |
||
328 | if (app->page_text) |
||
329 | fz_free_text_span(app->page_text); |
||
330 | if (app->page_links) |
||
331 | pdf_free_link(app->page_links); |
||
332 | |||
333 | if (app->xref) |
||
334 | pdfapp_loadpage_pdf(app); |
||
335 | |||
336 | /* Zero search hit position */ |
||
337 | app->hit = -1; |
||
338 | app->hitlen = 0; |
||
339 | |||
340 | /* Extract text */ |
||
341 | app->page_text = fz_new_text_span(); |
||
342 | tdev = fz_new_text_device(app->page_text); |
||
343 | fz_execute_display_list(app->page_list, tdev, fz_identity, fz_infinite_bbox); |
||
344 | fz_free_device(tdev); |
||
345 | } |
||
346 | |||
347 | if (drawpage) |
||
348 | { |
||
7621 | leency | 349 | sprintf(buf, "%s - %d/%d (%d dpi)", app->doctitle, |
350 | app->pageno, app->pagecount, app->resolution); |
||
8438 | maxcodehac | 351 | /// wintitle(app, buf); |
4680 | right-hear | 352 | |
353 | ctm = pdfapp_viewctm(app); |
||
354 | bbox = fz_round_rect(fz_transform_rect(ctm, app->page_bbox)); |
||
355 | |||
356 | /* Draw */ |
||
357 | if (app->image) |
||
358 | fz_drop_pixmap(app->image); |
||
359 | if (app->grayscale) |
||
360 | colorspace = fz_device_gray; |
||
361 | else |
||
8461 | maxcodehac | 362 | /* |
363 | #ifdef _WIN32 |
||
4680 | right-hear | 364 | colorspace = fz_device_bgr; |
8461 | maxcodehac | 365 | #else |
366 | colorspace = fz_device_rgb; |
||
367 | #endif |
||
368 | */ |
||
369 | colorspace = fz_device_bgr; |
||
370 | |||
4680 | right-hear | 371 | app->image = fz_new_pixmap_with_rect(colorspace, bbox); |
372 | fz_clear_pixmap_with_color(app->image, 255); |
||
373 | idev = fz_new_draw_device(app->cache, app->image); |
||
374 | fz_execute_display_list(app->page_list, idev, ctm, bbox); |
||
375 | fz_free_device(idev); |
||
376 | } |
||
377 | |||
378 | if (repaint) |
||
8461 | maxcodehac | 379 | { |
4680 | right-hear | 380 | pdfapp_panview(app, app->panx, app->pany); |
381 | |||
382 | if (app->shrinkwrap) |
||
383 | { |
||
8436 | maxcodehac | 384 | kol_board_puts ("SHRINK\n"); |
4680 | right-hear | 385 | int w = app->image->w; |
386 | int h = app->image->h; |
||
387 | if (app->winw == w) |
||
388 | app->panx = 0; |
||
389 | if (app->winh == h) |
||
390 | app->pany = 0; |
||
391 | if (w > app->scrw * 90 / 100) |
||
392 | w = app->scrw * 90 / 100; |
||
393 | if (h > app->scrh * 90 / 100) |
||
394 | h = app->scrh * 90 / 100; |
||
395 | if (w != app->winw || h != app->winh) |
||
396 | winresize(app, w, h); |
||
397 | } |
||
398 | |||
399 | winrepaint(app); |
||
400 | |||
401 | wincursor(app, ARROW); |
||
402 | } |
||
403 | |||
404 | fz_flush_warnings(); |
||
8461 | maxcodehac | 405 | |
406 | DrawPageSides(); |
||
4680 | right-hear | 407 | } |
408 | |||
409 | static void pdfapp_gotouri(pdfapp_t *app, fz_obj *uri) |
||
410 | { |
||
411 | char *buf; |
||
412 | buf = fz_malloc(fz_to_str_len(uri) + 1); |
||
413 | memcpy(buf, fz_to_str_buf(uri), fz_to_str_len(uri)); |
||
414 | buf[fz_to_str_len(uri)] = 0; |
||
415 | winopenuri(app, buf); |
||
416 | fz_free(buf); |
||
417 | } |
||
418 | |||
419 | static void pdfapp_gotopage(pdfapp_t *app, fz_obj *obj) |
||
420 | { |
||
421 | int number; |
||
422 | |||
423 | number = pdf_find_page_number(app->xref, obj); |
||
424 | if (number < 0) |
||
425 | return; |
||
426 | |||
427 | if (app->histlen + 1 == 256) |
||
428 | { |
||
429 | memmove(app->hist, app->hist + 1, sizeof(int) * 255); |
||
430 | app->histlen --; |
||
431 | } |
||
432 | app->hist[app->histlen++] = app->pageno; |
||
433 | app->pageno = number + 1; |
||
434 | pdfapp_showpage(app, 1, 1, 1); |
||
435 | } |
||
436 | |||
437 | static inline fz_bbox bboxcharat(fz_text_span *span, int idx) |
||
438 | { |
||
439 | int ofs = 0; |
||
440 | while (span) |
||
441 | { |
||
442 | if (idx < ofs + span->len) |
||
443 | return span->text[idx - ofs].bbox; |
||
444 | if (span->eol) |
||
445 | { |
||
446 | if (idx == ofs + span->len) |
||
447 | return fz_empty_bbox; |
||
448 | ofs ++; |
||
449 | } |
||
450 | ofs += span->len; |
||
451 | span = span->next; |
||
452 | } |
||
453 | return fz_empty_bbox; |
||
454 | } |
||
455 | |||
456 | void pdfapp_inverthit(pdfapp_t *app) |
||
457 | { |
||
458 | fz_bbox hitbox, bbox; |
||
459 | fz_matrix ctm; |
||
460 | int i; |
||
461 | |||
462 | if (app->hit < 0) |
||
463 | return; |
||
464 | |||
465 | hitbox = fz_empty_bbox; |
||
466 | ctm = pdfapp_viewctm(app); |
||
467 | |||
468 | for (i = app->hit; i < app->hit + app->hitlen; i++) |
||
469 | { |
||
470 | bbox = bboxcharat(app->page_text, i); |
||
471 | if (fz_is_empty_rect(bbox)) |
||
472 | { |
||
473 | if (!fz_is_empty_rect(hitbox)) |
||
474 | pdfapp_invert(app, fz_transform_bbox(ctm, hitbox)); |
||
475 | hitbox = fz_empty_bbox; |
||
476 | } |
||
477 | else |
||
478 | { |
||
479 | hitbox = fz_union_bbox(hitbox, bbox); |
||
480 | } |
||
481 | } |
||
482 | |||
483 | if (!fz_is_empty_rect(hitbox)) |
||
484 | pdfapp_invert(app, fz_transform_bbox(ctm, hitbox)); |
||
485 | } |
||
486 | |||
487 | static inline int charat(fz_text_span *span, int idx) |
||
488 | { |
||
489 | int ofs = 0; |
||
490 | while (span) |
||
491 | { |
||
492 | if (idx < ofs + span->len) |
||
493 | return span->text[idx - ofs].c; |
||
494 | if (span->eol) |
||
495 | { |
||
496 | if (idx == ofs + span->len) |
||
497 | return ' '; |
||
498 | ofs ++; |
||
499 | } |
||
500 | ofs += span->len; |
||
501 | span = span->next; |
||
502 | } |
||
503 | return 0; |
||
504 | } |
||
505 | |||
506 | static int textlen(fz_text_span *span) |
||
507 | { |
||
508 | int len = 0; |
||
509 | while (span) |
||
510 | { |
||
511 | len += span->len; |
||
512 | if (span->eol) |
||
513 | len ++; |
||
514 | span = span->next; |
||
515 | } |
||
516 | return len; |
||
517 | } |
||
518 | |||
519 | static int match(char *s, fz_text_span *span, int n) |
||
520 | { |
||
521 | int orig = n; |
||
522 | int c; |
||
523 | while ((c = *s++)) |
||
524 | { |
||
525 | if (c == ' ' && charat(span, n) == ' ') |
||
526 | { |
||
527 | while (charat(span, n) == ' ') |
||
528 | n++; |
||
529 | } |
||
530 | else |
||
531 | { |
||
532 | if (tolower(c) != tolower(charat(span, n))) |
||
533 | return 0; |
||
534 | n++; |
||
535 | } |
||
536 | } |
||
537 | return n - orig; |
||
538 | } |
||
539 | |||
540 | static void pdfapp_searchforward(pdfapp_t *app, enum panning *panto) |
||
541 | { |
||
542 | int matchlen; |
||
543 | int test; |
||
544 | int len; |
||
545 | int startpage; |
||
546 | |||
547 | wincursor(app, WAIT); |
||
548 | |||
549 | startpage = app->pageno; |
||
550 | |||
551 | do |
||
552 | { |
||
553 | len = textlen(app->page_text); |
||
554 | |||
555 | if (app->hit >= 0) |
||
556 | test = app->hit + strlen(app->search); |
||
557 | else |
||
558 | test = 0; |
||
559 | |||
560 | while (test < len) |
||
561 | { |
||
562 | matchlen = match(app->search, app->page_text, test); |
||
563 | if (matchlen) |
||
564 | { |
||
565 | app->hit = test; |
||
566 | app->hitlen = matchlen; |
||
567 | wincursor(app, HAND); |
||
568 | winrepaint(app); |
||
569 | return; |
||
570 | } |
||
571 | test++; |
||
572 | } |
||
573 | |||
574 | app->pageno++; |
||
575 | if (app->pageno > app->pagecount) |
||
576 | app->pageno = 1; |
||
577 | |||
578 | pdfapp_showpage(app, 1, 0, 0); |
||
579 | *panto = PAN_TO_TOP; |
||
580 | |||
581 | } while (app->pageno != startpage); |
||
582 | |||
583 | if (app->pageno == startpage) |
||
584 | { |
||
585 | pdfapp_warn(app, "String '%s' not found.", app->search); |
||
586 | winrepaintsearch(app); |
||
587 | } |
||
588 | else |
||
589 | winrepaint(app); |
||
590 | |||
591 | wincursor(app, HAND); |
||
592 | } |
||
593 | |||
594 | static void pdfapp_searchbackward(pdfapp_t *app, enum panning *panto) |
||
595 | { |
||
596 | int matchlen; |
||
597 | int test; |
||
598 | int len; |
||
599 | int startpage; |
||
600 | |||
601 | wincursor(app, WAIT); |
||
602 | |||
603 | startpage = app->pageno; |
||
604 | |||
605 | do |
||
606 | { |
||
607 | len = textlen(app->page_text); |
||
608 | |||
609 | if (app->hit >= 0) |
||
610 | test = app->hit - 1; |
||
611 | else |
||
612 | test = len; |
||
613 | |||
614 | while (test >= 0) |
||
615 | { |
||
616 | matchlen = match(app->search, app->page_text, test); |
||
617 | if (matchlen) |
||
618 | { |
||
619 | app->hit = test; |
||
620 | app->hitlen = matchlen; |
||
621 | wincursor(app, HAND); |
||
622 | winrepaint(app); |
||
623 | return; |
||
624 | } |
||
625 | test--; |
||
626 | } |
||
627 | |||
628 | app->pageno--; |
||
629 | if (app->pageno < 1) |
||
630 | app->pageno = app->pagecount; |
||
631 | |||
632 | pdfapp_showpage(app, 1, 0, 0); |
||
633 | *panto = PAN_TO_BOTTOM; |
||
634 | |||
635 | } while (app->pageno != startpage); |
||
636 | |||
637 | if (app->pageno == startpage) |
||
638 | { |
||
639 | pdfapp_warn(app, "String '%s' not found.", app->search); |
||
640 | winrepaintsearch(app); |
||
641 | } |
||
642 | else |
||
643 | winrepaint(app); |
||
644 | |||
645 | wincursor(app, HAND); |
||
646 | } |
||
647 | |||
648 | void pdfapp_onresize(pdfapp_t *app, int w, int h) |
||
649 | { |
||
650 | if (app->winw != w || app->winh != h) |
||
651 | { |
||
652 | app->winw = w; |
||
653 | app->winh = h; |
||
654 | pdfapp_panview(app, app->panx, app->pany); |
||
655 | winrepaint(app); |
||
656 | } |
||
657 | } |
||
658 | |||
659 | void pdfapp_onkey(pdfapp_t *app, int c) |
||
660 | { |
||
661 | int oldpage = app->pageno; |
||
662 | enum panning panto = PAN_TO_TOP; |
||
663 | int loadpage = 1; |
||
664 | |||
665 | if (app->isediting) |
||
666 | { |
||
667 | int n = strlen(app->search); |
||
668 | if (c < ' ') |
||
669 | { |
||
670 | if (c == '\b' && n > 0) |
||
671 | { |
||
672 | app->search[n - 1] = 0; |
||
673 | winrepaintsearch(app); |
||
674 | } |
||
675 | if (c == '\n' || c == '\r') |
||
676 | { |
||
677 | app->isediting = 0; |
||
678 | if (n > 0) |
||
679 | { |
||
680 | winrepaintsearch(app); |
||
681 | pdfapp_onkey(app, 'n'); |
||
682 | } |
||
683 | else |
||
684 | winrepaint(app); |
||
685 | } |
||
686 | if (c == '\033') |
||
687 | { |
||
688 | app->isediting = 0; |
||
689 | winrepaint(app); |
||
690 | } |
||
691 | } |
||
692 | else |
||
693 | { |
||
694 | if (n + 2 < sizeof app->search) |
||
695 | { |
||
696 | app->search[n] = c; |
||
697 | app->search[n + 1] = 0; |
||
698 | winrepaintsearch(app); |
||
699 | } |
||
700 | } |
||
701 | return; |
||
702 | } |
||
703 | |||
704 | /* |
||
705 | * Save numbers typed for later |
||
706 | */ |
||
707 | |||
708 | if (c >= '0' && c <= '9') |
||
709 | { |
||
710 | app->number[app->numberlen++] = c; |
||
711 | app->number[app->numberlen] = '\0'; |
||
712 | } |
||
713 | |||
714 | switch (c) |
||
715 | { |
||
716 | |||
717 | case '?': |
||
718 | winhelp(app); |
||
719 | break; |
||
720 | |||
721 | case 'q': |
||
722 | winclose(app); |
||
723 | break; |
||
724 | |||
725 | /* |
||
726 | * Zoom and rotate |
||
727 | */ |
||
728 | |||
729 | case '+': |
||
730 | case '=': |
||
731 | app->resolution *= ZOOMSTEP; |
||
732 | if (app->resolution > MAXRES) |
||
733 | app->resolution = MAXRES; |
||
734 | pdfapp_showpage(app, 0, 1, 1); |
||
735 | break; |
||
736 | case '-': |
||
737 | app->resolution /= ZOOMSTEP; |
||
738 | if (app->resolution < MINRES) |
||
739 | app->resolution = MINRES; |
||
740 | pdfapp_showpage(app, 0, 1, 1); |
||
741 | break; |
||
742 | |||
743 | case 'L': |
||
744 | app->rotate -= 90; |
||
745 | pdfapp_showpage(app, 0, 1, 1); |
||
746 | break; |
||
747 | case 'R': |
||
748 | app->rotate += 90; |
||
749 | pdfapp_showpage(app, 0, 1, 1); |
||
750 | break; |
||
751 | |||
752 | case 'c': |
||
753 | app->grayscale ^= 1; |
||
754 | pdfapp_showpage(app, 0, 1, 1); |
||
755 | break; |
||
756 | |||
757 | #ifndef NDEBUG |
||
758 | case 'a': |
||
759 | app->rotate -= 15; |
||
760 | pdfapp_showpage(app, 0, 1, 1); |
||
761 | break; |
||
762 | case 's': |
||
763 | app->rotate += 15; |
||
764 | pdfapp_showpage(app, 0, 1, 1); |
||
765 | break; |
||
766 | #endif |
||
767 | |||
768 | /* |
||
769 | * Pan view, but dont need to repaint image |
||
770 | */ |
||
771 | |||
772 | case 'w': |
||
773 | app->shrinkwrap = 1; |
||
774 | app->panx = app->pany = 0; |
||
775 | pdfapp_showpage(app, 0, 0, 1); |
||
776 | break; |
||
777 | |||
778 | case 'h': |
||
779 | app->panx += app->image->w / 10; |
||
780 | pdfapp_showpage(app, 0, 0, 1); |
||
781 | break; |
||
782 | |||
783 | case 'j': |
||
784 | app->pany -= app->image->h / 10; |
||
785 | pdfapp_showpage(app, 0, 0, 1); |
||
786 | break; |
||
787 | |||
788 | case 'k': |
||
789 | app->pany += app->image->h / 10; |
||
790 | pdfapp_showpage(app, 0, 0, 1); |
||
791 | break; |
||
792 | |||
793 | case 'l': |
||
794 | app->panx -= app->image->w / 10; |
||
795 | pdfapp_showpage(app, 0, 0, 1); |
||
796 | break; |
||
797 | |||
798 | /* |
||
799 | * Page navigation |
||
800 | */ |
||
801 | |||
802 | case 'g': |
||
803 | case '\n': |
||
804 | case '\r': |
||
805 | if (app->numberlen > 0) |
||
806 | app->pageno = atoi(app->number); |
||
807 | else |
||
808 | app->pageno = 1; |
||
809 | break; |
||
810 | |||
811 | case 'G': |
||
812 | app->pageno = app->pagecount; |
||
813 | break; |
||
814 | |||
815 | case 'm': |
||
816 | if (app->numberlen > 0) |
||
817 | { |
||
818 | int idx = atoi(app->number); |
||
819 | |||
820 | if (idx >= 0 && idx < nelem(app->marks)) |
||
821 | app->marks[idx] = app->pageno; |
||
822 | } |
||
823 | else |
||
824 | { |
||
825 | if (app->histlen + 1 == 256) |
||
826 | { |
||
827 | memmove(app->hist, app->hist + 1, sizeof(int) * 255); |
||
828 | app->histlen --; |
||
829 | } |
||
830 | app->hist[app->histlen++] = app->pageno; |
||
831 | } |
||
832 | break; |
||
833 | |||
834 | case 't': |
||
835 | if (app->numberlen > 0) |
||
836 | { |
||
837 | int idx = atoi(app->number); |
||
838 | |||
839 | if (idx >= 0 && idx < nelem(app->marks)) |
||
840 | if (app->marks[idx] > 0) |
||
841 | app->pageno = app->marks[idx]; |
||
842 | } |
||
843 | else if (app->histlen > 0) |
||
844 | app->pageno = app->hist[--app->histlen]; |
||
845 | break; |
||
846 | |||
847 | /* |
||
848 | * Back and forth ... |
||
849 | */ |
||
850 | |||
851 | case ',': |
||
852 | panto = PAN_TO_BOTTOM; |
||
853 | if (app->numberlen > 0) |
||
854 | app->pageno -= atoi(app->number); |
||
855 | else |
||
856 | app->pageno--; |
||
857 | break; |
||
858 | |||
859 | case '.': |
||
860 | panto = PAN_TO_TOP; |
||
861 | if (app->numberlen > 0) |
||
862 | app->pageno += atoi(app->number); |
||
863 | else |
||
864 | app->pageno++; |
||
865 | break; |
||
866 | |||
867 | case 'b': |
||
868 | panto = DONT_PAN; |
||
869 | if (app->numberlen > 0) |
||
870 | app->pageno -= atoi(app->number); |
||
871 | else |
||
872 | app->pageno--; |
||
873 | break; |
||
874 | |||
875 | case ' ': |
||
876 | panto = DONT_PAN; |
||
877 | if (app->numberlen > 0) |
||
878 | app->pageno += atoi(app->number); |
||
879 | else |
||
880 | app->pageno++; |
||
881 | break; |
||
882 | |||
883 | case ']': |
||
884 | panto = PAN_TO_TOP; |
||
885 | app->pageno++; |
||
886 | break; |
||
887 | |||
888 | case '[': |
||
889 | panto = PAN_TO_TOP; |
||
890 | app->pageno--; |
||
891 | break; |
||
892 | |||
893 | |||
894 | case '<': |
||
895 | panto = PAN_TO_TOP; |
||
896 | app->pageno -= 10; |
||
897 | break; |
||
898 | case '>': |
||
899 | panto = PAN_TO_TOP; |
||
900 | app->pageno += 10; |
||
901 | break; |
||
902 | |||
903 | /* |
||
904 | * Reloading the file... |
||
905 | */ |
||
906 | |||
907 | case 'r': |
||
908 | panto = DONT_PAN; |
||
909 | oldpage = -1; |
||
910 | winreloadfile(app); |
||
911 | break; |
||
912 | |||
913 | /* |
||
914 | * Searching |
||
915 | */ |
||
916 | |||
917 | case '/': |
||
918 | app->isediting = 1; |
||
919 | app->search[0] = 0; |
||
920 | app->hit = -1; |
||
921 | app->hitlen = 0; |
||
922 | winrepaintsearch(app); |
||
923 | break; |
||
924 | |||
925 | case 'n': |
||
926 | pdfapp_searchforward(app, &panto); |
||
927 | loadpage = 0; |
||
928 | break; |
||
929 | |||
930 | case 'N': |
||
931 | pdfapp_searchbackward(app, &panto); |
||
932 | loadpage = 0; |
||
933 | break; |
||
934 | |||
935 | } |
||
936 | |||
937 | if (c < '0' || c > '9') |
||
938 | app->numberlen = 0; |
||
939 | |||
940 | if (app->pageno < 1) |
||
941 | app->pageno = 1; |
||
942 | if (app->pageno > app->pagecount) |
||
943 | app->pageno = app->pagecount; |
||
944 | |||
945 | if (app->pageno != oldpage) |
||
946 | { |
||
947 | switch (panto) |
||
948 | { |
||
949 | case PAN_TO_TOP: |
||
950 | app->pany = 0; |
||
951 | break; |
||
952 | case PAN_TO_BOTTOM: |
||
953 | app->pany = -2000; |
||
954 | break; |
||
955 | case DONT_PAN: |
||
956 | break; |
||
957 | } |
||
958 | pdfapp_showpage(app, loadpage, 1, 1); |
||
959 | } |
||
960 | } |
||
961 | |||
962 | void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int state) |
||
963 | { |
||
964 | pdf_link *link; |
||
965 | fz_matrix ctm; |
||
966 | fz_point p; |
||
967 | |||
968 | p.x = x - app->panx + app->image->x; |
||
969 | p.y = y - app->pany + app->image->y; |
||
970 | |||
971 | ctm = pdfapp_viewctm(app); |
||
972 | ctm = fz_invert_matrix(ctm); |
||
973 | |||
974 | p = fz_transform_point(ctm, p); |
||
975 | |||
976 | for (link = app->page_links; link; link = link->next) |
||
977 | { |
||
978 | if (p.x >= link->rect.x0 && p.x <= link->rect.x1) |
||
979 | if (p.y >= link->rect.y0 && p.y <= link->rect.y1) |
||
980 | break; |
||
981 | } |
||
982 | |||
983 | if (link) |
||
984 | { |
||
985 | wincursor(app, HAND); |
||
986 | if (btn == 1 && state == 1) |
||
987 | { |
||
988 | if (link->kind == PDF_LINK_URI) |
||
989 | pdfapp_gotouri(app, link->dest); |
||
990 | else if (link->kind == PDF_LINK_GOTO) |
||
991 | pdfapp_gotopage(app, fz_array_get(link->dest, 0)); /* [ pageobj ... ] */ |
||
992 | return; |
||
993 | } |
||
994 | } |
||
995 | else |
||
996 | { |
||
997 | wincursor(app, ARROW); |
||
998 | } |
||
999 | |||
1000 | if (state == 1) |
||
1001 | { |
||
1002 | if (btn == 1 && !app->iscopying) |
||
1003 | { |
||
1004 | app->ispanning = 1; |
||
1005 | app->selx = x; |
||
1006 | app->sely = y; |
||
1007 | app->beyondy = 0; |
||
1008 | } |
||
1009 | if (btn == 3 && !app->ispanning) |
||
1010 | { |
||
1011 | app->iscopying = 1; |
||
1012 | app->selx = x; |
||
1013 | app->sely = y; |
||
1014 | app->selr.x0 = x; |
||
1015 | app->selr.x1 = x; |
||
1016 | app->selr.y0 = y; |
||
1017 | app->selr.y1 = y; |
||
1018 | } |
||
1019 | if (btn == 4 || btn == 5) /* scroll wheel */ |
||
1020 | { |
||
1021 | int dir = btn == 4 ? 1 : -1; |
||
1022 | app->ispanning = app->iscopying = 0; |
||
1023 | if (modifiers & (1<<2)) |
||
1024 | { |
||
1025 | /* zoom in/out if ctrl is pressed */ |
||
1026 | if (dir > 0) |
||
1027 | app->resolution *= ZOOMSTEP; |
||
1028 | else |
||
1029 | app->resolution /= ZOOMSTEP; |
||
1030 | if (app->resolution > MAXRES) |
||
1031 | app->resolution = MAXRES; |
||
1032 | if (app->resolution < MINRES) |
||
1033 | app->resolution = MINRES; |
||
1034 | pdfapp_showpage(app, 0, 1, 1); |
||
1035 | } |
||
1036 | else |
||
1037 | { |
||
1038 | /* scroll up/down, or left/right if |
||
1039 | shift is pressed */ |
||
1040 | int isx = (modifiers & (1<<0)); |
||
1041 | int xstep = isx ? 20 * dir : 0; |
||
1042 | int ystep = !isx ? 20 * dir : 0; |
||
1043 | pdfapp_panview(app, app->panx + xstep, app->pany + ystep); |
||
1044 | } |
||
1045 | } |
||
1046 | } |
||
1047 | |||
1048 | else if (state == -1) |
||
1049 | { |
||
1050 | if (app->iscopying) |
||
1051 | { |
||
1052 | app->iscopying = 0; |
||
1053 | app->selr.x0 = MIN(app->selx, x) - app->panx + app->image->x; |
||
1054 | app->selr.x1 = MAX(app->selx, x) - app->panx + app->image->x; |
||
1055 | app->selr.y0 = MIN(app->sely, y) - app->pany + app->image->y; |
||
1056 | app->selr.y1 = MAX(app->sely, y) - app->pany + app->image->y; |
||
1057 | winrepaint(app); |
||
1058 | if (app->selr.x0 < app->selr.x1 && app->selr.y0 < app->selr.y1) |
||
1059 | windocopy(app); |
||
1060 | } |
||
1061 | if (app->ispanning) |
||
1062 | app->ispanning = 0; |
||
1063 | } |
||
1064 | |||
1065 | else if (app->ispanning) |
||
1066 | { |
||
1067 | int newx = app->panx + x - app->selx; |
||
1068 | int newy = app->pany + y - app->sely; |
||
1069 | /* Scrolling beyond limits implies flipping pages */ |
||
1070 | /* Are we requested to scroll beyond limits? */ |
||
1071 | if (newy + app->image->h < app->winh || newy > 0) |
||
1072 | { |
||
1073 | /* Yes. We can assume that deltay != 0 */ |
||
1074 | int deltay = y - app->sely; |
||
1075 | /* Check whether the panning has occured in the |
||
1076 | * direction that we are already crossing the |
||
1077 | * limit it. If not, we can conclude that we |
||
1078 | * have switched ends of the page and will thus |
||
1079 | * start over counting. |
||
1080 | */ |
||
1081 | if( app->beyondy == 0 || (app->beyondy ^ deltay) >= 0 ) |
||
1082 | { |
||
1083 | /* Updating how far we are beyond and |
||
1084 | * flipping pages if beyond threshhold |
||
1085 | */ |
||
1086 | app->beyondy += deltay; |
||
1087 | if (app->beyondy > BEYOND_THRESHHOLD) |
||
1088 | { |
||
1089 | if( app->pageno > 1 ) |
||
1090 | { |
||
1091 | app->pageno--; |
||
1092 | pdfapp_showpage(app, 1, 1, 1); |
||
1093 | newy = -app->image->h; |
||
1094 | } |
||
1095 | app->beyondy = 0; |
||
1096 | } |
||
1097 | else if (app->beyondy < -BEYOND_THRESHHOLD) |
||
1098 | { |
||
1099 | if( app->pageno < app->pagecount ) |
||
1100 | { |
||
1101 | app->pageno++; |
||
1102 | pdfapp_showpage(app, 1, 1, 1); |
||
1103 | newy = 0; |
||
1104 | } |
||
1105 | app->beyondy = 0; |
||
1106 | } |
||
1107 | } |
||
1108 | else |
||
1109 | app->beyondy = 0; |
||
1110 | } |
||
1111 | /* Although at this point we've already determined that |
||
1112 | * or that no scrolling will be performed in |
||
1113 | * y-direction, the x-direction has not yet been taken |
||
1114 | * care off. Therefore |
||
1115 | */ |
||
1116 | pdfapp_panview(app, newx, newy); |
||
1117 | |||
1118 | app->selx = x; |
||
1119 | app->sely = y; |
||
1120 | } |
||
1121 | |||
1122 | else if (app->iscopying) |
||
1123 | { |
||
1124 | app->selr.x0 = MIN(app->selx, x) - app->panx + app->image->x; |
||
1125 | app->selr.x1 = MAX(app->selx, x) - app->panx + app->image->x; |
||
1126 | app->selr.y0 = MIN(app->sely, y) - app->pany + app->image->y; |
||
1127 | app->selr.y1 = MAX(app->sely, y) - app->pany + app->image->y; |
||
1128 | winrepaint(app); |
||
1129 | } |
||
1130 | |||
1131 | } |
||
1132 | |||
1133 | void pdfapp_oncopy(pdfapp_t *app, unsigned short *ucsbuf, int ucslen) |
||
1134 | { |
||
1135 | fz_bbox hitbox; |
||
1136 | fz_matrix ctm; |
||
1137 | fz_text_span *span; |
||
1138 | int c, i, p; |
||
1139 | int seen; |
||
1140 | |||
1141 | int x0 = app->selr.x0; |
||
1142 | int x1 = app->selr.x1; |
||
1143 | int y0 = app->selr.y0; |
||
1144 | int y1 = app->selr.y1; |
||
1145 | |||
1146 | ctm = pdfapp_viewctm(app); |
||
1147 | |||
1148 | p = 0; |
||
1149 | for (span = app->page_text; span; span = span->next) |
||
1150 | { |
||
1151 | seen = 0; |
||
1152 | |||
1153 | for (i = 0; i < span->len; i++) |
||
1154 | { |
||
1155 | hitbox = fz_transform_bbox(ctm, span->text[i].bbox); |
||
1156 | c = span->text[i].c; |
||
1157 | if (c < 32) |
||
1158 | c = '?'; |
||
1159 | if (hitbox.x1 >= x0 && hitbox.x0 <= x1 && hitbox.y1 >= y0 && hitbox.y0 <= y1) |
||
1160 | { |
||
1161 | if (p < ucslen - 1) |
||
1162 | ucsbuf[p++] = c; |
||
1163 | seen = 1; |
||
1164 | } |
||
1165 | } |
||
1166 | |||
1167 | if (seen && span->eol) |
||
1168 | { |
||
1169 | #ifdef _WIN32 |
||
1170 | if (p < ucslen - 1) |
||
1171 | ucsbuf[p++] = '\r'; |
||
1172 | #endif |
||
1173 | if (p < ucslen - 1) |
||
1174 | ucsbuf[p++] = '\n'; |
||
1175 | } |
||
1176 | } |
||
1177 | |||
1178 | ucsbuf[p] = 0; |
||
1179 | }>>>=>=>>>>>>>>0)); |