Subversion Repositories Kolibri OS

Rev

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