diff options
| author | Ben Harris <bjh21@bjh21.me.uk> | 2006-05-13 13:56:05 +0000 |
|---|---|---|
| committer | Ben Harris <bjh21@bjh21.me.uk> | 2006-05-13 13:56:05 +0000 |
| commit | c072eb7debe80aca352a5dc26bff08a6ecd8baff (patch) | |
| tree | 18c4cff9d3257803ec49535179ead154ffd3a4c6 /in_afm.c | |
| parent | 1d9065a073a8f8ac707a6fa2e7683755f1b82df0 (diff) | |
| download | halibut-c072eb7debe80aca352a5dc26bff08a6ecd8baff.zip halibut-c072eb7debe80aca352a5dc26bff08a6ecd8baff.tar.gz halibut-c072eb7debe80aca352a5dc26bff08a6ecd8baff.tar.bz2 halibut-c072eb7debe80aca352a5dc26bff08a6ecd8baff.tar.xz | |
Initial support for adding fonts at run-time. Currently we only support
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.
[originally from svn r6681]
Diffstat (limited to 'in_afm.c')
| -rw-r--r-- | in_afm.c | 192 |
1 files changed, 192 insertions, 0 deletions
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; +} |