Subversion Repositories Kolibri OS

Rev

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  /* 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
 
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
}