ref: 9ea76ed72cf02518746e3b0ea9ae29570e19ce2e
dir: /font.c/
/* font handling */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "roff.h" struct font { char name[FNLEN]; char fontname[FNLEN]; struct glyph glyphs[NGLYPHS]; int nglyphs; int spacewid; int special; int cs, bd; /* for .cs and .bd requests */ struct dict gdict; /* mapping from glyphs[i].id to i */ /* charset section characters */ char c[NGLYPHS][GNLEN]; /* character names in charset */ struct glyph *g[NGLYPHS]; /* character glyphs in charset */ struct glyph *g_map[NGLYPHS]; /* character remapped via font_map() */ int n; /* number of characters in charset */ struct dict cdict; /* mapping from c[i] to i */ /* font ligatures (lg*) */ char lg[NLIGS][LIGLEN * GNLEN]; /* ligatures */ int lgn; /* number of ligatures in lg[] */ /* kerning pair table per glyph (kn*) */ int knhead[NGLYPHS]; /* kerning pairs of glyphs[] */ int knnext[NKERNS]; /* next item in knhead[] list */ int knpair[NKERNS]; /* kerning pair 2nd glyphs */ int knval[NKERNS]; /* font pairwise kerning value */ int knn; /* number of kerning pairs */ }; /* find a glyph by its name */ struct glyph *font_find(struct font *fn, char *name) { int i = dict_get(&fn->cdict, name); if (i < 0) return NULL; return fn->g_map[i] ? fn->g_map[i] : fn->g[i]; } /* find a glyph by its device-dependent identifier */ struct glyph *font_glyph(struct font *fn, char *id) { int i = dict_get(&fn->gdict, id); return i >= 0 ? &fn->glyphs[i] : NULL; } static struct glyph *font_glyphput(struct font *fn, char *id, char *name, int type) { int i = fn->nglyphs++; struct glyph *g; g = &fn->glyphs[i]; strcpy(g->id, id); strcpy(g->name, name); g->type = type; g->font = fn; dict_put(&fn->gdict, g->id, i); return g; } /* map character name to the given glyph */ int font_map(struct font *fn, char *name, struct glyph *g) { int i = dict_get(&fn->cdict, name); if (g && g->font != fn) return 1; if (i < 0) { if (fn->n >= NGLYPHS) return 1; i = fn->n++; strcpy(fn->c[i], name); dict_put(&fn->cdict, fn->c[i], i); } fn->g_map[i] = g; return 0; } /* return nonzero if character name has been mapped with font_map() */ int font_mapped(struct font *fn, char *name) { int i = dict_get(&fn->cdict, name); return i >= 0 && fn->g_map[i]; } /* glyph index in fn->glyphs[] */ static int font_idx(struct font *fn, struct glyph *g) { return g ? g - fn->glyphs : -1; } /* * If the first m characters of src form a ligature, return n and * copy the ligature to lig. */ int font_lig(struct font *fn, char *lig, char src[][GNLEN], int n) { char cat[GNLEN * 2] = ""; int cmap[GNLEN * 2] = {0}; int i, l; for (i = 0; i < n && i < LIGLEN && strlen(cat) < GNLEN; i++) { strcat(cat, src[i]); cmap[strlen(cat)] = i; } for (i = 0; i < fn->lgn; i++) { l = strlen(fn->lg[i]); if (cmap[l] && !strncmp(cat, fn->lg[i], l)) { if (font_find(fn, fn->lg[i])) { memcpy(lig, cat, l); lig[l] = '\0'; return cmap[l] + 1; } } } return 0; } /* return nonzero if s is a ligature */ int font_islig(struct font *fn, char *s) { int i; for (i = 0; i < fn->lgn; i++) if (!strcmp(s, fn->lg[i])) return 1; return 0; } /* return pairwise kerning value between c1 and c2 */ int font_kern(struct font *fn, char *c1, char *c2) { int i1, i2, i; i1 = font_idx(fn, font_find(fn, c1)); i2 = font_idx(fn, font_find(fn, c2)); if (i1 < 0 || i2 < 0) return 0; i = fn->knhead[i1]; while (i >= 0) { if (fn->knpair[i] == i2) return fn->knval[i]; i = fn->knnext[i]; } return 0; } static int font_readchar(struct font *fn, FILE *fin) { char tok[ILNLEN]; char name[ILNLEN]; char id[ILNLEN]; struct glyph *glyph = NULL; int type; if (fn->n >= NGLYPHS) return 1; if (fscanf(fin, "%s %s", name, tok) != 2) return 1; if (!strcmp("---", name)) sprintf(name, "c%04d", fn->n); if (!strcmp("\"", tok)) { glyph = fn->g[fn->n - 1]; } else { if (fscanf(fin, "%d %s", &type, id) != 2) return 1; glyph = font_glyph(fn, id); if (!glyph) { glyph = font_glyphput(fn, id, name, type); sscanf(tok, "%d,%d,%d,%d,%d", &glyph->wid, &glyph->llx, &glyph->lly, &glyph->urx, &glyph->ury); } } strcpy(fn->c[fn->n], name); fn->g[fn->n] = glyph; dict_put(&fn->cdict, fn->c[fn->n], fn->n); fn->n++; return 0; } static int font_readkern(struct font *fn, FILE *fin) { char c1[ILNLEN], c2[ILNLEN]; int i1, i2, val; if (fscanf(fin, "%s %s %d", c1, c2, &val) != 3) return 1; i1 = font_idx(fn, font_glyph(fn, c1)); i2 = font_idx(fn, font_glyph(fn, c2)); if (fn->knn < NKERNS && i1 >= 0 && i2 >= 0) { fn->knnext[fn->knn] = fn->knhead[i1]; fn->knhead[i1] = fn->knn; fn->knval[fn->knn] = val; fn->knpair[fn->knn] = i2; fn->knn++; } return 0; } static void skipline(FILE* filp) { int c; do { c = getc(filp); } while (c != '\n' && c != EOF); } struct font *font_open(char *path) { struct font *fn; char tok[ILNLEN]; FILE *fin; int i; fin = fopen(path, "r"); if (!fin) return NULL; fn = xmalloc(sizeof(*fn)); if (!fn) { fclose(fin); return NULL; } memset(fn, 0, sizeof(*fn)); dict_init(&fn->gdict, NGLYPHS, -1, 0, 0); dict_init(&fn->cdict, NGLYPHS, -1, 0, 0); for (i = 0; i < LEN(fn->knhead); i++) fn->knhead[i] = -1; while (fscanf(fin, "%s", tok) == 1) { if (!strcmp("char", tok)) { font_readchar(fn, fin); } else if (!strcmp("kern", tok)) { font_readkern(fn, fin); } else if (!strcmp("spacewidth", tok)) { fscanf(fin, "%d", &fn->spacewid); } else if (!strcmp("special", tok)) { fn->special = 1; } else if (!strcmp("name", tok)) { fscanf(fin, "%s", fn->name); } else if (!strcmp("fontname", tok)) { fscanf(fin, "%s", fn->fontname); } else if (!strcmp("ligatures", tok)) { while (fscanf(fin, "%s", tok) == 1) { if (!strcmp("0", tok)) break; if (fn->lgn < NLIGS) strcpy(fn->lg[fn->lgn++], tok); } } else if (!strcmp("charset", tok)) { while (!font_readchar(fn, fin)) ; break; } skipline(fin); } fclose(fin); return fn; } void font_close(struct font *fn) { dict_done(&fn->gdict); dict_done(&fn->cdict); free(fn); } int font_special(struct font *fn) { return fn->special; } int font_spacewid(struct font *fn) { return fn->spacewid; } int font_getcs(struct font *fn) { return fn->cs; } void font_setcs(struct font *fn, int cs) { fn->cs = cs; } int font_getbd(struct font *fn) { return fn->bd; } void font_setbd(struct font *fn, int bd) { fn->bd = bd; }