Subversion Repositories Kolibri OS

Rev

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