diff options
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | bk_paper.c | 141 | ||||
| -rw-r--r-- | bk_pdf.c | 4 | ||||
| -rw-r--r-- | bk_ps.c | 7 | ||||
| -rw-r--r-- | error.c | 26 | ||||
| -rw-r--r-- | halibut.h | 11 | ||||
| -rw-r--r-- | in_afm.c | 192 | ||||
| -rw-r--r-- | input.c | 6 | ||||
| -rw-r--r-- | paper.h | 34 | ||||
| -rw-r--r-- | psdata.c | 30 |
10 files changed, 388 insertions, 65 deletions
@@ -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 @@ -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++; } @@ -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); } @@ -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++) @@ -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); @@ -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 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; +} @@ -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++; } @@ -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); @@ -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; |