Remove debugging leftover
[llpp.git] / link.c
blob8d72372dac36c80b357958557e7368d53e0d53c2
1 /* lots of code c&p-ed directly from mupdf */
2 #ifdef _WIN32
3 #define WIN32_LEAN_AND_MEAN
4 #include <windows.h>
5 #include <winsock2.h>
6 #define fionread_arg long
7 #define ssize_t int
8 #define FMT_ss "%d"
9 #ifdef _WIN64
10 #define FMT_s "%i64u"
11 #else
12 #define FMT_s "%u"
13 #endif
14 #pragma warning (disable:4244)
15 #pragma warning (disable:4996)
16 #pragma warning (disable:4995)
17 #endif
19 #ifdef _MSC_VER
20 #include <errno.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 static void __declspec (noreturn) err (int exitcode, const char *fmt, ...)
26 va_list ap;
27 int errcode;
29 errcode = errno;
30 va_start (ap, fmt);
31 vfprintf (stderr, fmt, ap);
32 va_end (ap);
33 fprintf (stderr, ": %s\n", strerror (errno));
34 exit (exitcode);
36 static void __declspec (noreturn) errx (int exitcode, const char *fmt, ...)
38 va_list ap;
40 va_start (ap, fmt);
41 vfprintf (stderr, fmt, ap);
42 va_end (ap);
43 fputc ('\n', stderr);
44 exit (exitcode);
46 static void __declspec (noreturn) sockerr (int exitcode, const char *fmt, ...)
48 va_list ap;
50 va_start (ap, fmt);
51 vfprintf (stderr, fmt, ap);
52 va_end (ap);
53 fprintf (stderr, ": wsaerror 0x%x\n", WSAGetLastError ());
54 exit (exitcode);
56 #else
57 #define FMT_ss "%zd"
58 #define FMT_s "%zu"
59 #define fionread_arg int
60 #define ioctlsocket ioctl
61 #define _GNU_SOURCE
62 #include <err.h>
63 #define sockerr err
64 #endif
65 #include <regex.h>
66 #include <errno.h>
67 #include <ctype.h>
68 #include <stdio.h>
69 #include <stdarg.h>
70 #include <stdlib.h>
71 #include <string.h>
72 #include <limits.h>
73 #ifndef _WIN32
74 #include <pthread.h>
75 #include <sys/time.h>
76 #include <sys/types.h>
77 #include <sys/socket.h>
78 #include <sys/ioctl.h>
79 #endif
81 #ifdef __APPLE__
82 #include <OpenGL/gl.h>
83 #else
84 #include <GL/gl.h>
85 #endif
87 #ifndef GL_TEXTURE_RECTANGLE_ARB
88 #define GL_TEXTURE_RECTANGLE_ARB 0x84F5
89 #endif
91 #include <caml/fail.h>
92 #include <caml/alloc.h>
93 #include <caml/memory.h>
94 #include <caml/unixsupport.h>
96 #include <fitz.h>
97 #include <mupdf.h>
99 #if 0
100 #define lprintf printf
101 #else
102 #define lprintf(...)
103 #endif
105 #ifdef FT_FREETYPE_H
106 #include FT_FREETYPE_H
107 #endif
109 #define ARSERT(cond) for (;;) { \
110 if (!(cond)) { \
111 errx (1, "%s:%d " #cond, __FILE__, __LINE__); \
113 break; \
116 struct slice {
117 int texindex;
118 int w, h;
121 struct pagedim {
122 int pageno;
123 int rotate;
124 fz_rect box;
125 fz_bbox bbox;
126 fz_matrix ctm, ctm1;
129 struct page {
130 int pageno;
131 int slicecount;
132 fz_textspan *text;
133 fz_pixmap *pixmap;
134 pdf_page *drawpage;
135 struct pagedim pagedim;
136 struct mark {
137 int i;
138 fz_textspan *span;
139 } fmark, lmark;
140 struct slice slices[];
143 #if !defined _WIN32 && !defined __APPLE__
144 #define USE_XSEL
145 #endif
147 struct {
148 int sock;
149 int sliceheight;
150 struct page *pig;
151 struct pagedim *pagedims;
152 int pagecount;
153 int pagedimcount;
154 pdf_xref *xref;
155 fz_glyphcache *cache;
156 int w, h;
158 int texindex;
159 int texcount;
160 GLuint *texids;
162 GLenum texform;
163 GLenum texty;
165 struct {
166 int w, h;
167 struct slice *slice;
168 } *texowners;
170 int rotate;
171 int needoutline;
173 #ifdef _WIN32
174 HANDLE thread;
175 #else
176 pthread_t thread;
177 #endif
178 FILE *xselpipe;
179 } state;
181 #ifdef _WIN32
182 static CRITICAL_SECTION critsec;
184 static void lock (void *unused)
186 (void) unused;
187 EnterCriticalSection (&critsec);
190 static void unlock (void *unused)
192 (void) unused;
193 LeaveCriticalSection (&critsec);
196 static int trylock (void *unused)
198 return TryEnterCriticalSection (&critsec) == 0;
200 #else
201 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
203 static void lock (const char *cap)
205 int ret = pthread_mutex_lock (&mutex);
206 if (ret) {
207 errx (1, "%s: pthread_mutex_lock: %s", cap, strerror (ret));
211 static void unlock (const char *cap)
213 int ret = pthread_mutex_unlock (&mutex);
214 if (ret) {
215 errx (1, "%s: pthread_mutex_unlock: %s", cap, strerror (ret));
219 static int trylock (const char *cap)
221 int ret = pthread_mutex_trylock (&mutex);
223 if (ret && ret != EBUSY) {
224 errx (1, "%s: pthread_mutex_trylock: %s", cap, strerror (ret));
226 return ret == EBUSY;
228 #endif
230 static void *parse_pointer (const char *cap, const char *s)
232 int ret;
233 void *ptr;
235 ret = sscanf (s, "%p", &ptr);
236 if (ret != 1) {
237 errx (1, "%s: cannot parse pointer in `%s'", cap, s);
239 return ptr;
242 static int hasdata (int sock)
244 int ret;
245 fionread_arg avail;
246 ret = ioctlsocket (sock, FIONREAD, &avail);
247 if (ret) sockerr (1, "hasdata: FIONREAD error ret=%d", ret);
248 return avail > 0;
251 static double now (void)
253 struct timeval tv;
255 if (gettimeofday (&tv, NULL)) {
256 err (1, "gettimeofday");
258 return tv.tv_sec + tv.tv_usec*1e-6;
261 static void readdata (int fd, char *p, int size)
263 ssize_t n;
265 n = recv (fd, p, size, 0);
266 if (n - size) {
267 if (!n) errx (1, "EOF while reading");
268 sockerr (1, "recv (req %d, ret " FMT_ss ")", size, n);
272 static void writedata (int fd, char *p, int size)
274 char buf[4];
275 ssize_t n;
277 buf[0] = (size >> 24) & 0xff;
278 buf[1] = (size >> 16) & 0xff;
279 buf[2] = (size >> 8) & 0xff;
280 buf[3] = (size >> 0) & 0xff;
282 n = send (fd, buf, 4, 0);
283 if (n != 4) {
284 if (!n) errx (1, "EOF while writing length");
285 sockerr (1, "send " FMT_ss, n);
288 n = send (fd, p, size, 0);
289 if (n - size) {
290 if (!n) errx (1, "EOF while writing data");
291 sockerr (1, "send (req %d, ret " FMT_ss ")", size, n);
295 static void
296 #ifdef __GNUC__
297 __attribute__ ((format (printf, 2, 3)))
298 #endif
299 printd (int fd, const char *fmt, ...)
301 int len;
302 va_list ap;
303 char buf[200];
305 va_start (ap, fmt);
306 len = vsnprintf (buf, sizeof (buf), fmt, ap);
307 va_end (ap);
308 writedata (fd, buf, len);
311 static void die (fz_error error)
313 fz_catch (error, "aborting");
314 if (state.xref)
315 pdf_freexref (state.xref);
316 exit (1);
319 static void openxref (char *filename)
321 int fd;
322 fz_error error;
323 fz_stream *file;
325 state.pig = NULL;
326 if (state.xref) {
327 pdf_freexref (state.xref);
328 state.xref = NULL;
330 if (state.pagedims) {
331 free (state.pagedims);
332 state.pagedims = NULL;
334 state.pagedimcount = 0;
336 fd = open (filename, O_BINARY | O_RDONLY, 0666);
337 if (fd < 0)
338 die (fz_throw ("cannot open file '%s'", filename));
340 file = fz_openfile (fd);
341 error = pdf_openxrefwithstream (&state.xref, file, NULL);
342 if (error)
343 die (fz_rethrow(error, "cannot open document '%s'", filename));
344 fz_close (file);
346 if (pdf_needspassword (state.xref)) {
347 die (fz_throw ("password protected"));
350 error = pdf_loadpagetree (state.xref);
351 if (error) {
352 die (fz_throw ("cannot load page tree"));
355 state.pagecount = pdf_getpagecount (state.xref);
358 static int readlen (int fd)
360 ssize_t n;
361 char p[4];
363 n = recv (fd, p, 4, 0);
364 if (n != 4) {
365 if (!n) errx (1, "EOF while reading length");
366 sockerr (1, "recv " FMT_ss, n);
369 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
372 static void unlinkpage (struct page *page)
374 int i;
376 for (i = 0; i < page->slicecount; ++i) {
377 struct slice *s = &page->slices[i];
378 if (s->texindex != -1) {
379 if (state.texowners[s->texindex].slice == s) {
380 state.texowners[s->texindex].slice = NULL;
381 ARSERT (state.texowners[s->texindex].w == s->w);
382 ARSERT (state.texowners[s->texindex].h >= s->h);
388 static void freepage (struct page *page)
390 fz_droppixmap (page->pixmap);
392 unlinkpage (page);
394 if (page->text) {
395 fz_freetextspan (page->text);
397 if (page->drawpage) {
398 pdf_freepage (page->drawpage);
401 free (page);
404 static void subdivide (struct page *p)
406 int i;
407 int h = p->pixmap->h;
408 int th = MIN (h, state.sliceheight);
410 for (i = 0; i < p->slicecount; ++i) {
411 struct slice *s = &p->slices[i];
412 s->texindex = -1;
413 s->h = MIN (th, h);
414 s->w = p->pixmap->w;
415 h -= th;
419 static int compatpdims (struct pagedim *p1, struct pagedim *p2)
421 return p1->rotate == p2->rotate
422 && !memcmp (&p1->bbox, &p2->bbox, sizeof (p1->bbox))
423 && !memcmp (&p1->ctm, &p2->ctm, sizeof (p1->ctm));
426 #ifdef __ALTIVEC__
427 #include <altivec.h>
429 static int cacheline32bytes;
431 static void __attribute__ ((constructor)) clcheck (void)
433 char **envp = environ;
434 unsigned long *auxv;
436 while (*envp++);
438 for (auxv = (unsigned long *) envp; *auxv != 0; auxv += 2) {
439 if (*auxv == 19) {
440 cacheline32bytes = auxv[1] == 32;
441 return;
446 static void __attribute__ ((optimize ("O"))) clearpixmap (fz_pixmap *pixmap)
448 if (cacheline32bytes) {
449 intptr_t a1, a2, diff;
450 size_t sizea, i, size = pixmap->w * pixmap->h * pixmap->n;
451 vector unsigned char v = vec_splat_u8 (-1);
452 vector unsigned char *p;
454 a1 = a2 = (intptr_t) pixmap->samples;
455 a2 = (a1 + 31) & ~31;
456 diff = a2 - a1;
457 sizea = size - diff;
458 p = (void *) a2;
460 while (a1 != a2) *(char *) a1++ = 0xff;
461 for (i = 0; i < (sizea & ~31); i += 32) {
462 __asm volatile ("dcbz %0, %1"::"b"(a2),"r"(i));
463 vec_st (v, i, p);
464 vec_st (v, i + 16, p);
466 while (i < sizea) *((char *) a1 + i++) = 0xff;
468 else fz_clearpixmapwithcolor (pixmap, 0xff);
470 #else
471 #define clearpixmap(p) fz_clearpixmapwithcolor (p, 0xff)
472 #endif
474 static void *render (int pageno, int pindex)
476 fz_error error;
477 int slicecount;
478 fz_obj *pageobj;
479 struct page *page = NULL;
480 double start, end;
481 pdf_page *drawpage;
482 fz_device *idev;
483 struct pagedim *pagedim;
485 start = now ();
486 printd (state.sock, "V rendering %d", pageno);
488 pagedim = &state.pagedims[pindex];
489 slicecount = (pagedim->bbox.y1 - pagedim->bbox.y0
490 + state.sliceheight - 1) / state.sliceheight;
491 slicecount += slicecount == 0;
493 if (state.pig) {
494 if (compatpdims (&state.pig->pagedim, pagedim)) {
495 page = state.pig;
496 if (page->text) {
497 fz_freetextspan (page->text);
498 page->text = NULL;
500 if (page->drawpage) {
501 pdf_freepage (page->drawpage);
502 page->drawpage = NULL;
505 else {
506 freepage (state.pig);
509 if (!page) {
510 page = calloc (sizeof (*page)
511 + (slicecount * sizeof (struct slice)), 1);
512 if (!page) {
513 err (1, "calloc page %d\n", pageno);
515 page->pixmap = fz_newpixmapwithrect (fz_devicergb, pagedim->bbox);
518 page->slicecount = slicecount;
520 pageobj = pdf_getpageobject (state.xref, pageno);
521 if (!pageobj)
522 die (fz_throw ("cannot retrieve info from page %d", pageno));
524 error = pdf_loadpage (&drawpage, state.xref, pageobj);
525 if (error)
526 die (error);
528 clearpixmap (page->pixmap);
530 idev = fz_newdrawdevice (state.cache, page->pixmap);
531 if (!idev)
532 die (fz_throw ("fz_newdrawdevice failed"));
533 error = pdf_runpage (state.xref, drawpage, idev, pagedim->ctm);
534 if (error)
535 die (fz_rethrow (error, "pdf_runpage failed"));
536 fz_freedevice (idev);
538 page->drawpage = drawpage;
539 page->pagedim = *pagedim;
540 page->pageno = pageno;
541 subdivide (page);
542 end = now ();
544 pdf_agestore(state.xref->store, 3);
546 printd (state.sock, "V rendering %d took %f sec", pageno, end - start);
547 state.pig = NULL;
548 return page;
551 static void initpdims (void)
553 int pageno;
554 double start, end;
556 start = now ();
557 for (pageno = 0; pageno < state.pagecount; ++pageno) {
558 int rotate;
559 fz_rect box;
560 struct pagedim *p;
561 fz_obj *obj, *pageobj;
563 pageobj = pdf_getpageobject (state.xref, pageno + 1);
565 obj = fz_dictgets (pageobj, "CropBox");
566 if (!fz_isarray (obj)) {
567 obj = fz_dictgets (pageobj, "MediaBox");
568 if (!fz_isarray (obj)) {
569 die (fz_throw ("cannot find page bounds %d (%d Rd)",
570 fz_tonum (pageobj), fz_togen (pageobj)));
573 box = pdf_torect (obj);
575 obj = fz_dictgets (pageobj, "Rotate");
576 if (fz_isint (obj)) {
577 rotate = fz_toint (obj);
579 else {
580 rotate = 0;
582 rotate += state.rotate;
584 p = &state.pagedims[state.pagedimcount - 1];
585 if ((state.pagedimcount == 0)
586 || (p->rotate != rotate || memcmp (&p->box, &box, sizeof (box)))) {
587 size_t size;
589 size = (state.pagedimcount + 1) * sizeof (*state.pagedims);
590 state.pagedims = realloc (state.pagedims, size);
591 if (!state.pagedims) {
592 err (1, "realloc pagedims to " FMT_s " (%d elems)",
593 size, state.pagedimcount + 1);
595 p = &state.pagedims[state.pagedimcount++];
596 p->rotate = rotate;
597 p->box = box;
598 p->pageno = pageno;
601 end = now ();
602 printd (state.sock, "T Processed %d pages in %f seconds",
603 state.pagecount, end - start);
606 static void layout (void)
608 int pindex;
609 fz_matrix ctm;
610 fz_rect box, box2;
611 double zoom, w;
612 struct pagedim *p = state.pagedims;
614 pindex = 0;
615 for (pindex = 0; pindex < state.pagedimcount; ++pindex, ++p) {
616 box.x0 = MIN (p->box.x0, p->box.x1);
617 box.y0 = MIN (p->box.y0, p->box.y1);
618 box.x1 = MAX (p->box.x0, p->box.x1);
619 box.y1 = MAX (p->box.y0, p->box.y1);
621 ctm = fz_identity;
622 ctm = fz_concat (ctm, fz_translate (0, -box.y1));
623 ctm = fz_concat (ctm, fz_rotate (p->rotate));
624 box2 = fz_transformrect (ctm, box);
625 w = box2.x1 - box2.x0;
627 zoom = (state.w / w);
628 ctm = fz_identity;
629 ctm = fz_concat (ctm, fz_translate (0, -box.y1));
630 ctm = fz_concat (ctm, fz_scale (zoom, -zoom));
631 memcpy (&p->ctm1, &ctm, sizeof (ctm));
632 ctm = fz_concat (ctm, fz_rotate (p->rotate));
633 p->bbox = fz_roundrect (fz_transformrect (ctm, box));
634 memcpy (&p->ctm, &ctm, sizeof (ctm));
637 while (p-- != state.pagedims) {
638 printd (state.sock, "l %d %d %d",
639 p->pageno, p->bbox.x1 - p->bbox.x0, p->bbox.y1 - p->bbox.y0);
643 static void recurse_outline (pdf_outline *outline, int level)
645 while (outline) {
646 int i;
647 fz_obj *obj;
648 int pageno = -1;
649 int top = 0, h = 0;
651 if (!outline->link) goto next;
653 obj = outline->link->dest;
654 if (fz_isindirect (obj)) {
655 obj = fz_resolveindirect (obj);
657 if (fz_isarray (obj)) {
658 fz_obj *obj2;
660 obj2 = fz_arrayget (obj, 0);
661 if (fz_isint (obj2)) {
662 pageno = fz_toint (obj2);
664 else {
665 pageno = pdf_findpageobject (state.xref, obj2) - 1;
668 if (fz_arraylen (obj) > 3) {
669 fz_point p;
670 fz_obj *xo, *yo;
672 xo = fz_arrayget (obj, 2);
673 yo = fz_arrayget (obj, 3);
674 if (!fz_isnull (xo) && !fz_isnull (yo)) {
675 struct pagedim *pagedim = state.pagedims;
677 for (i = 0; i < state.pagedimcount; ++i) {
678 if (state.pagedims[i].pageno > pageno)
679 break;
680 pagedim = &state.pagedims[i];
682 p.x = fz_toint (xo);
683 p.y = fz_toint (yo);
684 p = fz_transformpoint (pagedim->ctm, p);
685 h = pagedim->bbox.y1 - pagedim->bbox.y0;
686 top = p.y;
690 else {
691 pageno = pdf_findpageobject (state.xref, outline->link->dest) - 1;
694 lprintf ("%*c%s %d\n", level, ' ', outline->title, pageno);
695 printd (state.sock, "o %d %d %d %d %s",
696 level, pageno, top, h, outline->title);
697 next:
698 if (outline->child) {
699 recurse_outline (outline->child, level + 1);
701 outline = outline->next;
705 static void process_outline (void)
707 pdf_outline *outline;
709 if (!state.needoutline) return;
711 state.needoutline = 0;
712 outline = pdf_loadoutline (state.xref);
713 if (outline) {
714 recurse_outline (outline, 0);
715 pdf_freeoutline (outline);
719 static int comparespans (const void *l, const void *r)
721 fz_textspan const *const*ls = l;
722 fz_textspan const *const*rs = r;
723 return (*ls)->text->bbox.y0 - (*rs)->text->bbox.y0;
726 /* wishful thinking function */
727 static void search (regex_t *re, int pageno, int y, int forward)
729 int i, j;
730 int ret;
731 char *p;
732 char buf[256];
733 fz_matrix ctm;
734 fz_error error;
735 fz_obj *pageobj;
736 fz_device *tdev;
737 pdf_page *drawpage;
738 fz_textspan *text, *span, **pspan;
739 struct pagedim *pdim, *pdimprev;
740 int stop = 0;
741 int niters = 0;
742 int nspans;
743 double start, end;
745 start = now ();
746 while (pageno >= 0 && pageno < state.pagecount && !stop) {
747 if (niters++ == 5) {
748 pdf_agestore(state.xref->store, 3);
749 niters = 0;
750 if (hasdata (state.sock)) {
751 printd (state.sock, "T attention requested aborting search at %d",
752 pageno);
753 stop = 1;
755 else {
756 printd (state.sock, "T searching in page %d", pageno);
759 pdimprev = NULL;
760 for (i = 0; i < state.pagedimcount; ++i) {
761 pdim = &state.pagedims[i];
762 if (pdim->pageno == pageno) {
763 goto found;
765 if (pdim->pageno > pageno) {
766 pdim = pdimprev;
767 goto found;
769 pdimprev = pdim;
771 pdim = pdimprev;
772 found:
774 pageobj = pdf_getpageobject (state.xref, pageno + 1);
775 if (!pageobj)
776 die (fz_throw ("cannot retrieve info from page %d", pageno));
778 error = pdf_loadpage (&drawpage, state.xref, pageobj);
779 if (error)
780 die (error);
782 ctm = fz_rotate (pdim->rotate);
784 text = fz_newtextspan ();
785 tdev = fz_newtextdevice (text);
786 error = pdf_runpage (state.xref, drawpage, tdev, pdim->ctm1);
787 if (error) die (error);
788 fz_freedevice (tdev);
790 nspans = 0;
791 for (span = text; span; span = span->next) {
792 nspans++;
794 pspan = malloc (sizeof (void *) * nspans);
795 if (!pspan) {
796 err (1, "malloc span pointers " FMT_s, sizeof (void *) * nspans);
798 for (i = 0, span = text; span; span = span->next, ++i) {
799 pspan[i] = span;
801 qsort (pspan, nspans, sizeof (fz_textspan *), comparespans);
803 j = forward ? 0 : nspans - 1;
804 while (nspans--) {
805 regmatch_t rm;
807 span = pspan[j];
808 j += forward ? 1 : -1;
809 p = buf;
810 for (i = 0; i < MIN (span->len, (int) sizeof (buf) - 1); ++i) {
811 if (forward) {
812 if (span->text[i].bbox.y0 < y + 1) {
813 continue;
816 else {
817 if (span->text[i].bbox.y0 > y - 1) {
818 continue;
821 if (span->text[i].c < 256) {
822 *p++ = span->text[i].c;
824 else {
825 *p++ = '?';
828 if (p == buf) {
829 continue;
831 *p++ = 0;
833 ret = regexec (re, buf, 1, &rm, 0);
834 if (ret) {
835 if (ret != REG_NOMATCH) {
836 size_t size;
837 char errbuf[80];
838 size = regerror (ret, re, errbuf, sizeof (errbuf));
839 printd (state.sock,
840 "T regexec error `%.*s'",
841 (int) size, errbuf);
842 fz_freetextspan (text);
843 pdf_freepage (drawpage);
844 free (pspan);
845 return;
848 else {
849 int xoff, yoff;
850 fz_bbox *sb, *eb;
851 fz_point p1, p2, p3, p4;
853 xoff = -pdim->bbox.x0;
854 yoff = -pdim->bbox.y0;
856 sb = &span->text[rm.rm_so].bbox;
857 eb = &span->text[rm.rm_eo - 1].bbox;
859 p1.x = sb->x0;
860 p1.y = sb->y0;
861 p2.x = eb->x1;
862 p2.y = sb->y0;
863 p3.x = eb->x1;
864 p3.y = eb->y1;
865 p4.x = sb->x0;
866 p4.y = eb->y1;
868 p1 = fz_transformpoint (ctm, p1);
869 p2 = fz_transformpoint (ctm, p2);
870 p3 = fz_transformpoint (ctm, p3);
871 p4 = fz_transformpoint (ctm, p4);
873 if (!stop) {
874 printd (state.sock, "F %d %d %f %f %f %f %f %f %f %f",
875 pageno, 1,
876 p1.x + xoff, p1.y + yoff,
877 p2.x + xoff, p2.y + yoff,
878 p3.x + xoff, p3.y + yoff,
879 p4.x + xoff, p4.y + yoff);
881 printd (state.sock, "T found at %d `%.*s' in %f sec",
882 pageno, rm.rm_eo - rm.rm_so, &buf[rm.rm_so],
883 now () - start);
885 else {
886 printd (state.sock, "R %d %d %f %f %f %f %f %f %f %f",
887 pageno, 2,
888 p1.x + xoff, p1.y + yoff,
889 p2.x + xoff, p2.y + yoff,
890 p3.x + xoff, p3.y + yoff,
891 p4.x + xoff, p4.y + yoff);
893 stop = 1;
896 if (forward) {
897 pageno += 1;
898 y = 0;
900 else {
901 pageno -= 1;
902 y = INT_MAX;
904 fz_freetextspan (text);
905 pdf_freepage (drawpage);
906 free (pspan);
908 end = now ();
909 if (!stop) {
910 printd (state.sock, "T no matches %f sec", end - start);
912 printd (state.sock, "D");
915 static
916 #ifdef _WIN32
917 DWORD _stdcall
918 #else
919 void *
920 #endif
921 mainloop (void *unused)
923 char *p = NULL;
924 int len, ret, oldlen = 0;
926 for (;;) {
927 len = readlen (state.sock);
928 if (len == 0) {
929 errx (1, "readlen returned 0");
932 if (oldlen < len + 1) {
933 p = realloc (p, len + 1);
934 if (!p) {
935 err (1, "realloc %d failed", len + 1);
937 oldlen = len + 1;
939 readdata (state.sock, p, len);
940 p[len] = 0;
942 if (!strncmp ("open", p, 4)) {
943 fz_obj *obj;
944 char *filename = p + 5;
946 openxref (filename);
947 initpdims ();
949 obj = fz_dictgets (state.xref->trailer, "Info");
950 if (obj) {
951 char *s;
953 obj = fz_dictgets (obj, "Title");
954 s = pdf_toutf8 (obj);
955 if (*s) {
956 printd (state.sock, "t %s", s);
958 fz_free (s);
960 state.needoutline = 1;
962 else if (!strncmp ("free", p, 4)) {
963 void *ptr;
965 ret = sscanf (p + 4, " %p", &ptr);
966 if (ret != 1) {
967 errx (1, "malformed free `%.*s' ret=%d", len, p, ret);
969 unlinkpage (ptr);
970 state.pig = ptr;
972 else if (!strncmp ("search", p, 6)) {
973 int icase, pageno, y, ret, len2, forward;
974 char *pattern;
975 regex_t re;
977 ret = sscanf (p + 6, " %d %d %d %d,%n",
978 &icase, &pageno, &y, &forward, &len2);
979 if (ret != 4) {
980 errx (1, "malformed search `%s' ret=%d", p, ret);
983 pattern = p + 6 + len2;
984 ret = regcomp (&re, pattern,
985 REG_EXTENDED | (icase ? REG_ICASE : 0));
986 if (ret) {
987 char errbuf[80];
988 size_t size;
990 size = regerror (ret, &re, errbuf, sizeof (errbuf));
991 printd (state.sock, "T regcomp failed `%.*s'",
992 (int) size, errbuf);
994 else {
995 search (&re, pageno, y, forward);
996 regfree (&re);
999 else if (!strncmp ("geometry", p, 8)) {
1000 int w, h;
1002 printd (state.sock, "c");
1003 ret = sscanf (p + 8, " %d %d", &w, &h);
1004 if (ret != 2) {
1005 errx (1, "malformed geometry `%.*s' ret=%d", len, p, ret);
1008 lock ("geometry");
1009 state.h = h;
1010 if (w != state.w) {
1011 int i;
1012 state.w = w;
1013 for (i = 0; i < state.texcount; ++i) {
1014 state.texowners[i].slice = NULL;
1017 layout ();
1018 process_outline ();
1019 unlock ("geometry");
1020 printd (state.sock, "C %d", state.pagecount);
1022 else if (!strncmp ("rotate", p, 6)) {
1023 float rotate;
1025 printd (state.sock, "c");
1026 ret = sscanf (p + 6, " %f", &rotate);
1027 if (ret != 1) {
1028 errx (1, "bad rotate line `%.*s' ret=%d", len, p, ret);
1030 lock ("rotate");
1031 state.rotate = rotate;
1032 state.pagedimcount = 0;
1033 free (state.pagedims);
1034 state.pagedims = NULL;
1035 initpdims ();
1036 layout ();
1037 process_outline ();
1038 if (state.pig) {
1039 freepage (state.pig);
1040 state.pig = NULL;
1042 unlock ("rotate");
1043 printd (state.sock, "C %d", state.pagecount);
1045 else if (!strncmp ("render", p, 6)) {
1046 int pageno, pindex, w, h, ret;
1047 struct page *page;
1049 ret = sscanf (p + 6, " %d %d %d %d", &pageno, &pindex, &w, &h);
1050 if (ret != 4) {
1051 errx (1, "bad render line `%.*s' ret=%d", len, p, ret);
1054 lock ("render");
1055 page = render (pageno, pindex);
1056 unlock ("render");
1058 printd (state.sock, "r %d %d %d %d %p",
1059 pageno,
1060 state.w,
1061 state.h,
1062 state.rotate,
1063 page);
1065 else if (!strncmp ("interrupt", p, 9)) {
1066 printd (state.sock, "V interrupted");
1068 else {
1069 errx (1, "unknown command %.*s", len, p);
1072 return 0;
1075 static void showsel (struct page *page, int oy)
1077 int ox;
1078 fz_bbox bbox;
1079 fz_textspan *span;
1080 struct mark first, last;
1082 first = page->fmark;
1083 last = page->lmark;
1085 if (!first.span || !last.span) return;
1087 glEnable (GL_BLEND);
1088 glBlendFunc (GL_SRC_ALPHA, GL_SRC_ALPHA);
1089 glColor4f (0.5f, 0.5f, 0.0f, 0.6f);
1091 ox = -page->pixmap->x;
1092 oy = -page->pixmap->y + oy;
1093 for (span = first.span; span; span = span->next) {
1094 int i, j, k;
1096 bbox.x0 = bbox.y0 = bbox.x1 = bbox.y1 = 0;
1098 j = 0;
1099 k = span->len - 1;
1101 if (span == page->fmark.span && span == page->lmark.span) {
1102 j = MIN (first.i, last.i);
1103 k = MAX (first.i, last.i);
1105 else if (span == first.span) {
1106 j = first.i;
1108 else if (span == last.span) {
1109 k = last.i;
1112 for (i = j; i <= k; ++i) {
1113 bbox = fz_unionbbox (bbox, span->text[i].bbox);
1115 lprintf ("%d %d %d %d oy=%d ox=%d\n",
1116 bbox.x0,
1117 bbox.y0,
1118 bbox.x1,
1119 bbox.y1,
1120 oy, ox);
1122 glRecti (bbox.x0 + ox, bbox.y0 + oy, bbox.x1 + ox, bbox.y1 + oy);
1124 if (span == last.span) break;
1126 glDisable (GL_BLEND);
1129 static void highlightlinks (struct page *page, int yoff)
1131 pdf_link *link;
1132 int xoff;
1134 glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
1135 glEnable (GL_LINE_STIPPLE);
1136 glLineStipple (0.5, 0xcccc);
1138 xoff = -page->pixmap->x;
1139 yoff -= page->pixmap->y;
1141 glBegin (GL_QUADS);
1142 for (link = page->drawpage->links; link; link = link->next) {
1143 fz_point p1, p2, p3, p4;
1144 fz_matrix ctm = page->pagedim.ctm;
1146 p1.x = link->rect.x0;
1147 p1.y = link->rect.y0;
1149 p2.x = link->rect.x1;
1150 p2.y = link->rect.y0;
1152 p3.x = link->rect.x1;
1153 p3.y = link->rect.y1;
1155 p4.x = link->rect.x0;
1156 p4.y = link->rect.y1;
1158 p1 = fz_transformpoint (ctm, p1);
1159 p2 = fz_transformpoint (ctm, p2);
1160 p3 = fz_transformpoint (ctm, p3);
1161 p4 = fz_transformpoint (ctm, p4);
1163 switch (link->kind) {
1164 case PDF_LGOTO: glColor3ub (255, 0, 0); break;
1165 case PDF_LURI: glColor3ub (0, 0, 255); break;
1166 default: glColor3ub (0, 0, 0); break;
1169 glVertex2f (p1.x + xoff, p1.y + yoff);
1170 glVertex2f (p2.x + xoff, p2.y + yoff);
1171 glVertex2f (p3.x + xoff, p3.y + yoff);
1172 glVertex2f (p4.x + xoff, p4.y + yoff);
1174 glEnd ();
1176 glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
1177 glDisable (GL_LINE_STIPPLE);
1180 static void upload2 (struct page *page, int slicenum, const char *cap)
1182 int i;
1183 int w, h;
1184 double start, end;
1185 struct slice *slice = &page->slices[slicenum];
1187 w = page->pixmap->w;
1188 h = page->pixmap->h;
1190 ARSERT (w == slice->w);
1191 if (slice->texindex != -1
1192 && state.texowners[slice->texindex].slice == slice) {
1193 glBindTexture (GL_TEXTURE_RECTANGLE_ARB, state.texids[slice->texindex]);
1195 else {
1196 int subimage = 0;
1197 int index = (state.texindex++ % state.texcount);
1198 size_t offset = 0;
1200 for (i = 0; i < slicenum; ++i) {
1201 offset += w * page->slices[i].h * 4;
1204 if (state.texowners[index].w == slice->w) {
1205 if (state.texowners[index].h >= slice->h ) {
1206 subimage = 1;
1208 else {
1209 state.texowners[index].h = slice->h;
1212 else {
1213 state.texowners[index].h = slice->h;
1216 state.texowners[index].slice = slice;
1217 state.texowners[index].w = slice->w;
1218 slice->texindex = index;
1220 glBindTexture (GL_TEXTURE_RECTANGLE_ARB, state.texids[slice->texindex]);
1221 start = now ();
1222 if (subimage) {
1224 GLenum err = glGetError ();
1225 if (err != GL_NO_ERROR) {
1226 printf ("\033[0;31mERROR1 %d %d %#x\033[0m\n", w, slice->h, err);
1227 abort ();
1230 glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB,
1235 slice->h,
1236 state.texform,
1237 state.texty,
1238 page->pixmap->samples + offset
1241 GLenum err = glGetError ();
1242 if (err != GL_NO_ERROR) {
1243 printf ("\033[0;31mERROR %d %d %#x\033[0m\n", w, slice->h, err);
1244 abort ();
1248 else {
1249 glTexImage2D (GL_TEXTURE_RECTANGLE_ARB,
1251 GL_RGBA8,
1253 slice->h,
1255 state.texform,
1256 state.texty,
1257 page->pixmap->samples + offset
1261 end = now ();
1262 lprintf ("%s[%d] slice=%d(%d,%d) texid=%d %f sec\n",
1263 subimage ? "sub" : "img",
1264 page->pageno, slicenum,
1265 slice->w, slice->h,
1266 state.texids[slice->texindex],
1267 end - start);
1271 CAMLprim value ml_draw (value args_v, value ptr_v)
1273 CAMLparam2 (args_v, ptr_v);
1274 int dispy = Int_val (Field (args_v, 0));
1275 int w = Int_val (Field (args_v, 1));
1276 int h = Int_val (Field (args_v, 2));
1277 int py = Int_val (Field (args_v, 3));
1278 int hlinks = Bool_val (Field (args_v, 4));
1279 char *s = String_val (ptr_v);
1280 int ret;
1281 void *ptr;
1282 struct page *page;
1283 int slicenum = 0;
1284 int yoff = dispy - py;
1286 ret = sscanf (s, "%p", &ptr);
1287 if (ret != 1) {
1288 errx (1, "cannot parse pointer `%s'", s);
1290 page = ptr;
1292 w = page->pixmap->w;
1294 ARSERT (h >= 0 && "ml_draw wrong h");
1295 ARSERT (py <= page->pixmap->h && "ml_draw wrong py");
1297 glEnable (GL_TEXTURE_RECTANGLE_ARB);
1299 for (slicenum = 0; slicenum < page->slicecount; ++slicenum) {
1300 struct slice *slice = &page->slices[slicenum];
1301 if (slice->h > py) {
1302 break;
1304 py -= slice->h;
1307 h = MIN (state.h, h);
1308 while (h) {
1309 int th;
1310 struct slice *slice = &page->slices[slicenum];
1312 ARSERT (slicenum < page->slicecount && "ml_draw wrong slicenum");
1314 th = MIN (h, slice->h - py);
1315 upload2 (page, slicenum, "upload");
1317 glBegin (GL_QUADS);
1319 glTexCoord2i (0, py);
1320 glVertex2i (0, dispy);
1322 glTexCoord2i (w, py);
1323 glVertex2i (w, dispy);
1325 glTexCoord2i (w, py+th);
1326 glVertex2i (w, dispy + th);
1328 glTexCoord2i (0, py+th);
1329 glVertex2i (0, dispy + th);
1331 glEnd ();
1333 h -= th;
1334 py = 0;
1335 dispy += th;
1336 slicenum += 1;
1339 showsel (page, yoff);
1340 if (hlinks) highlightlinks (page, yoff);
1341 glDisable (GL_TEXTURE_RECTANGLE_ARB);
1343 CAMLreturn (Val_unit);
1346 static pdf_link *getlink (struct page *page, int x, int y)
1348 fz_point p;
1349 fz_matrix ctm;
1350 pdf_link *link;
1352 p.x = x + page->pixmap->x;
1353 p.y = y + page->pixmap->y;
1355 ctm = fz_invertmatrix (page->pagedim.ctm);
1356 p = fz_transformpoint (ctm, p);
1358 for (link = page->drawpage->links; link; link = link->next) {
1359 if (p.x >= link->rect.x0 && p.x <= link->rect.x1) {
1360 if (p.y >= link->rect.y0 && p.y <= link->rect.y1) {
1361 return link;
1365 return NULL;
1368 static void ensuretext (struct page *page)
1370 if (!page->text) {
1371 fz_error error;
1372 fz_device *tdev;
1374 page->text = fz_newtextspan ();
1375 tdev = fz_newtextdevice (page->text);
1376 error = pdf_runpage (state.xref, page->drawpage, tdev,
1377 page->pagedim.ctm);
1378 if (error) die (error);
1379 fz_freedevice (tdev);
1383 CAMLprim value ml_whatsunder (value ptr_v, value x_v, value y_v)
1385 CAMLparam3 (ptr_v, x_v, y_v);
1386 CAMLlocal3 (ret_v, tup_v, str_v);
1387 pdf_link *link;
1388 struct page *page;
1389 char *s = String_val (ptr_v);
1391 ret_v = Val_int (0);
1392 if (trylock ("ml_whatsunder")) {
1393 goto done;
1396 page = parse_pointer ("ml_whatsunder", s);
1397 link = getlink (page, Int_val (x_v), Int_val (y_v));
1398 if (link) {
1399 switch (link->kind) {
1400 case PDF_LGOTO:
1402 int pageno;
1403 fz_point p;
1404 fz_obj *obj;
1406 pageno = -1;
1407 p.x = 0;
1408 p.y = 0;
1410 if (fz_isarray (link->dest)) {
1411 obj = fz_arrayget (link->dest, 0);
1412 if (fz_isindirect (obj)) {
1413 pageno = pdf_findpageobject (state.xref, obj) - 1;
1415 else if (fz_isint (obj)) {
1416 pageno = fz_toint (obj);
1419 if (fz_arraylen (link->dest) > 3) {
1420 fz_obj *xo, *yo;
1422 xo = fz_arrayget (link->dest, 2);
1423 yo = fz_arrayget (link->dest, 3);
1424 if (!fz_isnull (xo) && !fz_isnull (yo)) {
1425 p.x = fz_toint (xo);
1426 p.y = fz_toint (yo);
1427 p = fz_transformpoint (page->pagedim.ctm, p);
1431 else {
1432 pageno = pdf_findpageobject (state.xref, link->dest) - 1;
1434 tup_v = caml_alloc_tuple (2);
1435 ret_v = caml_alloc_small (1, 1);
1436 Field (tup_v, 0) = Val_int (pageno);
1437 Field (tup_v, 1) = Val_int (p.y);
1438 Field (ret_v, 0) = tup_v;
1440 break;
1442 case PDF_LURI:
1443 str_v = caml_copy_string (fz_tostrbuf (link->dest));
1444 ret_v = caml_alloc_small (1, 0);
1445 Field (ret_v, 0) = str_v;
1446 break;
1448 default:
1449 printd (state.sock, "T unhandled link kind %d", link->kind);
1450 break;
1453 else {
1454 int i, x, y;
1455 fz_textspan *span;
1457 ensuretext (page);
1458 x = Int_val (x_v) + page->pixmap->x;
1459 y = Int_val (y_v) + page->pixmap->y;
1461 for (span = page->text; span; span = span->next) {
1462 for (i = 0; i < span->len; ++i) {
1463 fz_bbox *b;
1464 b = &span->text[i].bbox;
1465 if ((x >= b->x0 && x <= b->x1 && y >= b->y0 && y <= b->y1)) {
1466 const char *n2 =
1467 span->font && span->font->name
1468 ? span->font->name
1469 : "Span has no font name"
1471 #ifdef FT_FREETYPE_H
1472 FT_FaceRec *face = span->font->ftface;
1473 if (face && face->family_name) {
1474 char *s;
1475 char *n1 = face->family_name;
1476 size_t l1 = strlen (n1);
1477 size_t l2 = strlen (n2);
1479 if (l1 != l2 || memcmp (n1, n2, l1)) {
1480 s = malloc (l1 + l2 + 2);
1481 if (s) {
1482 memcpy (s, n2, l2);
1483 s[l2] = '=';
1484 memcpy (s + l2 + 1, n1, l1 + 1);
1485 str_v = caml_copy_string (s);
1486 free (s);
1490 if (str_v == 0) {
1491 str_v = caml_copy_string (n2);
1493 #else
1494 str_v = caml_copy_string (n2);
1495 #endif
1496 ret_v = caml_alloc_small (1, 2);
1497 Field (ret_v, 0) = str_v;
1498 goto unlock;
1503 unlock:
1504 unlock ("ml_whatsunder");
1506 done:
1507 CAMLreturn (ret_v);
1510 CAMLprim value ml_seltext (value ptr_v, value rect_v, value oy_v)
1512 CAMLparam4 (ptr_v, rect_v, oy_v, rect_v);
1513 fz_bbox *b;
1514 struct page *page;
1515 fz_textspan *span;
1516 struct mark first, last;
1517 int i, x0, x1, y0, y1, oy;
1518 char *s = String_val (ptr_v);
1520 if (trylock ("ml_seltext")) {
1521 goto done;
1524 page = parse_pointer ("ml_seltext", s);
1525 ensuretext (page);
1527 oy = Int_val (oy_v);
1528 x0 = Int_val (Field (rect_v, 0));
1529 y0 = Int_val (Field (rect_v, 1));
1530 x1 = Int_val (Field (rect_v, 2));
1531 y1 = Int_val (Field (rect_v, 3));
1533 if (0) {
1534 glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
1535 glColor3ub (128, 128, 128);
1536 glRecti (x0, y0, x1, y1);
1537 glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
1540 x0 += page->pixmap->x;
1541 y0 += page->pixmap->y - oy;
1542 x1 += page->pixmap->x;
1543 y1 += page->pixmap->y - oy;
1545 first.span = NULL;
1546 last.span = NULL;
1548 last.i = first.i = 0;
1549 first.span = page->text;
1550 for (span = page->text; span; span = span->next) {
1551 for (i = 0; i < span->len; ++i) {
1552 b = &span->text[i].bbox;
1553 if (x0 >= b->x0 && x0 <= b->x1 && y0 >= b->y0 && y0 <= b->y1) {
1554 first.i = i;
1555 first.span = span;
1557 if (x1 >= b->x0 && x1 <= b->x1 && y1 >= b->y0 && y1 <= b->y1) {
1558 last.i = i;
1559 last.span = span;
1564 if (y1 < y0 || x1 < x0) {
1565 int swap = 0;
1567 if (first.span == last.span) {
1568 swap = 1;
1570 else {
1571 if (y1 < y0) {
1572 for (span = first.span; span && span != last.span;
1573 span = span->next) {
1574 if (span->eol) {
1575 swap = 1;
1576 break;
1582 if (swap) {
1583 i = first.i;
1584 span = first.span;
1585 first.i = last.i;
1586 first.span = last.span;
1587 last.i = i;
1588 last.span = span;
1592 page->fmark = first;
1593 page->lmark = last;
1595 unlock ("ml_seltext");
1597 done:
1598 CAMLreturn (Val_unit);
1601 static int pipespan (FILE *f, fz_textspan *span, int a, int b)
1603 char buf[4];
1604 int i, len, ret;
1606 for (i = a; i <= b; ++i) {
1607 len = runetochar (buf, &span->text[i].c);
1608 ret = fwrite (buf, len, 1, f);
1610 if (ret != 1) {
1611 printd (state.sock, "T failed to write %d bytes ret=%d: %s",
1612 len, ret, strerror (errno));
1613 return -1;
1616 return 0;
1619 CAMLprim value ml_copysel (value ptr_v)
1621 CAMLparam1 (ptr_v);
1622 FILE *f;
1623 struct page *page;
1624 char *s = String_val (ptr_v);
1626 if (trylock ("ml_copysel")) {
1627 goto done;
1630 if (!*s) {
1631 close:
1632 #ifdef USE_XSEL
1633 if (state.xselpipe) {
1634 int ret = pclose (state.xselpipe);
1635 if (ret) {
1636 printd (state.sock, "T failed to close xsel pipe `%s'",
1637 strerror (errno));
1639 state.xselpipe = NULL;
1641 #else
1642 printf ("========================================\n");
1643 #endif
1645 else {
1646 fz_textspan *span;
1648 page = parse_pointer ("ml_sopysel", s);
1650 if (!page->fmark.span || !page->lmark.span) {
1651 printd (state.sock, "T nothing to copy");
1652 goto unlock;
1655 f = stdout;
1656 #ifdef USE_XSEL
1657 if (!state.xselpipe) {
1658 state.xselpipe = popen ("xsel -i", "w");
1659 if (!state.xselpipe) {
1660 printd (state.sock, "T failed to open xsel pipe `%s'",
1661 strerror (errno));
1663 else {
1664 f = state.xselpipe;
1667 else {
1668 f = state.xselpipe;
1670 #endif
1672 for (span = page->fmark.span;
1673 span && span != page->lmark.span->next;
1674 span = span->next) {
1675 int a = span == page->fmark.span ? page->fmark.i : 0;
1676 int b = span == page->lmark.span ? page->lmark.i : span->len - 1;
1677 if (pipespan (f, span, a, b)) {
1678 goto close;
1680 if (span->eol) {
1681 if (putc ('\n', f) == EOF) {
1682 printd (state.sock, "T failed break line on xsel pipe `%s'",
1683 strerror (errno));
1684 goto close;
1688 page->lmark.span = NULL;
1689 page->fmark.span = NULL;
1692 unlock:
1693 unlock ("ml_copysel");
1695 done:
1696 CAMLreturn (Val_unit);
1699 CAMLprim value ml_getpagewh (value pagedimno_v)
1701 CAMLparam1 (pagedimno_v);
1702 CAMLlocal1 (ret_v);
1703 int pagedimno = Int_val (pagedimno_v);
1705 ret_v = caml_alloc_small (4 * Double_wosize, Double_array_tag);
1706 Store_double_field (ret_v, 0, state.pagedims[pagedimno].box.x0);
1707 Store_double_field (ret_v, 1, state.pagedims[pagedimno].box.x1);
1708 Store_double_field (ret_v, 2, state.pagedims[pagedimno].box.y0);
1709 Store_double_field (ret_v, 3, state.pagedims[pagedimno].box.y1);
1710 CAMLreturn (ret_v);
1713 CAMLprim value ml_init (value sock_v)
1715 #ifndef _WIN32
1716 int ret;
1717 #endif
1718 CAMLparam1 (sock_v);
1720 state.texcount = 256;
1721 state.sliceheight = 24;
1722 state.texform = GL_RGBA;
1723 state.texty = GL_UNSIGNED_BYTE;
1725 fz_accelerate ();
1726 state.texids = calloc (state.texcount * sizeof (*state.texids), 1);
1727 if (!state.texids) {
1728 err (1, "calloc texids " FMT_s,
1729 state.texcount * sizeof (*state.texids));
1732 state.texowners = calloc (state.texcount * sizeof (*state.texowners), 1);
1733 if (!state.texowners) {
1734 err (1, "calloc texowners " FMT_s,
1735 state.texcount * sizeof (*state.texowners));
1738 glGenTextures (state.texcount, state.texids);
1740 #ifdef _WIN32
1741 state.sock = Socket_val (sock_v);
1742 #else
1743 state.sock = Int_val (sock_v);
1744 #endif
1746 state.cache = fz_newglyphcache ();
1747 if (!state.cache) {
1748 errx (1, "fz_newglyphcache failed");
1751 #ifdef _WIN32
1752 InitializeCriticalSection (&critsec);
1753 state.thread = CreateThread (NULL, 0, mainloop, NULL, 0, NULL);
1754 if (state.thread == INVALID_HANDLE_VALUE) {
1755 errx (1, "CreateThread failed: %lx", GetLastError ());
1757 #else
1758 ret = pthread_create (&state.thread, NULL, mainloop, NULL);
1759 if (ret) {
1760 errx (1, "pthread_create: %s", strerror (errno));
1762 #endif
1764 CAMLreturn (Val_unit);