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