Subversion Repositories Kolibri OS

Rev

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  /* for tolower() */
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
}