View | Details | Raw Unified | Return to bug 224712 | Differences between
and this patch

Collapse All | Expand All

(-)Makefile (-1 / +1 lines)
Lines 3-9 Link Here
3
3
4
PORTNAME=	llpp
4
PORTNAME=	llpp
5
PORTVERSION=	25
5
PORTVERSION=	25
6
PORTREVISION=	3
6
PORTREVISION=	4
7
CATEGORIES=	graphics
7
CATEGORIES=	graphics
8
MASTER_SITES=	http://repo.or.cz/llpp.git/snapshot/
8
MASTER_SITES=	http://repo.or.cz/llpp.git/snapshot/
9
DISTNAME=	v${PORTVERSION}
9
DISTNAME=	v${PORTVERSION}
(-)files/patch-link.c (-9 / +1583 lines)
Lines 1-6 Link Here
1
Fix build with MuPDF 1.12.0
2
3
Based on upstream commit 50a80d2fe92b52c0b50915bc194edf556b10aa49
4
1
--- link.c.orig	2016-11-29 15:11:31 UTC
5
--- link.c.orig	2016-11-29 15:11:31 UTC
2
+++ link.c
6
+++ link.c
3
@@ -511,8 +511,8 @@ static void pdfinfo (void)
7
@@ -8,12 +8,18 @@
8
 #include <string.h>
9
 #include <stdlib.h>
10
 #include <signal.h>
11
+
12
+#include <math.h>
13
 #include <wchar.h>
14
+#include <locale.h>
15
+#include <langinfo.h>
16
 
17
 #include <unistd.h>
18
 #include <pthread.h>
19
 #include <sys/uio.h>
20
 #include <sys/time.h>
21
+#include <sys/stat.h>
22
+#include <fcntl.h>
23
 #include <sys/types.h>
24
 #include <sys/ioctl.h>
25
 #include <sys/utsname.h>
26
@@ -29,7 +35,15 @@
27
 #include <limits.h>
28
 #include <inttypes.h>
29
 
30
+#ifdef __COCOA__
31
+#include <CoreFoundation/CoreFoundation.h>
32
+#endif
33
+
34
+#ifdef __APPLE__
35
+#include <OpenGL/gl.h>
36
+#else
37
 #include <GL/gl.h>
38
+#endif
39
 
40
 #include <caml/fail.h>
41
 #include <caml/alloc.h>
42
@@ -48,10 +62,6 @@
43
 #include <ft2build.h>
44
 #include FT_FREETYPE_H
45
 
46
-#ifdef USE_FONTCONFIG
47
-#include <fontconfig/fontconfig.h>
48
-#endif
49
-
50
 #define PIGGYBACK
51
 #define CACHE_PAGEREFS
52
 
53
@@ -191,16 +201,15 @@ struct page {
54
     int pageno;
55
     int pdimno;
56
     fz_stext_page *text;
57
-    fz_stext_sheet *sheet;
58
     fz_page *fzpage;
59
     fz_display_list *dlist;
60
+    fz_link *links;
61
     int slinkcount;
62
     struct slink *slinks;
63
     int annotcount;
64
     struct annot *annots;
65
     struct mark {
66
-        int i;
67
-        fz_stext_span *span;
68
+        fz_stext_char *ch;
69
     } fmark, lmark;
70
 };
71
 
72
@@ -270,6 +279,7 @@ struct {
73
         pdf_document *pdf;
74
     } pdflut;
75
 #endif
76
+    int utf8cs;
77
 } state;
78
 
79
 struct bo {
80
@@ -396,6 +406,7 @@ static int readlen (int fd)
81
 {
82
     /* Type punned unions here. Why? Less code (Adjusted by more comments).
83
        https://en.wikipedia.org/wiki/Type_punning */
84
+    /* Then again https://bugs.llvm.org/show_bug.cgi?id=31928 - hmm */
85
     union { uint32_t len; char raw[4]; } buf;
86
     readdata (fd, buf.raw, 4);
87
     return buf.len;
88
@@ -511,8 +522,8 @@ static void pdfinfo (void)
4
         { "info:Producer", "Producer" },
89
         { "info:Producer", "Producer" },
5
         { "info:CreationDate", "Creation date" },
90
         { "info:CreationDate", "Creation date" },
6
     };
91
     };
Lines 11-17 Link Here
11
 
96
 
12
     for (size_t i = 0; i < sizeof (metatbl) / sizeof (metatbl[1]); ++i) {
97
     for (size_t i = 0; i < sizeof (metatbl) / sizeof (metatbl[1]); ++i) {
13
         int need;
98
         int need;
14
@@ -524,9 +524,9 @@ static void pdfinfo (void)
99
@@ -524,9 +535,9 @@ static void pdfinfo (void)
15
                 printd ("info %s\t%s", metatbl[i].name, buf);
100
                 printd ("info %s\t%s", metatbl[i].name, buf);
16
             }
101
             }
17
             else {
102
             else {
Lines 19-38 Link Here
19
-                if (!buf) err (1, "realloc %d", need);
104
-                if (!buf) err (1, "realloc %d", need);
20
-                len = need;
105
-                len = need;
21
+                buf = realloc (buf, need + 1);
106
+                buf = realloc (buf, need + 1);
22
+                if (!buf) err (1, "realloc %d", need + 1);
107
+                if (!buf) err (1, "pdfinfo realloc %d", need + 1);
23
+                len = need + 1;
108
+                len = need + 1;
24
                 goto again;
109
                 goto again;
25
             }
110
             }
26
         }
111
         }
27
@@ -1670,7 +1670,6 @@ static void * mainloop (void UNUSED_ATTR
112
@@ -555,9 +566,6 @@ static void freepage (struct page *page)
113
     if (page->text) {
114
         fz_drop_stext_page (state.ctx, page->text);
115
     }
116
-    if (page->sheet) {
117
-        fz_drop_stext_sheet (state.ctx, page->sheet);
118
-    }
119
     if (page->slinks) {
120
         free (page->slinks);
121
     }
122
@@ -772,12 +780,13 @@ static struct tile *rendertile (struct page *page, int
123
         if (pbo) {
124
             tile->pixmap =
125
                 fz_new_pixmap_with_bbox_and_data (state.ctx, state.colorspace,
126
-                                                  &bbox, 1, pbo->ptr);
127
+                                                  &bbox, NULL, 1, pbo->ptr);
128
             tile->pbo = pbo;
129
         }
130
         else {
131
             tile->pixmap =
132
-                fz_new_pixmap_with_bbox (state.ctx, state.colorspace, &bbox, 1);
133
+                fz_new_pixmap_with_bbox (state.ctx, state.colorspace, &bbox,
134
+                                         NULL, 1);
135
         }
136
     }
137
 
138
@@ -817,7 +826,7 @@ pdf_collect_pages(pdf_document *doc, pdf_obj *node)
139
         fz_throw (ctx, FZ_ERROR_GENERIC, "cycle in page tree");
140
     for (int i = 0; i < len; i++) {
141
         pdf_obj *kid = pdf_array_get (ctx, kids, i);
142
-        char *type = pdf_to_name (ctx, pdf_dict_gets (ctx, kid, "Type"));
143
+        const char *type = pdf_to_name (ctx, pdf_dict_gets (ctx, kid, "Type"));
144
         if (*type
145
             ? !strcmp (type, "Pages")
146
             : pdf_dict_gets (ctx, kid, "Kids")
147
@@ -930,7 +939,6 @@ static void initpdims (int wthack)
148
                         fz_matrix ctm, page_ctm;
149
 
150
                         dev = fz_new_bbox_device (ctx, &rect);
151
-                        dev->hints |= FZ_IGNORE_SHADE;
152
                         pdf_page_transform (ctx, page, &mediabox, &page_ctm);
153
                         fz_invert_matrix (&ctm, &page_ctm);
154
                         pdf_run_page (ctx, page, dev, &fz_identity, NULL);
155
@@ -1034,7 +1042,6 @@ static void initpdims (int wthack)
156
                         fz_device *dev;
157
 
158
                         dev = fz_new_bbox_device (ctx, &rect);
159
-                        dev->hints |= FZ_IGNORE_SHADE;
160
                         fz_run_page (ctx, page, dev, &fz_identity, NULL);
161
                         fz_close_device (ctx, dev);
162
                         fz_drop_device (ctx, dev);
163
@@ -1291,7 +1298,7 @@ static void process_outline (void)
164
     }
165
 }
166
 
167
-static char *strofspan (fz_stext_span *span)
168
+static char *strofline (fz_stext_line *line)
169
 {
170
     char *p;
171
     char utf8[10];
172
@@ -1301,7 +1308,7 @@ static char *strofspan (fz_stext_span *span)
173
     p = malloc (cap + 1);
174
     if (!p) return NULL;
175
 
176
-    for (ch = span->text; ch < span->text + span->len; ++ch) {
177
+    for (ch = line->first_char; ch; ch = ch->next) {
178
         int n = fz_runetochar (utf8, ch->c);
179
         if (size + n > cap) {
180
             cap *= 2;
181
@@ -1316,17 +1323,14 @@ static char *strofspan (fz_stext_span *span)
182
     return p;
183
 }
184
 
185
-static int matchspan (regex_t *re, fz_stext_span *span,
186
+static int matchline (regex_t *re, fz_stext_line *line,
187
                       int stop, int pageno, double start)
188
 {
189
     int ret;
190
     char *p;
191
     regmatch_t rm;
192
-    int a, b, c;
193
-    fz_rect sb, eb;
194
-    fz_point p1, p2, p3, p4;
195
 
196
-    p = strofspan (span);
197
+    p = strofline (line);
198
     if (!p) return -1;
199
 
200
     ret = regexec (re, p, 1, &rm, 0);
201
@@ -1343,31 +1347,33 @@ static int matchspan (regex_t *re, fz_stext_span *span
202
         return 0;
203
     }
204
     else {
205
-        int l = span->len;
206
+        fz_point p1, p2, p3, p4;
207
+        fz_rect s = {0,0,0,0}, e;
208
+        fz_stext_char *ch;
209
+        int o = 0;
210
 
211
-        for (a = 0, c = 0; c < rm.rm_so && a < l; a++) {
212
-            c += fz_runelen (span->text[a].c);
213
+        for (ch = line->first_char; ch; ch = ch->next) {
214
+            o += fz_runelen (ch->c);
215
+            if (o > rm.rm_so) {
216
+                s = ch->bbox;
217
+                break;
218
+            }
219
         }
220
-        for (b = a; c < rm.rm_eo - 1 && b < l; b++) {
221
-            c += fz_runelen (span->text[b].c);
222
+        for (;ch; ch = ch->next) {
223
+            o += fz_runelen (ch->c);
224
+            if (o > rm.rm_eo) break;
225
         }
226
+        e = ch->bbox;
227
 
228
-        if (fz_runelen (span->text[b].c) > 1) {
229
-            b = fz_maxi (0, b-1);
230
-        }
231
+        p1.x = s.x0;
232
+        p1.y = s.y0;
233
+        p2.x = e.x1;
234
+        p2.y = s.y0;
235
+        p3.x = e.x1;
236
+        p3.y = e.y1;
237
+        p4.x = s.x0;
238
+        p4.y = e.y1;
239
 
240
-        fz_stext_char_bbox (state.ctx, &sb, span, a);
241
-        fz_stext_char_bbox (state.ctx, &eb, span, b);
242
-
243
-        p1.x = sb.x0;
244
-        p1.y = sb.y0;
245
-        p2.x = eb.x1;
246
-        p2.y = sb.y0;
247
-        p3.x = eb.x1;
248
-        p3.y = eb.y1;
249
-        p4.x = sb.x0;
250
-        p4.y = eb.y1;
251
-
252
         if (!stop) {
253
             printd ("firstmatch %d %d %f %f %f %f %f %f %f %f",
254
                     pageno, 1,
255
@@ -1393,24 +1399,16 @@ static int matchspan (regex_t *re, fz_stext_span *span
256
     }
257
 }
258
 
259
-static int compareblocks (const void *l, const void *r)
260
-{
261
-    fz_stext_block const *ls = l;
262
-    fz_stext_block const *rs = r;
263
-    return ls->bbox.y0 - rs->bbox.y0;
264
-}
265
-
266
 /* wishful thinking function */
267
 static void search (regex_t *re, int pageno, int y, int forward)
268
 {
269
-    int j;
270
     fz_device *tdev;
271
     fz_stext_page *text;
272
-    fz_stext_sheet *sheet;
273
     struct pagedim *pdim;
274
     int stop = 0, niters = 0;
275
     double start, end;
276
     fz_page *page;
277
+    fz_stext_block *block;
278
 
279
     start = now ();
280
     while (pageno >= 0 && pageno < state.pagecount && !stop) {
281
@@ -1428,9 +1426,8 @@ static void search (regex_t *re, int pageno, int y, in
28
             }
282
             }
283
         }
284
         pdim = pdimofpageno (pageno);
285
-        sheet = fz_new_stext_sheet (state.ctx);
286
         text = fz_new_stext_page (state.ctx, &pdim->mediabox);
287
-        tdev = fz_new_stext_device (state.ctx, sheet, text, 0);
288
+        tdev = fz_new_stext_device (state.ctx, text, 0);
29
 
289
 
30
             lock ("open");
290
         page = fz_load_page (state.ctx, state.doc, pageno);
31
-            fz_set_use_document_css (state.ctx, usedoccss);
291
         {
32
             fz_try (state.ctx) {
292
@@ -1438,34 +1435,34 @@ static void search (regex_t *re, int pageno, int y, in
33
                 ok = openxref (filename, password);
293
             fz_run_page (state.ctx, page, tdev, &ctm, NULL);
294
         }
295
 
296
-        qsort (text->blocks, text->len, sizeof (*text->blocks), compareblocks);
297
         fz_close_device (state.ctx, tdev);
298
         fz_drop_device (state.ctx, tdev);
299
 
300
-        for (j = 0; j < text->len; ++j) {
301
-            int k;
302
-            fz_page_block *pb;
303
-            fz_stext_block *block;
304
+        if (forward) {
305
+            for (block = text->first_block; block; block = block->next) {
306
+                fz_stext_line *line;
307
 
308
-            pb = &text->blocks[forward ? j : text->len - 1 - j];
309
-            if (pb->type != FZ_PAGE_BLOCK_TEXT) continue;
310
-            block = pb->u.text;
311
+                if (block->type != FZ_STEXT_BLOCK_TEXT) continue;
312
+                for (line = block->u.t.first_line; line; line = line->next) {
313
+                    if (line->bbox.y0 < y + 1) continue;
314
 
315
-            for (k = 0; k < block->len; ++k) {
316
+                    switch (matchline (re, line, stop, pageno, start)) {
317
+                    case 0: break;
318
+                    case 1: stop = 1; break;
319
+                    case -1: stop = 1; goto endloop;
320
+                    }
321
+                }
322
+            }
323
+        }
324
+        else {
325
+            for (block = text->last_block; block; block = block->prev) {
326
                 fz_stext_line *line;
327
-                fz_stext_span *span;
328
 
329
-                if (forward) {
330
-                    line = &block->lines[k];
331
+                if (block->type != FZ_STEXT_BLOCK_TEXT) continue;
332
+                for (line = block->u.t.last_line; line; line = line->prev) {
333
                     if (line->bbox.y0 < y + 1) continue;
334
-                }
335
-                else {
336
-                    line = &block->lines[block->len - 1 - k];
337
-                    if (line->bbox.y0 > y - 1) continue;
338
-                }
339
 
340
-                for (span = line->first_span; span; span = span->next) {
341
-                    switch (matchspan (re, span, stop, pageno, start)) {
342
+                    switch (matchline (re, line, stop, pageno, start)) {
343
                     case 0: break;
344
                     case 1: stop = 1; break;
345
                     case -1: stop = 1; goto endloop;
346
@@ -1473,6 +1470,7 @@ static void search (regex_t *re, int pageno, int y, in
347
                 }
34
             }
348
             }
35
@@ -4008,8 +4007,7 @@ CAMLprim value ml_platform (value unit_v
349
         }
350
+
351
         if (forward) {
352
             pageno += 1;
353
             y = 0;
354
@@ -1483,7 +1481,6 @@ static void search (regex_t *re, int pageno, int y, in
355
         }
356
     endloop:
357
         fz_drop_stext_page (state.ctx, text);
358
-        fz_drop_stext_sheet (state.ctx, sheet);
359
         fz_drop_page (state.ctx, page);
360
     }
361
     end = now ();
362
@@ -1537,17 +1534,13 @@ static void realloctexts (int texcount)
363
                           state.texids + texcount);
364
     }
365
 
366
-    size = texcount * sizeof (*state.texids);
367
+    size = texcount * (sizeof (*state.texids) + sizeof (*state.texowners));
368
     state.texids = realloc (state.texids, size);
369
     if (!state.texids) {
370
-        err (1, "realloc texids %" FMT_s, size);
371
+        err (1, "realloc texs %" FMT_s, size);
372
     }
373
 
374
-    size = texcount * sizeof (*state.texowners);
375
-    state.texowners = realloc (state.texowners, size);
376
-    if (!state.texowners) {
377
-        err (1, "realloc texowners %" FMT_s, size);
378
-    }
379
+    state.texowners = (void *) (state.texids + texcount);
380
     if (texcount > state.texcount) {
381
         glGenTextures (texcount - state.texcount,
382
                        state.texids + state.texcount);
383
@@ -1566,23 +1559,32 @@ static char *mbtoutf8 (char *s)
384
     wchar_t *tmp;
385
     size_t i, ret, len;
386
 
387
+    if (state.utf8cs) {
388
+        return s;
389
+    }
390
+
391
     len = mbstowcs (NULL, s, strlen (s));
392
     if (len == 0) {
393
         return s;
394
     }
395
     else {
396
         if (len == (size_t) -1) {
397
+            printd ("emsg mbtoutf8: mbstowcs %d:%s\n", errno, strerror (errno));
398
             return s;
399
         }
400
     }
401
 
402
-    tmp = malloc (len * sizeof (wchar_t));
403
+    tmp = calloc (len, sizeof (wchar_t));
404
     if (!tmp) {
405
+        printd ("emsg mbtoutf8: calloc(%zu, %zu) %d:%s",
406
+                len, sizeof (wchar_t), errno, strerror (errno));
407
         return s;
408
     }
409
 
410
     ret = mbstowcs (tmp, s, len);
411
     if (ret == (size_t) -1) {
412
+        printd ("emsg mbtoutf8: mbswcs %zu characters failed %d:%s\n",
413
+                len, errno, strerror (errno));
414
         free (tmp);
415
         return s;
416
     }
417
@@ -1594,6 +1596,7 @@ static char *mbtoutf8 (char *s)
418
 
419
     p = r = malloc (len + 1);
420
     if (!r) {
421
+        printd ("emsg mbtoutf8: malloc(%zu)", len);
422
         free (tmp);
423
         return s;
424
     }
425
@@ -1988,87 +1991,45 @@ static void recti (int x0, int y0, int x1, int y1)
426
 
427
 static void showsel (struct page *page, int ox, int oy)
428
 {
429
-    int seen = 0;
430
     fz_irect bbox;
431
     fz_rect rect;
432
-    fz_stext_line *line;
433
-    fz_page_block *pageb;
434
     fz_stext_block *block;
435
-    struct mark first, last;
436
+    int seen = 0;
437
     unsigned char selcolor[] = {15,15,15,140};
438
 
439
-    first = page->fmark;
440
-    last = page->lmark;
441
+    if (!page->fmark.ch || !page->lmark.ch) return;
442
 
443
-    if (!first.span || !last.span) return;
444
-
445
     glEnable (GL_BLEND);
446
     glBlendFunc (GL_SRC_ALPHA, GL_SRC_ALPHA);
447
     glColor4ubv (selcolor);
448
 
449
     ox += state.pagedims[page->pdimno].bounds.x0;
450
     oy += state.pagedims[page->pdimno].bounds.y0;
451
-    for (pageb = page->text->blocks;
452
-         pageb < page->text->blocks + page->text->len;
453
-         ++pageb) {
454
-        if (pageb->type != FZ_PAGE_BLOCK_TEXT) continue;
455
-        block = pageb->u.text;
456
 
457
-        for (line = block->lines;
458
-             line < block->lines + block->len;
459
-             ++line) {
460
-            fz_stext_span *span;
461
-            rect = fz_empty_rect;
462
+    for (block = page->text->first_block; block; block = block->next) {
463
+        fz_stext_line *line;
464
 
465
-            for (span = line->first_span; span; span = span->next) {
466
-                int i, j, k;
467
-                bbox.x0 = bbox.y0 = bbox.x1 = bbox.y1 = 0;
468
+        if (block->type != FZ_STEXT_BLOCK_TEXT) continue;
469
+        for (line = block->u.t.first_line; line; line = line->next) {
470
+            fz_stext_char *ch;
471
 
472
-                j = 0;
473
-                k = span->len - 1;
474
-
475
-                if (span == page->fmark.span && span == page->lmark.span) {
476
-                    seen = 1;
477
-                    j = fz_mini (first.i, last.i);
478
-                    k = fz_maxi (first.i, last.i);
479
-                }
480
-                else {
481
-                    if (span == first.span) {
482
-                        seen = 1;
483
-                        j = first.i;
484
-                    }
485
-                    else if (span == last.span) {
486
-                        seen = 1;
487
-                        k = last.i;
488
-                    }
489
-                }
490
-
491
-                if (seen) {
492
-                    for (i = j; i <= k; ++i) {
493
-                        fz_rect bbox1;
494
-                        fz_union_rect (&rect,
495
-                                       fz_stext_char_bbox (state.ctx, &bbox1,
496
-                                                           span, i));
497
-                    }
498
+            rect = fz_empty_rect;
499
+            for (ch = line->first_char; ch; ch = ch->next) {
500
+                if (ch == page->fmark.ch) seen = 1;
501
+                if (seen) fz_union_rect (&rect, &ch->bbox);
502
+                if (ch == page->lmark.ch) {
503
                     fz_round_rect (&bbox, &rect);
504
-                    lprintf ("%d %d %d %d oy=%d ox=%d\n",
505
-                             bbox.x0,
506
-                             bbox.y0,
507
-                             bbox.x1,
508
-                             bbox.y1,
509
-                             oy, ox);
510
-
511
                     recti (bbox.x0 + ox, bbox.y0 + oy,
512
                            bbox.x1 + ox, bbox.y1 + oy);
513
-                    if (span == last.span) {
514
-                        goto done;
515
-                    }
516
-                    rect = fz_empty_rect;
517
+                    goto done;
518
                 }
519
             }
520
+            fz_round_rect (&bbox, &rect);
521
+            recti (bbox.x0 + ox, bbox.y0 + oy,
522
+                   bbox.x1 + ox, bbox.y1 + oy);
523
         }
524
     }
525
- done:
526
+done:
527
     glDisable (GL_BLEND);
528
 }
529
 
530
@@ -2131,14 +2092,20 @@ static void solidrect (fz_matrix *m,
531
     glDrawArrays (GL_TRIANGLE_FAN, 0, 4);
532
 }
533
 
534
+static void ensurelinks (struct page *page)
535
+{
536
+    if (!page->links)
537
+        page->links = fz_load_links (state.ctx, page->fzpage);
538
+}
539
+
540
 static void highlightlinks (struct page *page, int xoff, int yoff)
541
 {
542
     fz_matrix ctm, tm, pm;
543
-    fz_link *link, *links;
544
+    fz_link *link;
545
     GLfloat *texcoords = state.texcoords;
546
     GLfloat *vertices = state.vertices;
547
 
548
-    links = fz_load_links (state.ctx, page->fzpage);
549
+    ensurelinks (page);
550
 
551
     glEnable (GL_TEXTURE_1D);
552
     glEnable (GL_BLEND);
553
@@ -2154,7 +2121,7 @@ static void highlightlinks (struct page *page, int xof
554
     glTexCoordPointer (1, GL_FLOAT, 0, texcoords);
555
     glVertexPointer (2, GL_FLOAT, 0, vertices);
556
 
557
-    for (link = links; link; link = link->next) {
558
+    for (link = page->links; link; link = link->next) {
559
         fz_point p1, p2, p3, p4;
560
 
561
         p1.x = link->rect.x0;
562
@@ -2214,16 +2181,10 @@ static void droptext (struct page *page)
563
 {
564
     if (page->text) {
565
         fz_drop_stext_page (state.ctx, page->text);
566
-        page->fmark.i = -1;
567
-        page->lmark.i = -1;
568
-        page->fmark.span = NULL;
569
-        page->lmark.span = NULL;
570
+        page->fmark.ch = NULL;
571
+        page->lmark.ch = NULL;
572
         page->text = NULL;
573
     }
574
-    if (page->sheet) {
575
-        fz_drop_stext_sheet (state.ctx, page->sheet);
576
-        page->sheet = NULL;
577
-    }
578
 }
579
 
580
 static void dropannots (struct page *page)
581
@@ -2279,6 +2240,10 @@ static void dropslinks (struct page *page)
582
         page->slinks = NULL;
583
         page->slinkcount = 0;
584
     }
585
+    if (page->links) {
586
+        fz_drop_link (state.ctx, page->links);
587
+        page->links = NULL;
588
+    }
589
 }
590
 
591
 static void ensureslinks (struct page *page)
592
@@ -2286,7 +2251,7 @@ static void ensureslinks (struct page *page)
593
     fz_matrix ctm;
594
     int i, count;
595
     size_t slinksize = sizeof (*page->slinks);
596
-    fz_link *link, *links;
597
+    fz_link *link;
598
 
599
     ensureannots (page);
600
     if (state.gen != page->sgen) {
601
@@ -2295,11 +2260,11 @@ static void ensureslinks (struct page *page)
602
     }
603
     if (page->slinks) return;
604
 
605
-    links = fz_load_links (state.ctx, page->fzpage);
606
+    ensurelinks (page);
607
     ctm = pagectm (page);
608
 
609
     count = page->annotcount;
610
-    for (link = links; link; link = link->next) {
611
+    for (link = page->links; link; link = link->next) {
612
         count++;
613
     }
614
     if (count > 0) {
615
@@ -2311,7 +2276,7 @@ static void ensureslinks (struct page *page)
616
             err (1, "calloc slinks %d", count);
617
         }
618
 
619
-        for (i = 0, link = links; link; ++i, link = link->next) {
620
+        for (i = 0, link = page->links; link; ++i, link = link->next) {
621
             fz_rect rect;
622
 
623
             rect = link->rect;
624
@@ -2467,20 +2432,20 @@ static void uploadslice (struct tile *tile, struct sli
625
     }
626
 }
627
 
628
-CAMLprim value ml_begintiles (value unit_v)
629
+CAMLprim void ml_begintiles (value unit_v)
630
 {
631
     CAMLparam1 (unit_v);
632
     glEnable (TEXT_TYPE);
633
     glTexCoordPointer (2, GL_FLOAT, 0, state.texcoords);
634
     glVertexPointer (2, GL_FLOAT, 0, state.vertices);
635
-    CAMLreturn (unit_v);
636
+    CAMLreturn0;
637
 }
638
 
639
-CAMLprim value ml_endtiles (value unit_v)
640
+CAMLprim void ml_endtiles (value unit_v)
641
 {
642
     CAMLparam1 (unit_v);
643
     glDisable (TEXT_TYPE);
644
-    CAMLreturn (unit_v);
645
+    CAMLreturn0;
646
 }
647
 
648
 CAMLprim void ml_drawtile (value args_v, value ptr_v)
649
@@ -2664,9 +2629,9 @@ static fz_link *getlink (struct page *page, int x, int
650
 {
651
     fz_point p;
652
     fz_matrix ctm;
653
-    fz_link *link, *links;
654
+    fz_link *link;
655
 
656
-    links = fz_load_links (state.ctx, page->fzpage);
657
+    ensureslinks (page);
658
 
659
     p.x = x;
660
     p.y = y;
661
@@ -2675,7 +2640,7 @@ static fz_link *getlink (struct page *page, int x, int
662
     fz_invert_matrix (&ctm, &ctm);
663
     fz_transform_point (&p, &ctm);
664
 
665
-    for (link = links; link; link = link->next) {
666
+    for (link = page->links; link; link = link->next) {
667
         if (p.x >= link->rect.x0 && p.x <= link->rect.x1) {
668
             if (p.y >= link->rect.y0 && p.y <= link->rect.y1) {
669
                 return link;
670
@@ -2697,13 +2662,10 @@ static void ensuretext (struct page *page)
671
 
672
         page->text = fz_new_stext_page (state.ctx,
673
                                         &state.pagedims[page->pdimno].mediabox);
674
-        page->sheet = fz_new_stext_sheet (state.ctx);
675
-        tdev = fz_new_stext_device (state.ctx, page->sheet, page->text, 0);
676
+        tdev = fz_new_stext_device (state.ctx, page->text, 0);
677
         ctm = pagectm (page);
678
         fz_run_display_list (state.ctx, page->dlist,
679
                              tdev, &ctm, &fz_infinite_rect, NULL);
680
-        qsort (page->text->blocks, page->text->len,
681
-               sizeof (*page->text->blocks), compareblocks);
682
         fz_close_device (state.ctx, tdev);
683
         fz_drop_device (state.ctx, tdev);
684
     }
685
@@ -2743,7 +2705,9 @@ CAMLprim value ml_find_page_with_links (value start_pa
686
         }
687
         else {
688
             fz_page *page = fz_load_page (state.ctx, state.doc, i);
689
-            found = !!fz_load_links (state.ctx, page);
690
+            fz_link *link = fz_load_links (state.ctx, page);
691
+            found = !!link;
692
+            fz_drop_link (state.ctx, link);
693
             fz_drop_page (state.ctx, page);
694
         }
695
 
696
@@ -2917,8 +2881,9 @@ CAMLprim value ml_getlink (value ptr_v, value n_v)
697
 CAMLprim value ml_getannotcontents (value ptr_v, value n_v)
698
 {
699
     CAMLparam2 (ptr_v, n_v);
700
+    CAMLlocal1 (ret_v);
701
     pdf_document *pdf;
702
-    const char *contents = "";
703
+    char *contents = NULL;
704
 
705
     lock (__func__);
706
     pdf = pdf_specifics (state.ctx, state.doc);
707
@@ -2929,11 +2894,18 @@ CAMLprim value ml_getannotcontents (value ptr_v, value
708
 
709
         page = parse_pointer (__func__, s);
710
         slink = &page->slinks[Int_val (n_v)];
711
-        contents = pdf_annot_contents (state.ctx,
712
-                                       (pdf_annot *) slink->u.annot);
713
+        contents = pdf_copy_annot_contents (state.ctx,
714
+                                            (pdf_annot *) slink->u.annot);
715
     }
716
     unlock (__func__);
717
-    CAMLreturn (caml_copy_string (contents));
718
+    if (contents) {
719
+        ret_v = caml_copy_string (contents);
720
+        fz_free (state.ctx, contents);
721
+    }
722
+    else  {
723
+        ret_v = caml_copy_string ("");
724
+    }
725
+    CAMLreturn (ret_v);
726
 }
727
 
728
 CAMLprim value ml_getlinkcount (value ptr_v)
729
@@ -3019,85 +2991,67 @@ CAMLprim value ml_whatsunder (value ptr_v, value x_v, 
730
     }
731
     else {
732
         fz_rect *b;
733
-        fz_page_block *pageb;
734
         fz_stext_block *block;
735
 
736
         ensuretext (page);
737
-        for (pageb = page->text->blocks;
738
-             pageb < page->text->blocks + page->text->len;
739
-             ++pageb) {
740
+
741
+        for (block = page->text->first_block; block; block = block->next) {
742
             fz_stext_line *line;
743
-            if (pageb->type != FZ_PAGE_BLOCK_TEXT) continue;
744
-            block = pageb->u.text;
745
 
746
+            if (block->type != FZ_STEXT_BLOCK_TEXT) continue;
747
             b = &block->bbox;
748
             if (!(x >= b->x0 && x <= b->x1 && y >= b->y0 && y <= b->y1))
749
                 continue;
750
 
751
-            for (line = block->lines;
752
-                 line < block->lines + block->len;
753
-                 ++line) {
754
-                fz_stext_span *span;
755
+            for (line = block->u.t.first_line; line; line = line->next) {
756
+                fz_stext_char *ch;
757
 
758
                 b = &line->bbox;
759
                 if (!(x >= b->x0 && x <= b->x1 && y >= b->y0 && y <= b->y1))
760
                     continue;
761
 
762
-                for (span = line->first_span; span; span = span->next) {
763
-                    int charnum;
764
+                for (ch = line->first_char; ch; ch = ch->next) {
765
+                    b = &ch->bbox;
766
 
767
-                    b = &span->bbox;
768
-                    if (!(x >= b->x0 && x <= b->x1 && y >= b->y0 && y <= b->y1))
769
-                        continue;
770
+                    if (x >= b->x0 && x <= b->x1 && y >= b->y0 && y <= b->y1) {
771
+                        const char *n2 = fz_font_name (state.ctx, ch->font);
772
+                        FT_FaceRec *face = fz_font_ft_face (state.ctx,
773
+                                                            ch->font);
774
 
775
-                    for (charnum = 0; charnum < span->len; ++charnum) {
776
-                        fz_rect bbox;
777
-                        fz_stext_char_bbox (state.ctx, &bbox, span, charnum);
778
-                        b = &bbox;
779
+                        if (!n2) n2 = "<unknown font>";
780
 
781
-                        if (x >= b->x0 && x <= b->x1
782
-                            && y >= b->y0 && y <= b->y1) {
783
-                            fz_stext_style *style = span->text->style;
784
-                            const char *n2 =
785
-                                style->font
786
-                                ? fz_font_name (state.ctx, style->font)
787
-                                : "Span has no font name"
788
-                                ;
789
-                            FT_FaceRec *face = fz_font_ft_face (state.ctx,
790
-                                                                style->font);
791
-                            if (face && face->family_name) {
792
-                                char *s;
793
-                                char *n1 = face->family_name;
794
-                                size_t l1 = strlen (n1);
795
-                                size_t l2 = strlen (n2);
796
+                        if (face && face->family_name) {
797
+                            char *s;
798
+                            char *n1 = face->family_name;
799
+                            size_t l1 = strlen (n1);
800
+                            size_t l2 = strlen (n2);
801
 
802
-                                if (l1 != l2 || memcmp (n1, n2, l1)) {
803
-                                    s = malloc (l1 + l2 + 2);
804
-                                    if (s) {
805
-                                        memcpy (s, n2, l2);
806
-                                        s[l2] = '=';
807
-                                        memcpy (s + l2 + 1, n1, l1 + 1);
808
-                                        str_v = caml_copy_string (s);
809
-                                        free (s);
810
-                                    }
811
+                            if (l1 != l2 || memcmp (n1, n2, l1)) {
812
+                                s = malloc (l1 + l2 + 2);
813
+                                if (s) {
814
+                                    memcpy (s, n2, l2);
815
+                                    s[l2] = '=';
816
+                                    memcpy (s + l2 + 1, n1, l1 + 1);
817
+                                    str_v = caml_copy_string (s);
818
+                                    free (s);
819
                                 }
820
                             }
821
-                            if (str_v == Val_unit) {
822
-                                str_v = caml_copy_string (n2);
823
-                            }
824
-                            ret_v = caml_alloc_small (1, utext);
825
-                            Field (ret_v, 0) = str_v;
826
-                            goto unlock;
827
                         }
828
+                        if (str_v == Val_unit) {
829
+                            str_v = caml_copy_string (n2);
830
+                        }
831
+                        ret_v = caml_alloc_small (1, utext);
832
+                        Field (ret_v, 0) = str_v;
833
+                        goto unlock;
834
                     }
835
                 }
836
             }
837
         }
838
     }
839
- unlock:
840
+unlock:
841
     unlock (__func__);
842
 
843
- done:
844
+done:
845
     CAMLreturn (ret_v);
846
 }
847
 
848
@@ -3120,10 +3074,8 @@ CAMLprim void ml_clearmark (value ptr_v)
849
     }
850
 
851
     page = parse_pointer (__func__, s);
852
-    page->fmark.span = NULL;
853
-    page->lmark.span = NULL;
854
-    page->fmark.i = 0;
855
-    page->lmark.i = 0;
856
+    page->fmark.ch = NULL;
857
+    page->lmark.ch = NULL;
858
 
859
     unlock (__func__);
860
  done:
861
@@ -3137,7 +3089,6 @@ CAMLprim value ml_markunder (value ptr_v, value x_v, v
862
     fz_rect *b;
863
     struct page *page;
864
     fz_stext_line *line;
865
-    fz_page_block *pageb;
866
     fz_stext_block *block;
867
     struct pagedim *pdim;
868
     int mark = Int_val (mark_v);
869
@@ -3155,34 +3106,8 @@ CAMLprim value ml_markunder (value ptr_v, value x_v, v
870
     ensuretext (page);
871
 
872
     if (mark == mark_page) {
873
-        int i;
874
-        fz_page_block *pb1 = NULL, *pb2 = NULL;
875
-
876
-        for (i = 0; i < page->text->len; ++i) {
877
-            if (page->text->blocks[i].type == FZ_PAGE_BLOCK_TEXT) {
878
-                pb1 = &page->text->blocks[i];
879
-                break;
880
-            }
881
-        }
882
-        if (!pb1) goto unlock;
883
-
884
-        for (i = page->text->len - 1; i >= 0; --i) {
885
-            if (page->text->blocks[i].type == FZ_PAGE_BLOCK_TEXT) {
886
-                pb2 = &page->text->blocks[i];
887
-                break;
888
-            }
889
-        }
890
-        if (!pb2) goto unlock;
891
-
892
-        block = pb1->u.text;
893
-
894
-        page->fmark.i = 0;
895
-        page->fmark.span = block->lines->first_span;
896
-
897
-        block = pb2->u.text;
898
-        line = &block->lines[block->len - 1];
899
-        page->lmark.i = line->last_span->len - 1;
900
-        page->lmark.span = line->last_span;
901
+        page->fmark.ch = page->text->first_block->u.t.first_line->first_char;
902
+        page->lmark.ch = page->text->last_block->u.t.last_line->last_char;
903
         ret_v = Val_bool (1);
904
         goto unlock;
905
     }
906
@@ -3190,102 +3115,62 @@ CAMLprim value ml_markunder (value ptr_v, value x_v, v
907
     x += pdim->bounds.x0;
908
     y += pdim->bounds.y0;
909
 
910
-    for (pageb = page->text->blocks;
911
-         pageb < page->text->blocks + page->text->len;
912
-         ++pageb) {
913
-        if (pageb->type != FZ_PAGE_BLOCK_TEXT) continue;
914
-        block = pageb->u.text;
915
-
916
+    for (block = page->text->first_block; block; block = block->next) {
917
+        if (block->type != FZ_STEXT_BLOCK_TEXT) continue;
918
         b = &block->bbox;
919
         if (!(x >= b->x0 && x <= b->x1 && y >= b->y0 && y <= b->y1))
920
             continue;
921
 
922
         if (mark == mark_block) {
923
-            page->fmark.i = 0;
924
-            page->fmark.span = block->lines->first_span;
925
-
926
-            line = &block->lines[block->len - 1];
927
-            page->lmark.i = line->last_span->len - 1;
928
-            page->lmark.span = line->last_span;
929
+            page->fmark.ch = block->u.t.first_line->first_char;
930
+            page->lmark.ch = block->u.t.last_line->last_char;
931
             ret_v = Val_bool (1);
932
             goto unlock;
933
         }
934
 
935
-        for (line = block->lines;
936
-             line < block->lines + block->len;
937
-             ++line) {
938
-            fz_stext_span *span;
939
+        for (line = block->u.t.first_line; line; line = line->next) {
940
+            fz_stext_char *ch;
941
 
942
             b = &line->bbox;
943
             if (!(x >= b->x0 && x <= b->x1 && y >= b->y0 && y <= b->y1))
944
                 continue;
945
 
946
             if (mark == mark_line) {
947
-                page->fmark.i = 0;
948
-                page->fmark.span = line->first_span;
949
-
950
-                page->lmark.i = line->last_span->len - 1;
951
-                page->lmark.span = line->last_span;
952
+                page->fmark.ch = line->first_char;
953
+                page->lmark.ch = line->last_char;
954
                 ret_v = Val_bool (1);
955
                 goto unlock;
956
             }
957
 
958
-            for (span = line->first_span; span; span = span->next) {
959
-                int charnum;
960
-
961
-                b = &span->bbox;
962
-                if (!(x >= b->x0 && x <= b->x1 && y >= b->y0 && y <= b->y1))
963
-                    continue;
964
-
965
-                for (charnum = 0; charnum < span->len; ++charnum) {
966
-                    fz_rect bbox;
967
-                    fz_stext_char_bbox (state.ctx, &bbox, span, charnum);
968
-                    b = &bbox;
969
-
970
-                    if (x >= b->x0 && x <= b->x1 && y >= b->y0 && y <= b->y1) {
971
-                        /* unicode ftw */
972
-                        int charnum2, charnum3 = -1, charnum4 = -1;
973
-
974
-                        if (uninteresting (span->text[charnum].c)) goto unlock;
975
-
976
-                        for (charnum2 = charnum; charnum2 >= 0; --charnum2) {
977
-                            if (uninteresting (span->text[charnum2].c)) {
978
-                                charnum3 = charnum2 + 1;
979
-                                break;
980
-                            }
981
-                        }
982
-                        if (charnum3 == -1) charnum3 = 0;
983
-
984
-                        charnum4 = charnum;
985
-                        for (charnum2 = charnum + 1;
986
-                             charnum2 < span->len;
987
-                             ++charnum2) {
988
-                            if (uninteresting (span->text[charnum2].c)) break;
989
-                            charnum4 = charnum2;
990
-                        }
991
-
992
-                        page->fmark.i = charnum3;
993
-                        page->fmark.span = span;
994
-
995
-                        page->lmark.i = charnum4;
996
-                        page->lmark.span = span;
997
-                        ret_v = Val_bool (1);
998
-                        goto unlock;
999
+            for (ch = line->first_char; ch; ch = ch->next) {
1000
+                fz_stext_char *ch2, *first = NULL, *last = NULL;
1001
+                b = &ch->bbox;
1002
+                if (x >= b->x0 && x <= b->x1 && y >= b->y0 && y <= b->y1) {
1003
+                    for (ch2 = line->first_char; ch2 != ch; ch2 = ch2->next) {
1004
+                        if (uninteresting (ch2->c)) first = NULL;
1005
+                        else if (!first) first = ch2;
1006
                     }
1007
+                    for (ch2 = ch; ch2; ch2 = ch2->next) {
1008
+                        if (uninteresting (ch2->c)) break;
1009
+                        last = ch2;
1010
+                    }
1011
+
1012
+                    page->fmark.ch = first;
1013
+                    page->lmark.ch = last;
1014
+                    ret_v = Val_bool (1);
1015
+                    goto unlock;
1016
                 }
1017
             }
1018
         }
1019
     }
1020
- unlock:
1021
+unlock:
1022
     if (!Bool_val (ret_v)) {
1023
-        page->fmark.span = NULL;
1024
-        page->lmark.span = NULL;
1025
-        page->fmark.i = 0;
1026
-        page->lmark.i = 0;
1027
+        page->fmark.ch = NULL;
1028
+        page->lmark.ch = NULL;
1029
     }
1030
     unlock (__func__);
1031
 
1032
- done:
1033
+done:
1034
     CAMLreturn (ret_v);
1035
 }
1036
 
1037
@@ -3295,8 +3180,8 @@ CAMLprim value ml_rectofblock (value ptr_v, value x_v,
1038
     CAMLlocal2 (ret_v, res_v);
1039
     fz_rect *b = NULL;
1040
     struct page *page;
1041
-    fz_page_block *pageb;
1042
     struct pagedim *pdim;
1043
+    fz_stext_block *block;
1044
     char *s = String_val (ptr_v);
1045
     int x = Int_val (x_v), y = Int_val (y_v);
1046
 
1047
@@ -3312,16 +3197,14 @@ CAMLprim value ml_rectofblock (value ptr_v, value x_v,
1048
 
1049
     ensuretext (page);
1050
 
1051
-    for (pageb = page->text->blocks;
1052
-         pageb < page->text->blocks + page->text->len;
1053
-         ++pageb) {
1054
-        switch (pageb->type) {
1055
-        case FZ_PAGE_BLOCK_TEXT:
1056
-            b = &pageb->u.text->bbox;
1057
+    for (block = page->text->first_block; block; block = block->next) {
1058
+        switch (block->type) {
1059
+        case FZ_STEXT_BLOCK_TEXT:
1060
+            b = &block->bbox;
1061
             break;
1062
 
1063
-        case FZ_PAGE_BLOCK_IMAGE:
1064
-            b = &pageb->u.image->bbox;
1065
+        case FZ_STEXT_BLOCK_IMAGE:
1066
+            b = &block->bbox;
1067
             break;
1068
 
1069
         default:
1070
@@ -3354,11 +3237,11 @@ CAMLprim void ml_seltext (value ptr_v, value rect_v)
1071
     struct page *page;
1072
     struct pagedim *pdim;
1073
     char *s = String_val (ptr_v);
1074
-    int i, x0, x1, y0, y1, fi, li;
1075
+    int x0, x1, y0, y1;
1076
+    fz_stext_char *ch;
1077
     fz_stext_line *line;
1078
-    fz_page_block *pageb;
1079
     fz_stext_block *block;
1080
-    fz_stext_span *span, *fspan, *lspan;
1081
+    fz_stext_char *fc, *lc;
1082
 
1083
     if (trylock (__func__)) {
1084
         goto done;
1085
@@ -3381,76 +3264,51 @@ CAMLprim void ml_seltext (value ptr_v, value rect_v)
1086
         x1 = t;
1087
     }
1088
 
1089
-    fi = page->fmark.i;
1090
-    fspan = page->fmark.span;
1091
+    fc = page->fmark.ch;
1092
+    lc = page->lmark.ch;
1093
 
1094
-    li = page->lmark.i;
1095
-    lspan = page->lmark.span;
1096
-
1097
-    for (pageb = page->text->blocks;
1098
-         pageb < page->text->blocks + page->text->len;
1099
-         ++pageb) {
1100
-        if (pageb->type != FZ_PAGE_BLOCK_TEXT) continue;
1101
-        block = pageb->u.text;
1102
-        for (line = block->lines;
1103
-             line < block->lines + block->len;
1104
-             ++line) {
1105
-
1106
-            for (span = line->first_span; span; span = span->next) {
1107
-                for (i = 0; i < span->len; ++i) {
1108
-                    fz_stext_char_bbox (state.ctx, &b, span, i);
1109
-
1110
-                    if (x0 >= b.x0 && x0 <= b.x1
1111
-                        && y0 >= b.y0 && y0 <= b.y1) {
1112
-                        fspan = span;
1113
-                        fi = i;
1114
-                    }
1115
-                    if (x1 >= b.x0 && x1 <= b.x1
1116
-                        && y1 >= b.y0 && y1 <= b.y1) {
1117
-                        lspan = span;
1118
-                        li = i;
1119
-                    }
1120
+    for (block = page->text->first_block; block; block = block->next) {
1121
+        if (block->type != FZ_STEXT_BLOCK_TEXT) continue;
1122
+        for (line = block->u.t.first_line; line; line = line->next) {
1123
+            for (ch = line->first_char; ch; ch = ch->next) {
1124
+                b = ch->bbox;
1125
+                if (x0 >= b.x0 && x0 <= b.x1 && y0 >= b.y0 && y0 <= b.y1) {
1126
+                    fc = ch;
1127
                 }
1128
+                if (x1 >= b.x0 && x1 <= b.x1 && y1 >= b.y0 && y1 <= b.y1) {
1129
+                    lc = ch;
1130
+                }
1131
             }
1132
         }
1133
     }
1134
-    if (x1 < x0 && fspan == lspan) {
1135
-        i = fi;
1136
-        span = fspan;
1137
+    if (x1 < x0 && fc == lc) {
1138
+        fz_stext_char *t;
1139
 
1140
-        fi = li;
1141
-        fspan = lspan;
1142
-
1143
-        li = i;
1144
-        lspan = span;
1145
+        t = fc;
1146
+        fc = lc;
1147
+        lc = t;
1148
     }
1149
 
1150
-    page->fmark.i = fi;
1151
-    page->fmark.span = fspan;
1152
+    page->fmark.ch = fc;
1153
+    page->lmark.ch = lc;
1154
 
1155
-    page->lmark.i = li;
1156
-    page->lmark.span = lspan;
1157
-
1158
     unlock (__func__);
1159
 
1160
  done:
1161
     CAMLreturn0;
1162
 }
1163
 
1164
-static int UNUSED_ATTR pipespan (FILE *f, fz_stext_span *span, int a, int b)
1165
+static int pipechar (FILE *f, fz_stext_char *ch)
1166
 {
1167
     char buf[4];
1168
-    int i, len, ret;
1169
+    int len, ret;
1170
 
1171
-    for (i = a; i <= b; ++i) {
1172
-        len = fz_runetochar (buf, span->text[i].c);
1173
-        ret = fwrite (buf, len, 1, f);
1174
-
1175
-        if (ret != 1) {
1176
-            fprintf (stderr, "failed to write %d bytes ret=%d: %s\n",
1177
-                     len, ret, strerror (errno));
1178
-            return -1;
1179
-        }
1180
+    len = fz_runetochar (buf, ch->c);
1181
+    ret = fwrite (buf, len, 1, f);
1182
+    if (ret != 1) {
1183
+        fprintf (stderr, "failed to write %d bytes ret=%d: %s\n",
1184
+                 len, ret, strerror (errno));
1185
+        return -1;
1186
     }
1187
     return 0;
1188
 }
1189
@@ -3549,7 +3407,7 @@ CAMLprim value ml_hassel (value ptr_v)
1190
     }
1191
 
1192
     page = parse_pointer (__func__, s);
1193
-    ret_v = Val_bool (page->fmark.span && page->lmark.span);
1194
+    ret_v = Val_bool (page->fmark.ch && page->lmark.ch);
1195
     unlock (__func__);
1196
  done:
1197
     CAMLreturn (ret_v);
1198
@@ -3562,7 +3420,6 @@ CAMLprim void ml_copysel (value fd_v, value ptr_v)
1199
     int seen = 0;
1200
     struct page *page;
1201
     fz_stext_line *line;
1202
-    fz_page_block *pageb;
1203
     fz_stext_block *block;
1204
     int fd = Int_val (fd_v);
1205
     char *s = String_val (ptr_v);
1206
@@ -3573,7 +3430,7 @@ CAMLprim void ml_copysel (value fd_v, value ptr_v)
1207
 
1208
     page = parse_pointer (__func__, s);
1209
 
1210
-    if (!page->fmark.span || !page->lmark.span) {
1211
+    if (!page->fmark.ch || !page->lmark.ch) {
1212
         fprintf (stderr, "nothing to copy on page %d\n", page->pageno);
1213
         goto unlock;
1214
     }
1215
@@ -3585,43 +3442,24 @@ CAMLprim void ml_copysel (value fd_v, value ptr_v)
1216
         f = stdout;
1217
     }
1218
 
1219
-    for (pageb = page->text->blocks;
1220
-         pageb < page->text->blocks + page->text->len;
1221
-         ++pageb) {
1222
-        if (pageb->type != FZ_PAGE_BLOCK_TEXT) continue;
1223
-        block = pageb->u.text;
1224
-        for (line = block->lines;
1225
-             line < block->lines + block->len;
1226
-             ++line) {
1227
-            fz_stext_span *span;
1228
-
1229
-            for (span = line->first_span; span; span = span->next) {
1230
-                int a, b;
1231
-
1232
-                seen |= span == page->fmark.span || span == page->lmark.span;
1233
-                a = span == page->fmark.span ? page->fmark.i : 0;
1234
-                b = span == page->lmark.span ? page->lmark.i : span->len - 1;
1235
-
1236
-                if (seen) {
1237
-                    if (pipespan (f, span, a, b)) {
1238
-                        goto close;
1239
-                    }
1240
-                    if (span == page->lmark.span) {
1241
-                        goto close;
1242
-                    }
1243
-                    if (span == line->last_span) {
1244
-                        if (putc ('\n', f) == EOF) {
1245
-                            fprintf (stderr,
1246
-                                     "failed break line on sel pipe: %s\n",
1247
-                                     strerror (errno));
1248
-                            goto close;
1249
-                        }
1250
-                    }
1251
+    for (block = page->text->first_block; block; block = block->next) {
1252
+        if (block->type != FZ_STEXT_BLOCK_TEXT) continue;
1253
+        for (line = block->u.t.first_line; line; line = line->next) {
1254
+            fz_stext_char *ch;
1255
+            for (ch = line->first_char; ch; ch = ch->next) {
1256
+                if (seen || ch == page->fmark.ch) {
1257
+                    do {
1258
+                        pipechar (f, ch);
1259
+                        if (ch == page->lmark.ch) goto close;
1260
+                    } while ((ch = ch->next));
1261
+                    seen = 1;
1262
+                    break;
1263
                 }
1264
             }
1265
+            if (seen) fputc ('\n', f);
1266
         }
1267
     }
1268
- close:
1269
+close:
1270
     if (f != stdout) {
1271
         int ret = fclose (f);
1272
         fd = -1;
1273
@@ -3632,10 +3470,10 @@ CAMLprim void ml_copysel (value fd_v, value ptr_v)
1274
             }
1275
         }
1276
     }
1277
- unlock:
1278
+unlock:
1279
     unlock (__func__);
1280
 
1281
- done:
1282
+done:
1283
     if (fd >= 0) {
1284
         if (close (fd)) {
1285
             fprintf (stderr, "failed to close sel pipe: %s\n",
1286
@@ -3768,7 +3606,6 @@ CAMLprim value ml_getpagebox (value opaque_v)
1287
 
1288
     ret_v = caml_alloc_tuple (4);
1289
     dev = fz_new_bbox_device (state.ctx, &rect);
1290
-    dev->hints |= FZ_IGNORE_SHADE;
1291
 
1292
     ctm = pagectm (page);
1293
     fz_run_page (state.ctx, page->fzpage, dev, &ctm, NULL);
1294
@@ -3792,6 +3629,7 @@ CAMLprim void ml_setaalevel (value level_v)
1295
     CAMLreturn0;
1296
 }
1297
 
1298
+#ifndef __COCOA__
1299
 #pragma GCC diagnostic push
1300
 #pragma GCC diagnostic ignored "-Wvariadic-macros"
1301
 #include <X11/Xlib.h>
1302
@@ -3848,7 +3686,6 @@ CAMLprim value ml_glxinit (value display_v, value wid_
1303
     int num_conf;
1304
     EGLint visid;
1305
     EGLint attribs[] = {
1306
-        EGL_DEPTH_SIZE, 24,
1307
         EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1308
         EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
1309
         EGL_NONE
1310
@@ -3887,7 +3724,7 @@ CAMLprim value ml_glxinit (value display_v, value wid_
1311
     CAMLreturn (Val_int (visid));
1312
 }
1313
 
1314
-CAMLprim value ml_glxcompleteinit (value unit_v)
1315
+CAMLprim void ml_glxcompleteinit (value unit_v)
1316
 {
1317
     CAMLparam1 (unit_v);
1318
 
1319
@@ -3902,12 +3739,11 @@ CAMLprim value ml_glxcompleteinit (value unit_v)
1320
         caml_failwith ("eglCreateWindowSurface");
1321
     }
1322
 
1323
-    XFree (glx.visual);
1324
     if (!eglMakeCurrent (glx.edpy, glx.win, glx.win, glx.ctx)) {
1325
         glx.ctx = NULL;
1326
         caml_failwith ("eglMakeCurrent");
1327
     }
1328
-    CAMLreturn (unit_v);
1329
+    CAMLreturn0;
1330
 }
1331
 #else
1332
 CAMLprim value ml_glxinit (value display_v, value wid_v, value screen_v)
1333
@@ -3932,7 +3768,7 @@ CAMLprim value ml_glxinit (value display_v, value wid_
1334
     CAMLreturn (Val_int (glx.visual->visualid));
1335
 }
1336
 
1337
-CAMLprim value ml_glxcompleteinit (value unit_v)
1338
+CAMLprim void ml_glxcompleteinit (value unit_v)
1339
 {
1340
     CAMLparam1 (unit_v);
1341
 
1342
@@ -3949,7 +3785,7 @@ CAMLprim value ml_glxcompleteinit (value unit_v)
1343
         glx.ctx = NULL;
1344
         caml_failwith ("glXMakeCurrent");
1345
     }
1346
-    CAMLreturn (unit_v);
1347
+    CAMLreturn0;
1348
 }
1349
 #endif
1350
 
1351
@@ -3964,7 +3800,7 @@ CAMLprim void ml_setcursor (value cursor_v)
1352
     CAMLreturn0;
1353
 }
1354
 
1355
-CAMLprim value ml_swapb (value unit_v)
1356
+CAMLprim void ml_swapb (value unit_v)
1357
 {
1358
     CAMLparam1 (unit_v);
1359
 #ifdef USE_EGL
1360
@@ -3974,7 +3810,7 @@ CAMLprim value ml_swapb (value unit_v)
1361
 #else
1362
     glXSwapBuffers (glx.dpy, glx.wid);
1363
 #endif
1364
-    CAMLreturn (unit_v);
1365
+    CAMLreturn0;
1366
 }
1367
 
1368
 #include "keysym2ucs.c"
1369
@@ -3994,7 +3830,22 @@ CAMLprim value ml_keysymtoutf8 (value keysym_v)
1370
     str_v = caml_copy_string (buf);
1371
     CAMLreturn (str_v);
1372
 }
1373
+#else
1374
+CAMLprim value ml_keysymtoutf8 (value keysym_v)
1375
+{
1376
+    CAMLparam1 (keysym_v);
1377
+    CAMLlocal1 (str_v);
1378
+    long ucs_v = Long_val (keysym_v);
1379
+    int len;
1380
+    char buf[5];
1381
 
1382
+    len = fz_runetochar (buf, ucs_v);
1383
+    buf[len] = 0;
1384
+    str_v = caml_copy_string (buf);
1385
+    CAMLreturn (str_v);
1386
+}
1387
+#endif
1388
+
1389
 enum { piunknown, pilinux, piosx, pisun, pibsd, picygwin };
1390
 
1391
 CAMLprim value ml_platform (value unit_v)
1392
@@ -4008,8 +3859,7 @@ CAMLprim value ml_platform (value unit_v)
36
     platid = pilinux;
1393
     platid = pilinux;
37
 #elif defined __CYGWIN__
1394
 #elif defined __CYGWIN__
38
     platid = picygwin;
1395
     platid = picygwin;
Lines 42-44 Link Here
42
     platid = pibsd;
1399
     platid = pibsd;
43
 #elif defined __sun__
1400
 #elif defined __sun__
44
     platid = pisun;
1401
     platid = pisun;
1402
@@ -4145,6 +3995,12 @@ CAMLprim void ml_unmappbo (value s_v)
1403
 
1404
 static void setuppbo (void)
1405
 {
1406
+#ifdef __COCOA__
1407
+  static CFBundleRef framework = NULL;
1408
+  if (framework == NULL)
1409
+    framework = CFBundleGetBundleWithIdentifier (CFSTR ("com.apple.opengl"));
1410
+#define GGPA(n) (&state.n = CFBundleGetFunctionPointerForName (framework, CFSTR (#n)))
1411
+#else
1412
 #ifdef USE_EGL
1413
 #define GGPA(n) (*(void (**) ()) &state.n = eglGetProcAddress (#n))
1414
 #else
1415
@@ -4156,6 +4012,7 @@ static void setuppbo (void)
1416
         && GGPA (glBufferDataARB)
1417
         && GGPA (glGenBuffersARB)
1418
         && GGPA (glDeleteBuffersARB);
1419
+#endif
1420
 #undef GGPA
1421
 }
1422
 
1423
@@ -4364,101 +4221,6 @@ CAMLprim value ml_fz_version (value UNUSED_ATTR unit_v
1424
     return caml_copy_string (FZ_VERSION);
1425
 }
1426
 
1427
-#ifdef USE_FONTCONFIG
1428
-static struct {
1429
-    int inited;
1430
-    FcConfig *config;
1431
-} fc;
1432
-
1433
-static fz_font *fc_load_system_font_func (fz_context *ctx,
1434
-                                          const char *name,
1435
-                                          int bold,
1436
-                                          int italic,
1437
-                                          int UNUSED_ATTR needs_exact_metrics)
1438
-{
1439
-    char *buf;
1440
-    size_t i, size;
1441
-    fz_font *font;
1442
-    FcChar8 *path;
1443
-    FcResult result;
1444
-    FcPattern *pat, *pat1;
1445
-
1446
-    lprintf ("looking up %s bold:%d italic:%d needs_exact_metrics:%d\n",
1447
-             name, bold, italic, needs_exact_metrics);
1448
-    if (!fc.inited) {
1449
-        fc.inited = 1;
1450
-        fc.config = FcInitLoadConfigAndFonts ();
1451
-        if (!fc.config) {
1452
-            lprintf ("FcInitLoadConfigAndFonts failed\n");
1453
-            return NULL;
1454
-        }
1455
-    }
1456
-    if (!fc.config) return NULL;
1457
-
1458
-    size = strlen (name);
1459
-    if (bold) size += sizeof (":bold") - 1;
1460
-    if (italic) size += sizeof (":italic") - 1;
1461
-    size += 1;
1462
-
1463
-    buf = malloc (size);
1464
-    if (!buf) {
1465
-        err (1, "malloc %zu failed", size);
1466
-    }
1467
-
1468
-    strcpy (buf, name);
1469
-    if (bold && italic) {
1470
-        strcat (buf, ":bold:italic");
1471
-    }
1472
-    else {
1473
-        if (bold) strcat (buf, ":bold");
1474
-        if (italic) strcat (buf, ":italic");
1475
-    }
1476
-    for (i = 0; i < size; ++i) {
1477
-        if (buf[i] == ',' || buf[i] == '-') buf[i] = ':';
1478
-    }
1479
-
1480
-    lprintf ("fcbuf=%s\n", buf);
1481
-    pat = FcNameParse ((FcChar8 *) buf);
1482
-    if (!pat) {
1483
-        printd ("emsg FcNameParse failed\n");
1484
-        free (buf);
1485
-        return NULL;
1486
-    }
1487
-
1488
-    if (!FcConfigSubstitute (fc.config, pat, FcMatchPattern)) {
1489
-        printd ("emsg FcConfigSubstitute failed\n");
1490
-        free (buf);
1491
-        return NULL;
1492
-    }
1493
-    FcDefaultSubstitute (pat);
1494
-
1495
-    pat1 = FcFontMatch (fc.config, pat, &result);
1496
-    if (!pat1) {
1497
-        printd ("emsg FcFontMatch failed\n");
1498
-        FcPatternDestroy (pat);
1499
-        free (buf);
1500
-        return NULL;
1501
-    }
1502
-
1503
-    if (FcPatternGetString (pat1, FC_FILE, 0, &path) != FcResultMatch) {
1504
-        printd ("emsg FcPatternGetString failed\n");
1505
-        FcPatternDestroy (pat);
1506
-        FcPatternDestroy (pat1);
1507
-        free (buf);
1508
-        return NULL;
1509
-    }
1510
-
1511
-#if 0
1512
-    printd ("emsg name=%s path=%s\n", name, path);
1513
-#endif
1514
-    font = fz_new_font_from_file (ctx, name, (char *) path, 0, 0);
1515
-    FcPatternDestroy (pat);
1516
-    FcPatternDestroy (pat1);
1517
-    free (buf);
1518
-    return font;
1519
-}
1520
-#endif
1521
-
1522
 CAMLprim void ml_init (value csock_v, value params_v)
1523
 {
1524
     CAMLparam2 (csock_v, params_v);
1525
@@ -4470,6 +4232,20 @@ CAMLprim void ml_init (value csock_v, value params_v)
1526
     int mustoresize;
1527
     int haspboext;
1528
 
1529
+    /* Without following call to setlocale mbstowcs fails for, at
1530
+       least, strings containing chinese symbols (δΈ­ for instance)
1531
+       (with glibc citing EILSEQ="Invalid or incomplete multibyte or
1532
+       wide character" as the reason of failure and with macOS
1533
+       producing bogus output) */
1534
+    if (setlocale (LC_CTYPE, "")) {
1535
+        /* Following two lines were taken from dvtm/vt.c */
1536
+        const char *cset = nl_langinfo (CODESET);
1537
+        state.utf8cs = !strcmp (cset, "UTF-8");
1538
+    }
1539
+    else {
1540
+        fprintf (stderr, "setlocale failed\n");
1541
+    }
1542
+
1543
     state.csock         = Int_val (csock_v);
1544
     state.rotate        = Int_val (Field (params_v, 0));
1545
     state.fitmodel      = Int_val (Field (params_v, 1));
1546
@@ -4489,19 +4265,11 @@ CAMLprim void ml_init (value csock_v, value params_v)
1547
         }
1548
     }
1549
 
1550
-    haspboext           = Bool_val (Field (params_v, 9));
1551
+    haspboext         = Bool_val (Field (params_v, 9));
1552
 
1553
     state.ctx = fz_new_context (NULL, NULL, mustoresize);
1554
     fz_register_document_handlers (state.ctx);
1555
 
1556
-#ifdef USE_FONTCONFIG
1557
-    if (Bool_val (Field (params_v, 11))) {
1558
-        fz_install_load_system_font_funcs (
1559
-            state.ctx, fc_load_system_font_func, NULL
1560
-            );
1561
-    }
1562
-#endif
1563
-
1564
     state.trimmargins = Bool_val (Field (trim_v, 0));
1565
     fuzz_v            = Field (trim_v, 1);
1566
     state.trimfuzz.x0 = Int_val (Field (fuzz_v, 0));
1567
@@ -4512,48 +4280,13 @@ CAMLprim void ml_init (value csock_v, value params_v)
1568
     set_tex_params (colorspace);
1569
 
1570
     if (*fontpath) {
1571
-#ifndef USE_FONTCONFIG
1572
         state.face = load_font (fontpath);
1573
-#else
1574
-        FcChar8 *path;
1575
-        FcResult result;
1576
-        char *buf = fontpath;
1577
-        FcPattern *pat, *pat1;
1578
-
1579
-        fc.inited = 1;
1580
-        fc.config = FcInitLoadConfigAndFonts ();
1581
-        if (!fc.config) {
1582
-            errx (1, "FcInitLoadConfigAndFonts failed");
1583
-        }
1584
-
1585
-        pat = FcNameParse ((FcChar8 *) buf);
1586
-        if (!pat) {
1587
-            errx (1, "FcNameParse failed");
1588
-        }
1589
-
1590
-        if (!FcConfigSubstitute (fc.config, pat, FcMatchPattern)) {
1591
-            errx (1, "FcConfigSubstitute failed");
1592
-        }
1593
-        FcDefaultSubstitute (pat);
1594
-
1595
-        pat1 = FcFontMatch (fc.config, pat, &result);
1596
-        if (!pat1) {
1597
-            errx (1, "FcFontMatch failed");
1598
-        }
1599
-
1600
-        if (FcPatternGetString (pat1, FC_FILE, 0, &path) != FcResultMatch) {
1601
-            errx (1, "FcPatternGetString failed");
1602
-        }
1603
-
1604
-        state.face = load_font ((char *) path);
1605
-        FcPatternDestroy (pat);
1606
-        FcPatternDestroy (pat1);
1607
-#endif
1608
     }
1609
     else {
1610
         int len;
1611
-        const char *data = pdf_lookup_substitute_font (state.ctx, 0, 0,
1612
-                                                       0, 0, &len);
1613
+        const unsigned char *data;
1614
+
1615
+        data = pdf_lookup_substitute_font (state.ctx, 0, 0, 0, 0, &len);
1616
         state.face = load_builtin_font (data, len);
1617
     }
1618
     if (!state.face) _exit (1);

Return to bug 224712