Initial support for adding fonts at run-time. Currently we only support
authorben <ben@cda61777-01e9-0310-a592-d414129be87e>
Sat, 13 May 2006 13:56:05 +0000 (13:56 +0000)
committerben <ben@cda61777-01e9-0310-a592-d414129be87e>
Sat, 13 May 2006 13:56:05 +0000 (13:56 +0000)
loading AFM files, we recognise them by name, and we can't embed fonts in
the output (which is also invalid, though accepted by xpdf, in the PDF case).
Oh, and there's no documentation.  Still, it's a start.

git-svn-id: svn://svn.tartarus.org/sgt/halibut@6681 cda61777-01e9-0310-a592-d414129be87e

Makefile
bk_paper.c
bk_pdf.c
bk_ps.c
error.c
halibut.h
in_afm.c [new file with mode: 0644]
input.c
paper.h
psdata.c

index d57cb3c..8f53a51 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -106,7 +106,7 @@ CFLAGS += -I$(LIBCHARSET_SRCDIR) -I$(LIBCHARSET_OBJDIR)
 include $(LIBCHARSET_SRCDIR)Makefile
 
 MODULES := main malloc ustring error help licence version misc tree234
-MODULES += input keywords contents index biblio
+MODULES += input in_afm keywords contents index biblio
 MODULES += bk_text bk_html bk_whlp bk_man bk_info bk_paper bk_ps bk_pdf
 MODULES += winhelp psdata wcwidth
 
index 5e0830f..64e44ed 100644 (file)
@@ -78,6 +78,7 @@
 #include <assert.h>
 #include <stdio.h>
 #include <stdarg.h>
+#include <stdlib.h>
 
 #include "halibut.h"
 #include "paper.h"
@@ -396,9 +397,9 @@ static paper_conf paper_configure(paragraph *source, font_list *fontlist) {
                paper_cfg_fonts(ret.ftitle.fonts, fontlist, uadv(p->keyword),
                                &p->fpos);
            } else if (!ustricmp(p->keyword, L"paper-chapter-font-size")) {
-               ret.ftitle.font_size = utoi(uadv(p->keyword));
+               ret.fchapter.font_size = utoi(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-chapter-fonts")) {
-               paper_cfg_fonts(ret.ftitle.fonts, fontlist, uadv(p->keyword),
+               paper_cfg_fonts(ret.fchapter.fonts, fontlist, uadv(p->keyword),
                                &p->fpos);
            } else if (!ustricmp(p->keyword, L"paper-section-font-size")) {
                wchar_t *q = uadv(p->keyword);
@@ -458,29 +459,31 @@ static paper_conf paper_configure(paragraph *source, font_list *fontlist) {
      * but must be in the title and body fonts. */
     while (*uadv(ret.rquote) && *uadv(uadv(ret.rquote))) {
        int n;
-       if (!fonts_ok(ret.lquote,
-                     ret.fbase.fonts[FONT_NORMAL],
-                     ret.fbase.fonts[FONT_EMPH],
-                     ret.ftitle.fonts[FONT_NORMAL],
-                     ret.ftitle.fonts[FONT_EMPH],
-                     ret.fchapter.fonts[FONT_NORMAL],
-                     ret.fchapter.fonts[FONT_EMPH], NULL) ||
-           !fonts_ok(ret.rquote,
-                     ret.fbase.fonts[FONT_NORMAL],
-                     ret.fbase.fonts[FONT_EMPH],
-                     ret.ftitle.fonts[FONT_NORMAL],
-                     ret.ftitle.fonts[FONT_EMPH],
-                     ret.fchapter.fonts[FONT_NORMAL],
-                     ret.fchapter.fonts[FONT_EMPH], NULL))
-           break;
-       for (n = 0; n < ret.nfsect; n++)
-           if (!fonts_ok(ret.lquote,
-                        ret.fsect[n].fonts[FONT_NORMAL],
-                        ret.fsect[n].fonts[FONT_EMPH], NULL) ||
-                !fonts_ok(ret.rquote,
-                          ret.fsect[n].fonts[FONT_NORMAL],
-                          ret.fsect[n].fonts[FONT_EMPH], NULL))
+       if (fonts_ok(ret.lquote,
+                    ret.fbase.fonts[FONT_NORMAL],
+                    ret.fbase.fonts[FONT_EMPH],
+                    ret.ftitle.fonts[FONT_NORMAL],
+                    ret.ftitle.fonts[FONT_EMPH],
+                    ret.fchapter.fonts[FONT_NORMAL],
+                    ret.fchapter.fonts[FONT_EMPH], NULL) &&
+           fonts_ok(ret.rquote,
+                    ret.fbase.fonts[FONT_NORMAL],
+                    ret.fbase.fonts[FONT_EMPH],
+                    ret.ftitle.fonts[FONT_NORMAL],
+                    ret.ftitle.fonts[FONT_EMPH],
+                    ret.fchapter.fonts[FONT_NORMAL],
+                    ret.fchapter.fonts[FONT_EMPH], NULL)) {
+           for (n = 0; n < ret.nfsect; n++)
+               if (!fonts_ok(ret.lquote,
+                             ret.fsect[n].fonts[FONT_NORMAL],
+                             ret.fsect[n].fonts[FONT_EMPH], NULL) ||
+                   !fonts_ok(ret.rquote,
+                             ret.fsect[n].fonts[FONT_NORMAL],
+                             ret.fsect[n].fonts[FONT_EMPH], NULL))
+                   break;
+           if (n == ret.nfsect)
                break;
+       }
        ret.lquote = uadv(ret.rquote);
        ret.rquote = uadv(ret.lquote);
     }
@@ -510,6 +513,7 @@ void *paper_pre_backend(paragraph *sourceform, keywordlist *keywords,
     paragraph index_placeholder_para;
     page_data *first_index_page;
 
+    init_std_fonts();
     fontlist = snew(font_list);
     fontlist->head = fontlist->tail = NULL;
 
@@ -1347,7 +1351,7 @@ static font_encoding *new_font_encoding(font_data *font)
     return fe;
 }
 
-static int kern_cmp(void *a, void *b)
+int kern_cmp(void *a, void *b)
 {
     kern_pair const *ka = a, *kb = b;
 
@@ -1362,37 +1366,68 @@ static int kern_cmp(void *a, void *b)
     return 0;
 }
 
+/* This wouldn't be necessary if C had closures. */
+static font_info *glyph_cmp_fi;
+
+static int glyph_cmp(void const *a, void const *b)
+{
+    return strcmp(glyph_cmp_fi->glyphs[*(unsigned short *)a],
+                 glyph_cmp_fi->glyphs[*(unsigned short *)b]);
+}
+
+/*
+ * Set up the glyphsbyname index for a font.
+ */
+void font_index_glyphs(font_info *fi) {
+    int i;
+
+    fi->glyphsbyname = snewn(fi->nglyphs, unsigned short);
+    for (i = 0; i < fi->nglyphs; i++)
+       fi->glyphsbyname[i] = i;
+    glyph_cmp_fi = fi;
+    qsort(fi->glyphsbyname, fi->nglyphs, sizeof(fi->glyphsbyname[0]),
+         glyph_cmp);
+}
+
+int find_glyph(font_info *fi, char const *name) {
+    int i, j, k, r;
+
+    i = -1;
+    j = fi->nglyphs;
+    while (j-i > 1) {
+       k = (i + j) / 2;
+       r = strcmp(fi->glyphs[fi->glyphsbyname[k]], name);
+       if (r == 0)
+           return fi->glyphsbyname[k];
+       else if (r > 0)
+           j = k;
+       else
+           i = k;
+    }
+    return -1;
+}
+
 static font_data *make_std_font(font_list *fontlist, char const *name)
 {
-    const int *widths;
-    const kern_pair *kerns;
     int nglyphs;
+    font_info const *fi;
     font_data *f;
     font_encoding *fe;
     int i;
 
     for (fe = fontlist->head; fe; fe = fe->next)
-       if (strcmp(fe->font->name, name) == 0)
+       if (strcmp(fe->font->info->name, name) == 0)
            return fe->font;
 
-    /* XXXKERN */
-    widths = ps_std_font_widths(name);
-    kerns = ps_std_font_kerns(name);
-    if (!widths || !kerns)
-       return NULL;
-
-    for (nglyphs = 0; ps_std_glyphs[nglyphs] != NULL; nglyphs++);
+    for (fi = all_fonts; fi; fi = fi->next)
+       if (strcmp(fi->name, name) == 0) break;
+    if (!fi) return NULL;
 
     f = snew(font_data);
 
     f->list = fontlist;
-    f->name = name;
-    f->nglyphs = nglyphs;
-    f->glyphs = ps_std_glyphs;
-    f->widths = widths;
-    f->kerns = newtree234(kern_cmp);
-    for (;kerns->left != 0xFFFF; kerns++)
-       add234(f->kerns, (void *)kerns);
+    f->info = fi;
+    nglyphs = f->info->nglyphs;
     f->subfont_map = snewn(nglyphs, subfont_map_entry);
 
     /*
@@ -1406,16 +1441,11 @@ static font_data *make_std_font(font_list *fontlist, char const *name)
     fe->free_pos = 0xA1;              /* only the top half is free */
     f->latest_subfont = fe;
 
-    for (i = 0; i < (int)lenof(f->bmp); i++)
-       f->bmp[i] = 0xFFFF;
-
     for (i = 0; i < nglyphs; i++) {
        wchar_t ucs;
-       ucs = ps_glyph_to_unicode(f->glyphs[i]);
-       assert(ucs != 0xFFFF);
-       f->bmp[ucs] = i;
+       ucs = ps_glyph_to_unicode(f->info->glyphs[i]);
        if (ucs >= 0x20 && ucs <= 0x7E) {
-           fe->vector[ucs] = f->glyphs[i];
+           fe->vector[ucs] = f->info->glyphs[i];
            fe->indices[ucs] = i;
            fe->to_unicode[ucs] = ucs;
            f->subfont_map[i].subfont = fe;
@@ -1442,7 +1472,7 @@ static int find_kern(font_data *font, int lindex, int rindex)
        return 0;
     wantkp.left = lindex;
     wantkp.right = rindex;
-    kp = find234(font->kerns, &wantkp, NULL);
+    kp = find234(font->info->kerns, &wantkp, NULL);
     if (kp == NULL)
        return 0;
     return kp->kern;
@@ -1459,13 +1489,14 @@ static int string_width(font_data *font, wchar_t const *string, int *errs)
     oindex = 0xFFFF;
     for (; *string; string++) {
        index = (*string < 0 || *string > 0xFFFF ? 0xFFFF :
-                font->bmp[*string]);
+                font->info->bmp[*string]);
 
        if (index == 0xFFFF) {
            if (errs)
                *errs = 1;
        } else {
-           width += find_kern(font, oindex, index) + font->widths[index];
+           width += find_kern(font, oindex, index) +
+               font->info->widths[index];
        }
        oindex = index;
     }
@@ -1913,7 +1944,7 @@ static int render_string(page_data *page, font_data *font, int fontsize,
     while (*str) {
        oglyph = glyph;
        glyph = (*str < 0 || *str > 0xFFFF ? 0xFFFF :
-                font->bmp[*str]);
+                font->info->bmp[*str]);
 
        if (glyph == 0xFFFF) {
            str++;
@@ -1940,7 +1971,7 @@ static int render_string(page_data *page, font_data *font, int fontsize,
 
            font->subfont_map[glyph].subfont = font->latest_subfont;
            font->subfont_map[glyph].position = c;
-           font->latest_subfont->vector[c] = font->glyphs[glyph];
+           font->latest_subfont->vector[c] = font->info->glyphs[glyph];
            font->latest_subfont->indices[c] = glyph;
            font->latest_subfont->to_unicode[c] = *str;
 
@@ -1964,7 +1995,7 @@ static int render_string(page_data *page, font_data *font, int fontsize,
        }
 
        text[textpos++] = font->subfont_map[glyph].position;
-       textwid += font->widths[glyph] * fontsize;
+       textwid += font->info->widths[glyph] * fontsize;
 
        str++;
     }
index 5edf592..034cff1 100644 (file)
--- a/bk_pdf.c
+++ b/bk_pdf.c
@@ -148,7 +148,7 @@ void pdf_backend(paragraph *sourceform, keywordlist *keywords,
        objtext(font, "<<\n/Type /Font\n/Subtype /Type1\n/Name /");
        objtext(font, fe->name);
        objtext(font, "\n/BaseFont /");
-       objtext(font, fe->font->name);
+       objtext(font, fe->font->info->name);
        objtext(font, "\n/Encoding <<\n/Type /Encoding\n/Differences [");
 
        for (i = 0; i < 256; i++) {
@@ -183,7 +183,7 @@ void pdf_backend(paragraph *sourceform, keywordlist *keywords,
                if (fe->indices[i] < 0)
                    width = 0.0;
                else
-                   width = fe->font->widths[fe->indices[i]];
+                   width = fe->font->info->widths[fe->indices[i]];
                sprintf(buf, "%g\n", 1000.0 * width / FUNITS_PER_PT);
                objtext(widths, buf);
            }
diff --git a/bk_ps.c b/bk_ps.c
index 5409290..95d1383 100644 (file)
--- a/bk_ps.c
+++ b/bk_ps.c
@@ -56,7 +56,7 @@ void ps_backend(paragraph *sourceform, keywordlist *keywords,
     fprintf(fp, "%%%%DocumentNeededResources:\n");
     for (fe = doc->fonts->head; fe; fe = fe->next)
        /* XXX This may request the same font multiple times. */
-       fprintf(fp, "%%%%+ font %s\n", fe->font->name);
+       fprintf(fp, "%%%%+ font %s\n", fe->font->info->name);
     fprintf(fp, "%%%%DocumentSuppliedResources: procset Halibut 0 0\n");
     fprintf(fp, "%%%%EndComments\n");
 
@@ -96,7 +96,7 @@ void ps_backend(paragraph *sourceform, keywordlist *keywords,
 
     for (fe = doc->fonts->head; fe; fe = fe->next)
        /* XXX This may request the same font multiple times. */
-       fprintf(fp, "%%%%IncludeResource: font %s\n", fe->font->name);
+       fprintf(fp, "%%%%IncludeResource: font %s\n", fe->font->info->name);
 
     /*
      * Re-encode the fonts.
@@ -109,7 +109,8 @@ void ps_backend(paragraph *sourceform, keywordlist *keywords,
        sprintf(fname, "f%d", font_index++);
        fe->name = dupstr(fname);
 
-       fprintf(fp, "/%s findfont dup length dict begin\n", fe->font->name);
+       fprintf(fp, "/%s findfont dup length dict begin\n",
+           fe->font->info->name);
        fprintf(fp, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
        fprintf(fp, "/Encoding [\n");
        for (i = 0; i < 256; i++)
diff --git a/error.c b/error.c
index 5575100..f7461ef 100644 (file)
--- a/error.c
+++ b/error.c
@@ -286,6 +286,32 @@ static void do_error(int code, va_list ap) {
        flags = FILEPOS;
        sfree(sp);
        break;
+      case err_afmeof:
+       fpos = *va_arg(ap, filepos *);
+       sprintf(error, "AFM file ended unexpectedly");
+       flags = FILEPOS;
+       break;
+      case err_afmkey:
+       fpos = *va_arg(ap, filepos *);
+       sp = va_arg(ap, char *);
+       sprintf(error, "required AFM key '%.200s' missing", sp);
+       flags = FILEPOS;
+       break;
+      case err_afmvers:
+       fpos = *va_arg(ap, filepos *);
+       sprintf(error, "unsupported AFM version");
+       flags = FILEPOS;
+       break;
+      case err_afmval:
+       fpos = *va_arg(ap, filepos *);
+       sp = va_arg(ap, char *);
+       i = va_arg(ap, int);
+       if (i == 1)
+           sprintf(error, "AFM key '%.200s' requires a value", sp);
+       else
+           sprintf(error, "AFM key '%.200s' requires %d values", sp, i);
+       flags = FILEPOS;
+       break;  
       case err_whatever:
        sp = va_arg(ap, char *);
         vsprintf(error, sp, ap);
index 36ad929..eb62b9e 100644 (file)
--- a/halibut.h
+++ b/halibut.h
@@ -243,7 +243,11 @@ enum {
     err_text_codeline,                /* \c line too long in text backend */
     err_htmlver,                      /* unrecognised HTML version keyword */
     err_charset,                      /* unrecognised character set name */
-    err_nofont,                        /* unrecognised font name */
+    err_nofont,                       /* unrecognised font name */
+    err_afmeof,                       /* eof in AFM file */
+    err_afmkey,                       /* missing expected keyword in AFM */
+    err_afmvers,                      /* unsupported AFM version */
+    err_afmval,                       /* missing value(s) for AFM key */
     err_whatever                       /* random error of another type */
 };
 
@@ -382,6 +386,11 @@ paragraph *cmdline_cfg_simple(char *string, ...);
 paragraph *read_input(input *in, indexdata *idx);
 
 /*
+ * in_afm.c
+ */
+void read_afm_file(input *in);
+
+/*
  * keywords.c
  */
 struct keywordlist_Tag {
diff --git a/in_afm.c b/in_afm.c
new file mode 100644 (file)
index 0000000..0935bf3
--- /dev/null
+++ b/in_afm.c
@@ -0,0 +1,192 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "halibut.h"
+#include "paper.h"
+
+char *afm_read_line(input *in) {
+    int i, len = 256;
+    int c;
+    char *line;
+
+    do {
+       i = 0;
+       in->pos.line++;
+       c = getc(in->currfp);
+       if (c == EOF) {
+           error(err_afmeof, &in->pos);
+           return NULL;
+       }
+       line = snewn(len, char);
+       while (c != EOF && c != '\r' && c != '\n') {
+           if (i >= len - 1) {
+               len += 256;
+               line = sresize(line, len, char);
+           }
+           line[i++] = c;
+           c = getc(in->currfp);
+       }
+       if (c == '\r') {
+           /* Cope with CRLF terminated lines */
+           c = getc(in->currfp);
+           if (c != '\n' && c != EOF)
+               ungetc(c, in->currfp);
+       }
+       line[i] = 0;
+    } while (line[(strspn(line, " \t"))] == 0 ||
+            strncmp(line, "Comment ", 8) == 0 ||
+            strncmp(line, "Comment\t", 8) == 0);
+
+    return line;
+}
+
+static int afm_require_key(char *line, char const *expected, input *in) {
+    char *key = strtok(line, " \t");
+
+    if (strcmp(key, expected) == 0)
+       return TRUE;
+    error(err_afmkey, &in->pos, expected);
+    return FALSE;
+}
+
+void read_afm_file(input *in) {
+    char *line, *key, *val;
+    font_info *fi;
+
+    fi = snew(font_info);
+    fi->name = NULL;
+    fi->nglyphs = 0;
+    fi->glyphs = NULL;
+    fi->widths = NULL;
+    fi->kerns = newtree234(kern_cmp);
+    in->pos.line = 0;
+    line = afm_read_line(in);
+    if (!line || !afm_require_key(line, "StartFontMetrics", in))
+       goto giveup;
+    if (!(val = strtok(NULL, " \t"))) {
+       error(err_afmval, in->pos, "StartFontMetrics", 1);
+       goto giveup;
+    }
+    if (atof(val) >= 5.0) {
+       error(err_afmvers, &in->pos);
+       goto giveup;
+    }
+    sfree(line);
+    for (;;) {
+       line = afm_read_line(in);
+       if (line == NULL)
+           goto giveup;
+       key = strtok(line, " \t");
+       if (strcmp(key, "EndFontMetrics") == 0) {
+           fi->next = all_fonts;
+           all_fonts = fi;
+           fclose(in->currfp);
+           return;
+       } else if (strcmp(key, "FontName") == 0) {
+           if (!(val = strtok(NULL, " \t"))) {
+               error(err_afmval, &in->pos, key, 1);
+               goto giveup;
+           }
+           fi->name = dupstr(val);
+       } else if (strcmp(key, "StartCharMetrics") == 0) {
+           char const **glyphs;
+           int *widths;
+           int i;
+           if (!(val = strtok(NULL, " \t"))) {
+               error(err_afmval, &in->pos, key, 1);
+               goto giveup;
+           }
+           fi->nglyphs = atoi(val);
+           sfree(line);
+           glyphs = snewn(fi->nglyphs, char const *);
+           widths = snewn(fi->nglyphs, int);
+           for (i = 0; i < fi->nglyphs; i++) {
+               glyphs[i] = NULL;
+               line = afm_read_line(in);
+               if (line == NULL)
+                   goto giveup;
+               key = strtok(line, " \t");
+               while (key != NULL) {
+                   if (strcmp(key, "WX") == 0 || strcmp(key, "W0X") == 0) {
+                       if (!(val = strtok(NULL, " \t")) ||
+                           !strcmp(val, ";")) {
+                           error(err_afmval, &in->pos, key, 1);
+                           goto giveup;
+                       }
+                       widths[i] = atoi(val);
+                   } else if (strcmp(key, "N") == 0) {
+                       if (!(val = strtok(NULL, " \t")) ||
+                           !strcmp(val, ";")) {
+                           error(err_afmval, &in->pos, key, 1);
+                           goto giveup;
+                       }
+                       glyphs[i] = dupstr(val);
+                   }
+                   do {
+                       key = strtok(NULL, " \t");
+                   } while (key && strcmp(key, ";"));
+                   key = strtok(NULL, " \t");
+               }
+               sfree(line);
+           }
+           line = afm_read_line(in);
+           if (!line || !afm_require_key(line, "EndCharMetrics", in))
+               goto giveup;
+           sfree(line);
+           fi->glyphs = glyphs;
+           fi->widths = widths;
+
+           for (i = 0; i < fi->nglyphs; i++) {
+               wchar_t ucs;
+               ucs = ps_glyph_to_unicode(fi->glyphs[i]);
+               if (ucs < 0xFFFF)
+                   fi->bmp[ucs] = i;
+           }
+           font_index_glyphs(fi);
+       } else if (strcmp(key, "StartKernPairs") == 0 ||
+                  strcmp(key, "StartKernPairs0") == 0) {
+           int nkerns, i;
+           kern_pair *kerns;
+           if (!(val = strtok(NULL, " \t"))) {
+               error(err_afmval, &in->pos, key, 1);
+               goto giveup;
+           }
+           nkerns = atoi(val);
+           sfree(line);
+           kerns = snewn(nkerns, kern_pair);
+           for (i = 0; i < nkerns; i++) {
+               line = afm_read_line(in);
+               if (line == NULL)
+                   goto giveup;
+               key = strtok(line, " \t");
+               if (strcmp(key, "KPX") == 0) {
+                   char *nl, *nr;
+                   int l, r;
+                   kern_pair *kp;
+                   nl = strtok(NULL, " \t");
+                   nr = strtok(NULL, " \t");
+                   val = strtok(NULL, " \t");
+                   if (!val) {
+                       error(err_afmval, &in->pos, key, 3);
+                       goto giveup;
+                   }
+                   l = find_glyph(fi, nl);
+                   r = find_glyph(fi, nr);
+                   if (l == -1 || r == -1) continue;
+                   kp = snew(kern_pair);
+                   kp->left = l;
+                   kp->right = r;
+                   kp->kern = atoi(val);
+                   add234(fi->kerns, kp);
+               }
+           }
+           line = afm_read_line(in);
+           if (!line || !afm_require_key(line, "EndKernPairs", in))
+               goto giveup;
+           sfree(line);
+       }
+    }
+  giveup:
+    sfree(fi);
+    fclose(in->currfp);
+    return;
+}
diff --git a/input.c b/input.c
index dc44675..6e20488 100644 (file)
--- a/input.c
+++ b/input.c
@@ -1576,7 +1576,11 @@ paragraph *read_input(input *in, indexdata *idx) {
            in->csstate = charset_init_state;
            in->wcpos = in->nwc = 0;
            in->pushback_chars = NULL;
-           read_file(&hptr, in, idx, macros);
+           if (strcmp(in->filenames[in->currindex] +
+                      strlen(in->filenames[in->currindex]) - 4, ".afm") == 0)
+               read_afm_file(in);
+           else
+               read_file(&hptr, in, idx, macros);
        }
        in->currindex++;
     }
diff --git a/paper.h b/paper.h
index 6813fe6..b8d7698 100644 (file)
--- a/paper.h
+++ b/paper.h
@@ -14,6 +14,7 @@
 
 typedef struct document_Tag document;
 typedef struct kern_pair_Tag kern_pair;
+typedef struct font_info_Tag font_info;
 typedef struct font_data_Tag font_data;
 typedef struct font_encoding_Tag font_encoding;
 typedef struct font_list_Tag font_list;
@@ -50,9 +51,15 @@ struct kern_pair_Tag {
 };
 
 /*
- * This data structure represents a particular font.
+ * This data structure holds static information about a font that doesn't
+ * depend on the particular document.  It gets generated when the font's
+ * metrics are read in.
  */
-struct font_data_Tag {
+
+font_info *all_fonts;
+
+struct font_info_Tag {
+    font_info *next;
     /*
      * Specify the PostScript name of the font and its point size.
      */
@@ -65,6 +72,12 @@ struct font_data_Tag {
     int nglyphs;
     const char *const *glyphs;
     const int *widths;
+    /*
+     * Glyph indices sorted into glyph-name order, for name-to-index
+     * mapping.
+     */
+    unsigned short *glyphsbyname;
+    /* A tree of kern_pairs */
     tree234 *kerns;
     /*
      * For reasonably speedy lookup, we set up a 65536-element
@@ -74,6 +87,14 @@ struct font_data_Tag {
      * it), whose elements are indices into the above two arrays.
      */
     unsigned short bmp[65536];
+};
+
+/*
+ * This structure holds the information about how a font is used
+ * in a document.
+ */
+struct font_data_Tag {
+    font_info const *info;
     /*
      * At some point I'm going to divide the font into sub-fonts
      * with largely non-overlapping encoding vectors. This array
@@ -318,10 +339,19 @@ struct outline_element_Tag {
 };
 
 /*
+ * Functions exported from bk_paper.c
+ */
+int kern_cmp(void *, void *); /* use when setting up kern_pairs */
+void font_index_glyphs(font_info *fi);
+int find_glyph(font_info *fi, char const *name);
+
+
+/*
  * Functions and data exported from psdata.c.
  */
 wchar_t ps_glyph_to_unicode(char const *glyph);
 extern const char *const ps_std_glyphs[];
+void init_std_fonts(void);
 const int *ps_std_font_widths(char const *fontname);
 const kern_pair *ps_std_font_kerns(char const *fontname);
 
index f1d72cd..68ee58c 100644 (file)
--- a/psdata.c
+++ b/psdata.c
@@ -3,6 +3,7 @@
  * formats.
  */
 
+#include <assert.h>
 #include "halibut.h"
 #include "paper.h"
 
@@ -4086,6 +4087,35 @@ static const struct ps_std_font_data {
     }},
 };
 
+void init_std_fonts(void) {
+    int i, j;
+    kern_pair const *kern;
+    static int done = FALSE;
+
+    if (done) return;
+    for (i = 0; i < (int)lenof(ps_std_fonts); i++) {
+       font_info *fi = snew(font_info);
+       fi->name = ps_std_fonts[i].name;
+       fi->nglyphs = lenof(ps_std_glyphs) - 1;
+       fi->glyphs = ps_std_glyphs;
+       fi->widths = ps_std_fonts[i].widths;
+       fi->kerns = newtree234(kern_cmp);
+       for (kern = ps_std_fonts[i].kerns; kern->left != 0xFFFF; kern++)
+           add234(fi->kerns, (void *)kern);
+       for (j = 0; j < (int)lenof(fi->bmp); j++)
+           fi->bmp[j] = 0xFFFF;
+       for (j = 0; j < fi->nglyphs; j++) {
+           wchar_t ucs;
+           ucs = ps_glyph_to_unicode(fi->glyphs[j]);
+           assert(ucs != 0xFFFF);
+           fi->bmp[ucs] = j;
+       }
+       fi->next = all_fonts;
+       all_fonts = fi;
+    }
+    done = TRUE;
+}
+
 const int *ps_std_font_widths(char const *fontname)
 {
     int i;