hyph: .hcode should behave like .tr
[neatroff.git] / font.c
blob857f51ca5fa16110c2d6adbe4e0e3cfd21f0c3ea
1 /* font handling */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "roff.h"
7 /* find a glyph by its name */
8 struct glyph *font_find(struct font *fn, char *name)
10 int i = dict_get(&fn->cdict, name);
11 if (i < 0)
12 return NULL;
13 return fn->g_map[i] ? fn->g_map[i] : fn->g[i];
16 /* find a glyph by its device-dependent identifier */
17 struct glyph *font_glyph(struct font *fn, char *id)
19 int i = dict_get(&fn->gdict, id);
20 return i >= 0 ? &fn->glyphs[i] : NULL;
23 static struct glyph *font_glyphput(struct font *fn, char *id, char *name, int type)
25 int i = fn->nglyphs++;
26 struct glyph *g;
27 g = &fn->glyphs[i];
28 strcpy(g->id, id);
29 strcpy(g->name, name);
30 g->type = type;
31 g->font = fn;
32 dict_put(&fn->gdict, g->id, i);
33 return g;
36 /* map character name to the given glyph */
37 int font_map(struct font *fn, char *name, struct glyph *g)
39 int i = dict_get(&fn->cdict, name);
40 if (g && g->font != fn)
41 return 1;
42 if (i < 0) {
43 if (fn->n >= NGLYPHS)
44 return 1;
45 i = fn->n++;
46 strcpy(fn->c[i], name);
47 dict_put(&fn->cdict, fn->c[i], i);
49 fn->g_map[i] = g;
50 return 0;
53 /* return nonzero if character name has been mapped with font_map() */
54 int font_mapped(struct font *fn, char *name)
56 int i = dict_get(&fn->cdict, name);
57 return i >= 0 && fn->g_map[i];
60 /* glyph index in fn->glyphs[] */
61 static int font_idx(struct font *fn, struct glyph *g)
63 return g ? g - fn->glyphs : -1;
67 * Given a list of characters in the reverse order, font_lig()
68 * returns the number of characters from the beginning of this
69 * list that form a ligature in this font. Zero naturally means
70 * no ligature was matched.
72 int font_lig(struct font *fn, char **c, int n)
74 int i;
75 /* concatenated characters in c[], in the correct order */
76 char s[GNLEN * 2] = "";
77 /* b[i] is the number of character of c[] in s + i */
78 int b[GNLEN * 2] = {0};
79 int len = 0;
80 for (i = 0; i < n; i++) {
81 char *cur = c[n - i - 1];
82 b[len] = n - i;
83 strcpy(s + len, cur);
84 len += strlen(cur);
86 for (i = 0; i < fn->lgn; i++) {
87 int l = strlen(fn->lg[i]);
88 if (b[len - l] > 1 && !strcmp(s + len - l, fn->lg[i]))
89 if (font_find(fn, fn->lg[i]))
90 return b[len - l];
92 return 0;
95 /* return nonzero if s is a ligature */
96 int font_islig(struct font *fn, char *s)
98 int i;
99 for (i = 0; i < fn->lgn; i++)
100 if (!strcmp(s, fn->lg[i]))
101 return 1;
102 return 0;
105 /* return pairwise kerning value between c1 and c2 */
106 int font_kern(struct font *fn, char *c1, char *c2)
108 int i1, i2, i;
109 i1 = font_idx(fn, font_find(fn, c1));
110 i2 = font_idx(fn, font_find(fn, c2));
111 if (i1 < 0 || i2 < 0)
112 return 0;
113 i = fn->knhead[i1];
114 while (i >= 0) {
115 if (fn->knpair[i] == i2)
116 return fn->knval[i];
117 i = fn->knnext[i];
119 return 0;
122 static int font_readchar(struct font *fn, FILE *fin)
124 char tok[ILNLEN];
125 char name[ILNLEN];
126 char id[ILNLEN];
127 struct glyph *glyph = NULL;
128 int type;
129 if (fn->n >= NGLYPHS)
130 return 1;
131 if (fscanf(fin, "%s %s", name, tok) != 2)
132 return 1;
133 if (!strcmp("---", name))
134 sprintf(name, "c%04d", fn->n);
135 if (!strcmp("\"", tok)) {
136 glyph = fn->g[fn->n - 1];
137 } else {
138 if (fscanf(fin, "%d %s", &type, id) != 2)
139 return 1;
140 glyph = font_glyph(fn, id);
141 if (!glyph) {
142 glyph = font_glyphput(fn, id, name, type);
143 sscanf(tok, "%d,%d,%d,%d,%d", &glyph->wid,
144 &glyph->llx, &glyph->lly, &glyph->urx, &glyph->ury);
147 strcpy(fn->c[fn->n], name);
148 fn->g[fn->n] = glyph;
149 dict_put(&fn->cdict, fn->c[fn->n], fn->n);
150 fn->n++;
151 return 0;
154 static int font_readkern(struct font *fn, FILE *fin)
156 char c1[ILNLEN], c2[ILNLEN];
157 int i1, i2, val;
158 if (fscanf(fin, "%s %s %d", c1, c2, &val) != 3)
159 return 1;
160 i1 = font_idx(fn, font_glyph(fn, c1));
161 i2 = font_idx(fn, font_glyph(fn, c2));
162 if (fn->knn < NKERNS && i1 >= 0 && i2 >= 0) {
163 fn->knnext[fn->knn] = fn->knhead[i1];
164 fn->knhead[i1] = fn->knn;
165 fn->knval[fn->knn] = val;
166 fn->knpair[fn->knn] = i2;
167 fn->knn++;
169 return 0;
172 static void skipline(FILE* filp)
174 int c;
175 do {
176 c = getc(filp);
177 } while (c != '\n' && c != EOF);
180 struct font *font_open(char *path)
182 struct font *fn;
183 char tok[ILNLEN];
184 FILE *fin;
185 int i;
186 fin = fopen(path, "r");
187 if (!fin)
188 return NULL;
189 fn = xmalloc(sizeof(*fn));
190 if (!fn) {
191 fclose(fin);
192 return NULL;
194 memset(fn, 0, sizeof(*fn));
195 dict_init(&fn->gdict, NGLYPHS, -1, 0, 0);
196 dict_init(&fn->cdict, NGLYPHS, -1, 0, 0);
197 for (i = 0; i < LEN(fn->knhead); i++)
198 fn->knhead[i] = -1;
199 while (fscanf(fin, "%s", tok) == 1) {
200 if (!strcmp("char", tok)) {
201 font_readchar(fn, fin);
202 } else if (!strcmp("kern", tok)) {
203 font_readkern(fn, fin);
204 } else if (!strcmp("spacewidth", tok)) {
205 fscanf(fin, "%d", &fn->spacewid);
206 } else if (!strcmp("special", tok)) {
207 fn->special = 1;
208 } else if (!strcmp("name", tok)) {
209 fscanf(fin, "%s", fn->name);
210 } else if (!strcmp("fontname", tok)) {
211 fscanf(fin, "%s", fn->fontname);
212 } else if (!strcmp("ligatures", tok)) {
213 while (fscanf(fin, "%s", tok) == 1) {
214 if (!strcmp("0", tok))
215 break;
216 if (fn->lgn < NLIGS)
217 strcpy(fn->lg[fn->lgn++], tok);
219 } else if (!strcmp("charset", tok)) {
220 while (!font_readchar(fn, fin))
222 break;
224 skipline(fin);
226 fclose(fin);
227 return fn;
230 void font_close(struct font *fn)
232 free(fn);