3681 lines · 100.0 KB · C
RawDownload
/* lots of code c&p-ed directly from mupdf */#include <ctype.h>#include <errno.h>#include <fcntl.h>#include <inttypes.h>#include <langinfo.h>#include <locale.h>#include <math.h>#include <pthread.h>#include <regex.h>#include <spawn.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <sys/uio.h>#include <unistd.h>#include <wchar.h> #ifdef LLPARANOIDP#pragma GCC diagnostic error "-Weverything"#pragma GCC diagnostic ignored "-Wpadded"#pragma GCC diagnostic ignored "-Wsign-conversion"#pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"#pragma GCC diagnostic ignored "-Wdocumentation"#pragma GCC diagnostic ignored "-Wdouble-promotion"#pragma GCC diagnostic ignored "-Wimplicit-int-float-conversion"#else#pragma GCC diagnostic error "-Wcast-qual"#endif #include GL_H #define CAML_NAME_SPACE#include <caml/fail.h>#include <caml/alloc.h>#include <caml/memory.h>#include <caml/unixsupport.h> #pragma GCC diagnostic push#pragma GCC diagnostic ignored "-Wfloat-equal"#include <mupdf/fitz.h>#include <mupdf/pdf.h>#pragma GCC diagnostic pop #pragma GCC diagnostic push#ifdef __clang__#pragma GCC diagnostic ignored "-Wreserved-id-macro"#endif#include <ft2build.h>#include FT_FREETYPE_H#pragma GCC diagnostic pop #include "cutils.h" #define ARSERT(c) !(c) ? errx (1, "%s:%d " #c, __FILE__, __LINE__) : (void) 0#define ML(d) extern value ml_##d; value ml_##d#define ML0(d) extern void ml_##d; void ml_##d#define STTI(st) ((unsigned int) (st)) enum { Copen=23, Ccs, Cfreepage, Cfreetile, Csearch, Cgeometry, Creqlayout,       Cpage, Ctile, Ctrimset, Csettrim, Csliceh, Cinterrupt };enum { FitWidth, FitProportional, FitPage };enum { LDfirst, LDlast };enum { LDfirstvisible, LDleft, LDright, LDdown, LDup };enum { Uuri, Utext, Utextannot, Ufileannot, Unone };enum { MarkPage, MarkBlock, MarkLine, MarkWord }; struct slice {    int h;    int texindex;}; struct tile {    int w, h;    int slicecount;    int sliceheight;    fz_pixmap *pixmap;    struct slice slices[1];}; struct pagedim {    int pageno;    int rotate;    int left;    int tctmready;    fz_irect bounds;    fz_rect pagebox;    fz_rect mediabox;    fz_matrix ctm, zoomctm, tctm;}; struct slink {    enum { SLINK, SANNOT } tag;    fz_irect bbox;    union {        fz_link *link;        pdf_annot *annot;    } u;}; struct annot {    fz_irect bbox;    pdf_annot *annot;}; struct page {    int tgen;    int sgen;    int agen;    int pageno;    int pdimno;    fz_stext_page *text;    fz_page *fzpage;    fz_display_list *dlist;    fz_link *links;    int slinkcount;    struct slink *slinks;    int annotcount;    struct annot *annots;    fz_stext_char *fmark, *lmark;}; static struct {    pthread_mutex_t mutex;    int sliceheight;    struct pagedim *pagedims;    int pagecount;    int pagedimcount;    fz_document *doc;    fz_context *ctx;    int w, h;    char *dcf;    int pfds[2];     struct {        int index, count;        GLuint *ids;        GLenum iform, form, ty;        struct {            int w, h;            struct slice *slice;        } *owners;    } tex;     fz_colorspace *colorspace;    float papercolor[4];     FT_Face face;    fz_pixmap *pig;    pthread_t thread;    fz_irect trimfuzz;    GLuint stid, boid;    int trimmargins, needoutline, gen, rotate, aalevel,        fitmodel, trimanew, csock, dirty, utf8cs;     GLfloat texcoords[8], vertices[16];} state = { .mutex = PTHREAD_MUTEX_INITIALIZER }; static void lock (const char *cap){    int ret = pthread_mutex_lock (&state.mutex);    if (ret) {        errx (1, "%s: pthread_mutex_lock: %d(%s)", cap, ret, strerror (ret));    }} static void unlock (const char *cap){    int ret = pthread_mutex_unlock (&state.mutex);    if (ret) {        errx (1, "%s: pthread_mutex_unlock: %d(%s)", cap, ret, strerror (ret));    }} static int trylock (const char *cap){    int ret = pthread_mutex_trylock (&state.mutex);    if (ret && ret != EBUSY) {        errx (1, "%s: pthread_mutex_trylock: %d(%s)", cap,              ret, strerror (ret));    }    return ret == EBUSY;} static int hasdata (int fd){    int ret, avail;    ret = ioctl (fd, FIONREAD, &avail);    if (ret) {        err (1, errno, "hasdata: FIONREAD error ret=%d", ret);    }    return avail > 0;} ML (hasdata (value fd_v)){    CAMLparam1 (fd_v);    CAMLreturn (Val_bool (hasdata (Int_val (fd_v))));} static void readdata (int fd, void *p, int size){    ssize_t n; again:    n = read (fd, p, size);    if (n < 0) {        if (errno == EINTR) {            goto again;        }        err (1, errno, "writev (fd %d, req %d, ret %zd)", fd, size, n);    }    if (n - size) {        errx (1, "read (fd %d, req %d, ret %zd)", fd, size, n);    }} static void writedata (int fd, char *p, int size){    ssize_t n;    uint32_t size4 = size;    struct iovec iov[2] = {        { .iov_base = &size4, .iov_len = 4 },        { .iov_base = p, .iov_len = size }    }; again:    n = writev (fd, iov, 2);    if (n < 0) {        if (errno == EINTR) {            goto again;        }        err (1, errno, "writev (fd %d, req %d, ret %zd)", fd, size + 4, n);    }    if (n - size - 4) {        errx (1, "writev (fd %d, req %d, ret %zd)", fd, size + 4, n);    }} static int readlen (int fd){    uint32_t u;    readdata (fd, &u, 4);    return u;} ML0 (wcmd (value fd_v, value bytes_v, value len_v)){    CAMLparam3 (fd_v, bytes_v, len_v);    writedata (Int_val (fd_v), &Byte (bytes_v, 0), Int_val (len_v));    CAMLreturn0;} ML (rcmd (value fd_v)){    CAMLparam1 (fd_v);    CAMLlocal1 (strdata_v);    int fd = Int_val (fd_v);    int len = readlen (fd);    strdata_v = caml_alloc_string (len);    readdata (fd, Bytes_val (strdata_v), len);    CAMLreturn (strdata_v);} static void GCC_FMT_ATTR (1, 2) printd (const char *fmt, ...){    char fbuf[64];    int size = sizeof (fbuf), len;    va_list ap;    char *buf = fbuf;     for (;;) {        va_start (ap, fmt);        len = vsnprintf (buf, size, fmt, ap);        va_end (ap);         if (len > -1) {            if (len < size - 4) {                writedata (state.csock, buf, len);                break;            }            else {                size = len + 5;            }        }        else {            err (1, errno, "vsnprintf for `%s' failed", fmt);        }        buf = realloc (buf == fbuf ? NULL : buf, size);        if (!buf) {            err (1, errno, "realloc for temp buf (%d bytes) failed", size);        }    }    if (buf != fbuf) {        free (buf);    }} static void closedoc (void){    if (state.doc) {        fz_drop_document (state.ctx, state.doc);        state.doc = NULL;    }} static int openxref (char *filename, char *mimetype, char *password,                     int w, int h, int em){    for (int i = 0; i < state.tex.count; ++i) {        state.tex.owners[i].w = -1;        state.tex.owners[i].slice = NULL;    }     closedoc ();     state.dirty = 0;    if (state.pagedims) {        free (state.pagedims);        state.pagedims = NULL;    }    state.pagedimcount = 0;     fz_set_aa_level (state.ctx, state.aalevel);    if (mimetype) {        fz_stream *st = fz_open_file (state.ctx, filename);        state.doc = fz_open_document_with_stream (state.ctx, mimetype, st);    }    else {        state.doc = fz_open_document (state.ctx, filename);    }    if (fz_needs_password (state.ctx, state.doc)) {        if (password && !*password) {            printd ("pass");            return 0;        }        else {            int ok = fz_authenticate_password (state.ctx, state.doc, password);            if (!ok) {                printd ("pass fail");                return 0;            }        }    }    if (w >= 0 || h >= 0 || em >=0) {        fz_layout_document (state.ctx, state.doc, w, h, em);    }    state.pagecount = fz_count_pages (state.ctx, state.doc);    if (state.pagecount < 0) {        state.pagecount = 0;        return 0;    }    return 1;} static void docinfo (void){    struct { char *tag; char *name; } tab[] = {        { FZ_META_INFO_TITLE, "Title" },        { FZ_META_INFO_AUTHOR, "Author" },        { FZ_META_FORMAT, "Format" },        { FZ_META_ENCRYPTION, "Encryption" },        { FZ_META_INFO_CREATOR, "Creator" },        { FZ_META_INFO_PRODUCER, "Producer" },        { FZ_META_INFO_CREATIONDATE, "Creation date" },        { FZ_META_INFO_MODIFICATIONDATE, "Modification date"},    };    int len = 0, need;    char *buf = NULL;     for (size_t i = 0; i < sizeof (tab) / sizeof (*tab); ++i) {    again:        need = fz_lookup_metadata (state.ctx, state.doc, tab[i].tag, buf, len);        if (need > 0) {            if (need <= len) {                printd ("info %s\t%s", tab[i].name, buf);            }            else {                buf = realloc (buf, need);                if (!buf) {                    err (1, errno, "docinfo realloc %d", need);                }                len = need;                goto again;            }        }    }    free (buf);     printd ("infoend");} static void unlinktile (struct tile *tile){    for (int i = 0; i < tile->slicecount; ++i) {        struct slice *s = &tile->slices[i];         if (s->texindex != -1) {            if (state.tex.owners[s->texindex].slice == s) {                state.tex.owners[s->texindex].slice = NULL;            }        }    }} static void freepage (struct page *page){    if (page) {        fz_drop_stext_page (state.ctx, page->text);        free (page->slinks);        fz_drop_display_list (state.ctx, page->dlist);        fz_drop_page (state.ctx, page->fzpage);        free (page);    }} static void freetile (struct tile *tile){    unlinktile (tile);    fz_drop_pixmap (state.ctx, state.pig);    state.pig = tile->pixmap;    free (tile);} static void trimctm (pdf_page *page, int pindex){    struct pagedim *pdim = &state.pagedims[pindex];     if (!page) {        return;    }    if (!pdim->tctmready) {        fz_rect realbox, mediabox;        fz_matrix page_ctm, ctm;         ctm = fz_concat (fz_rotate (-pdim->rotate), fz_scale (1, -1));        realbox = fz_transform_rect (pdim->mediabox, ctm);        pdf_page_transform (state.ctx, page, &mediabox, &page_ctm);        pdim->tctm = fz_concat (            fz_invert_matrix (page_ctm),            fz_concat (ctm, fz_translate (-realbox.x0, -realbox.y0)));        pdim->tctmready = 1;    }} static fz_matrix pagectm1 (fz_page *fzpage, struct pagedim *pdim){    fz_matrix ctm;    ptrdiff_t pdimno = pdim - state.pagedims;     ARSERT (pdim - state.pagedims < INT_MAX);    if (pdf_specifics (state.ctx, state.doc)) {        trimctm (pdf_page_from_fz_page (state.ctx, fzpage), (int) pdimno);        ctm = fz_concat (pdim->tctm, pdim->ctm);    }    else {        ctm = fz_concat (fz_translate (-pdim->mediabox.x0, -pdim->mediabox.y0),                         pdim->ctm);    }    return ctm;} static fz_matrix pagectm (struct page *page){    return pagectm1 (page->fzpage, &state.pagedims[page->pdimno]);} static void *loadpage (int pageno, int pindex){    fz_device *dev;    struct page *page;     page = calloc (sizeof (struct page), 1);    if (!page) {        err (1, errno, "calloc page %d", pageno);    }     page->dlist = fz_new_display_list (state.ctx, fz_infinite_rect);    dev = fz_new_list_device (state.ctx, page->dlist);    fz_try (state.ctx) {        page->fzpage = fz_load_page (state.ctx, state.doc, pageno);        fz_run_page (state.ctx, page->fzpage, dev, fz_identity, NULL);    }    fz_catch (state.ctx) {        page->fzpage = NULL;    }    fz_close_device (state.ctx, dev);    fz_drop_device (state.ctx, dev);     page->pdimno = pindex;    page->pageno = pageno;    page->sgen = state.gen;    page->agen = state.gen;    page->tgen = state.gen;    return page;} static struct tile *alloctile (int h)

Lines 1–500 of 3681.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t