Subversion Repositories Kolibri OS

Rev

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