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
#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
+#include <stdlib.h>
#include "halibut.h"
#include "paper.h"
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);
* 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);
}
paragraph index_placeholder_para;
page_data *first_index_page;
+ init_std_fonts();
fontlist = snew(font_list);
fontlist->head = fontlist->tail = NULL;
return fe;
}
-static int kern_cmp(void *a, void *b)
+int kern_cmp(void *a, void *b)
{
kern_pair const *ka = a, *kb = 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);
/*
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;
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;
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;
}
while (*str) {
oglyph = glyph;
glyph = (*str < 0 || *str > 0xFFFF ? 0xFFFF :
- font->bmp[*str]);
+ font->info->bmp[*str]);
if (glyph == 0xFFFF) {
str++;
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;
}
text[textpos++] = font->subfont_map[glyph].position;
- textwid += font->widths[glyph] * fontsize;
+ textwid += font->info->widths[glyph] * fontsize;
str++;
}
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++) {
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);
}
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");
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.
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++)
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);
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 */
};
paragraph *read_input(input *in, indexdata *idx);
/*
+ * in_afm.c
+ */
+void read_afm_file(input *in);
+
+/*
* keywords.c
*/
struct keywordlist_Tag {
--- /dev/null
+#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;
+}
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++;
}
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;
};
/*
- * 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.
*/
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
* 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
};
/*
+ * 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);
* formats.
*/
+#include <assert.h>
#include "halibut.h"
#include "paper.h"
}},
};
+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;