cp: the zero-th argument
[neatroff.git] / font.c
blobeab51c65871beb06e83ad3ea801b584d37dabdea
1 /* font handling */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "roff.h"
7 /* convert wid in device unitwidth size to size sz */
8 #define DEVWID(sz, wid) (((wid) * (sz) + (dev_uwid / 2)) / dev_uwid)
10 /* flags for gpat->flg */
11 #define GF_PAT 1 /* gsub/gpos pattern glyph */
12 #define GF_REP 2 /* gsub replacement glyph */
13 #define GF_CON 4 /* context glyph */
14 #define GF_GRP 8 /* glyph group */
16 /* glyph substitution and positioning rules */
17 struct grule {
18 struct gpat { /* rule description */
19 short g; /* glyph index */
20 short flg; /* pattern flags; GF_* */
21 short x, y, xadv, yadv; /* gpos data */
22 } *pats; /* rule pattern */
23 short len; /* pats[] length */
24 short feat, scrp; /* rule's feature and script */
27 struct font {
28 char name[FNLEN];
29 char fontname[FNLEN];
30 int spacewid;
31 int special;
32 int cs, cs_ps, bd, zoom; /* for .cs, .bd, .fzoom requests */
33 int s1, n1, s2, n2; /* for .tkf request */
34 struct glyph *gl; /* glyphs present in the font */
35 int gl_n, gl_sz; /* number of glyphs in the font */
36 struct dict *gl_dict; /* mapping from gl[i].id to i */
37 struct dict *ch_dict; /* charset mapping */
38 struct dict *ch_map; /* characters mapped via font_map() */
39 /* font features and scripts */
40 char feat_name[NFEATS][8]; /* feature names */
41 int feat_set[NFEATS]; /* feature enabled */
42 char scrp_name[NSCRPS][8]; /* script names */
43 int scrp; /* current script */
44 /* glyph substitution and positioning */
45 struct grule *gsub; /* glyph substitution rules */
46 int gsub_n, gsub_sz;
47 struct grule *gpos; /* glyph positioning rules */
48 int gpos_n, gpos_sz;
49 struct iset *gsub0; /* rules matching a glyph at pos 0 */
50 struct iset *gpos0; /* rules matching a glyph at pos 0 */
51 struct iset *ggrp; /* glyph groups */
54 /* find a glyph by its name */
55 struct glyph *font_find(struct font *fn, char *name)
57 int i = dict_get(fn->ch_map, name);
58 if (i == -1) /* -2 means the glyph has been unmapped */
59 i = dict_get(fn->ch_dict, name);
60 return i >= 0 ? fn->gl + i : NULL;
63 /* find a glyph by its device-dependent identifier */
64 struct glyph *font_glyph(struct font *fn, char *id)
66 int i = dict_get(fn->gl_dict, id);
67 return i >= 0 ? &fn->gl[i] : NULL;
70 static int font_glyphput(struct font *fn, char *id, char *name, int type)
72 struct glyph *g;
73 if (fn->gl_n == fn->gl_sz) {
74 fn->gl_sz = fn->gl_sz + 1024;
75 fn->gl = mextend(fn->gl, fn->gl_n, fn->gl_sz, sizeof(fn->gl[0]));
77 g = &fn->gl[fn->gl_n];
78 snprintf(g->id, sizeof(g->id), "%s", id);
79 snprintf(g->name, sizeof(g->name), "%s", name);
80 g->type = type;
81 g->font = fn;
82 dict_put(fn->gl_dict, g->id, fn->gl_n);
83 return fn->gl_n++;
86 /* map character name to the given glyph; remove the mapping if id is NULL */
87 int font_map(struct font *fn, char *name, char *id)
89 int gidx = -1;
90 if (id)
91 gidx = font_glyph(fn, id) ? font_glyph(fn, id) - fn->gl : -2;
92 dict_put(fn->ch_map, name, gidx);
93 return 0;
96 /* return nonzero if character name has been mapped with font_map() */
97 int font_mapped(struct font *fn, char *name)
99 return dict_get(fn->ch_map, name) != -1;
102 static int font_findfeat(struct font *fn, char *feat);
104 /* enable/disable ligatures; first bit for liga and the second bit for rlig */
105 static int font_featlg(struct font *fn, int val)
107 int ret = 0;
108 ret |= font_feat(fn, "liga", val & 1);
109 ret |= font_feat(fn, "rlig", val & 2) << 1;
110 return ret;
113 /* enable/disable pairwise kerning */
114 static int font_featkn(struct font *fn, int val)
116 return font_feat(fn, "kern", val);
119 /* glyph index in fn->glyphs[] */
120 static int font_idx(struct font *fn, struct glyph *g)
122 return g ? g - fn->gl : -1;
125 static int font_gpatmatch(struct font *fn, struct gpat *p, int g)
127 int *r;
128 if (!(p->flg & GF_GRP))
129 return p->g == g;
130 r = iset_get(fn->ggrp, p->g);
131 while (r && *r >= 0)
132 if (*r++ == g)
133 return 1;
134 return 0;
137 static int font_rulematch(struct font *fn, struct grule *rule,
138 int *src, int slen, int *dst, int dlen)
140 int sidx = 0; /* the index of matched glyphs in src */
141 int ncon = 0; /* number of initial context glyphs */
142 struct gpat *pats = rule->pats;
143 int j;
144 if (fn->scrp >= 0 && fn->scrp != rule->scrp)
145 return 0;
146 if (!fn->feat_set[rule->feat])
147 return 0;
148 /* the number of initial context glyphs */
149 for (j = 0; j < rule->len && pats[j].flg & GF_CON; j++)
150 ncon++;
151 if (dlen < ncon)
152 return 0;
153 /* matching the base pattern */
154 for (; j < rule->len; j++) {
155 if (pats[j].flg & GF_REP)
156 continue;
157 if (sidx >= slen || !font_gpatmatch(fn, &pats[j], src[sidx]))
158 return 0;
159 sidx++;
161 /* matching the initial context */
162 for (j = 0; j < rule->len && pats[j].flg & GF_CON; j++)
163 if (!font_gpatmatch(fn, &pats[j], dst[j - ncon]))
164 return 0;
165 return 1;
168 /* find a matching gsub/gpos rule; *idx should be -1 initially */
169 static int font_findrule(struct font *fn, int gsub, int pos,
170 int *fwd, int fwdlen, int *ctx, int ctxlen, int *idx)
172 struct grule *rules = gsub ? fn->gsub : fn->gpos;
173 int *r1 = iset_get(gsub ? fn->gsub0 : fn->gpos0, fwd[0]);
174 while (r1 && r1[++*idx] >= 0) {
175 if (r1[*idx] >= pos && font_rulematch(fn, &rules[r1[*idx]],
176 fwd, fwdlen, ctx, ctxlen))
177 return r1[*idx];
179 return -1;
182 /* perform all possible gpos rules on src */
183 static void font_performgpos(struct font *fn, int *src, int slen,
184 int *x, int *y, int *xadv, int *yadv)
186 struct grule *gpos = fn->gpos;
187 struct gpat *pats;
188 int curs_feat = dir_do ? font_findfeat(fn, "curs") : -1;
189 int curs_beg = -1;
190 int curs_dif = 0;
191 int i, k;
192 for (i = 0; i < slen; i++) {
193 int idx = -1;
194 int curs_cur = 0;
195 while (1) {
196 int r = font_findrule(fn, 0, 0, src + i, slen - i,
197 src + i, i, &idx);
198 if (r < 0)
199 break;
200 pats = gpos[r].pats;
201 for (k = 0; k < gpos[r].len; k++) {
202 x[i + k] += pats[k].x;
203 y[i + k] += pats[k].y;
204 xadv[i + k] += pats[k].xadv;
205 yadv[i + k] += pats[k].yadv;
207 if (gpos[r].feat == curs_feat) {
208 curs_cur = 1;
209 if (curs_beg < 0)
210 curs_beg = i;
211 for (k = 0; k < gpos[r].len; k++)
212 curs_dif += pats[k].yadv;
215 if (curs_beg >= 0 && !curs_cur) {
216 yadv[curs_beg] -= curs_dif;
217 curs_beg = -1;
218 curs_dif = 0;
221 if (curs_beg >= 0)
222 yadv[curs_beg] -= curs_dif;
225 /* find the first gsub rule after pos that matches any glyph in src */
226 static int font_firstgsub(struct font *fn, int pos, int *src, int slen)
228 int best = -1;
229 int i;
230 for (i = 0; i < slen; i++) {
231 int idx = -1;
232 int r = font_findrule(fn, 1, pos, src + i, slen - i,
233 src + i, i, &idx);
234 if (r >= 0 && (best < 0 || r < best))
235 best = r;
237 return best;
240 /* apply the given gsub rule to all matches in src */
241 static int font_gsubapply(struct font *fn, struct grule *rule,
242 int *src, int slen, int *smap)
244 int dst[WORDLEN];
245 int dlen = 0;
246 int dmap[WORDLEN];
247 int i, j;
248 memset(dmap, 0, slen * sizeof(dmap[i]));
249 for (i = 0; i < slen; i++) {
250 dmap[dlen] = smap[i];
251 if (font_rulematch(fn, rule, src + i, slen - i,
252 dst + dlen, dlen)) {
253 for (j = 0; j < rule->len; j++) {
254 if (rule->pats[j].flg & GF_REP)
255 dst[dlen++] = rule->pats[j].g;
256 if (rule->pats[j].flg & GF_PAT)
257 i++;
259 i--;
260 } else {
261 dst[dlen++] = src[i];
264 memcpy(src, dst, dlen * sizeof(dst[0]));
265 memcpy(smap, dmap, dlen * sizeof(dmap[0]));
266 return dlen;
269 /* perform all possible gsub rules on src */
270 static int font_performgsub(struct font *fn, int *src, int slen, int *smap)
272 int i = -1;
273 while (++i >= 0) {
274 if ((i = font_firstgsub(fn, i, src, slen)) < 0)
275 break;
276 slen = font_gsubapply(fn, &fn->gsub[i], src, slen, smap);
278 return slen;
281 int font_layout(struct font *fn, struct glyph **gsrc, int nsrc, int sz,
282 struct glyph **gdst, int *dmap,
283 int *x, int *y, int *xadv, int *yadv, int lg, int kn)
285 int dst[WORDLEN];
286 int ndst = nsrc;
287 int i;
288 int featlg, featkn;
289 /* initialising dst */
290 for (i = 0; i < nsrc; i++)
291 dst[i] = font_idx(fn, gsrc[i]);
292 for (i = 0; i < ndst; i++)
293 dmap[i] = i;
294 memset(x, 0, ndst * sizeof(x[0]));
295 memset(y, 0, ndst * sizeof(y[0]));
296 memset(xadv, 0, ndst * sizeof(xadv[0]));
297 memset(yadv, 0, ndst * sizeof(yadv[0]));
298 /* substitution rules */
299 if (lg)
300 featlg = font_featlg(fn, 3);
301 ndst = font_performgsub(fn, dst, ndst, dmap);
302 if (lg)
303 font_featlg(fn, featlg);
304 /* positioning rules */
305 if (kn)
306 featkn = font_featkn(fn, 1);
307 font_performgpos(fn, dst, ndst, x, y, xadv, yadv);
308 if (kn)
309 font_featkn(fn, featkn);
310 for (i = 0; i < ndst; i++)
311 gdst[i] = fn->gl + dst[i];
312 return ndst;
315 static int font_readchar(struct font *fn, FILE *fin, int *n, int *gid)
317 struct glyph *g;
318 char tok[ILNLEN];
319 char name[ILNLEN];
320 char id[ILNLEN];
321 int type;
322 if (fscanf(fin, "%s %s", name, tok) != 2)
323 return 1;
324 if (!strcmp("---", name))
325 sprintf(name, "c%04d", *n);
326 if (strcmp("\"", tok)) {
327 if (fscanf(fin, "%d %s", &type, id) != 2)
328 return 1;
329 *gid = dict_get(fn->gl_dict, id);
330 if (*gid < 0) {
331 *gid = font_glyphput(fn, id, name, type);
332 g = &fn->gl[*gid];
333 sscanf(tok, "%hd,%hd,%hd,%hd,%hd", &g->wid,
334 &g->llx, &g->lly, &g->urx, &g->ury);
336 dict_put(fn->ch_dict, name, *gid);
337 (*n)++;
338 } else {
339 dict_put(fn->ch_map, name, *gid);
341 return 0;
344 static int font_findfeat(struct font *fn, char *feat)
346 int i;
347 for (i = 0; i < LEN(fn->feat_name) && fn->feat_name[i][0]; i++)
348 if (!strcmp(feat, fn->feat_name[i]))
349 return i;
350 if (i < LEN(fn->feat_name)) {
351 snprintf(fn->feat_name[i], sizeof(fn->feat_name[i]), "%s", feat);
352 return i;
354 return -1;
357 static int font_findscrp(struct font *fn, char *scrp)
359 int i;
360 for (i = 0; i < LEN(fn->scrp_name) && fn->scrp_name[i][0]; i++)
361 if (!strcmp(scrp, fn->scrp_name[i]))
362 return i;
363 if (i < LEN(fn->scrp_name)) {
364 snprintf(fn->scrp_name[i], sizeof(fn->scrp_name[i]), "%s", scrp);
365 return i;
367 return -1;
370 static struct gpat *font_gpat(struct font *fn, int len)
372 struct gpat *pats = xmalloc(len * sizeof(pats[0]));
373 memset(pats, 0, len * sizeof(pats[0]));
374 return pats;
377 static struct grule *font_gsub(struct font *fn, int len, int feat, int scrp)
379 struct grule *rule;
380 struct gpat *pats = font_gpat(fn, len);
381 if (fn->gsub_n == fn->gsub_sz) {
382 fn->gsub_sz = fn->gsub_sz + 1024;
383 fn->gsub = mextend(fn->gsub, fn->gsub_n, fn->gsub_sz,
384 sizeof(fn->gsub[0]));
386 rule = &fn->gsub[fn->gsub_n++];
387 rule->pats = pats;
388 rule->len = len;
389 rule->feat = feat;
390 rule->scrp = scrp;
391 return rule;
394 static struct grule *font_gpos(struct font *fn, int len, int feat, int scrp)
396 struct grule *rule;
397 struct gpat *pats = font_gpat(fn, len);
398 if (fn->gpos_n == fn->gpos_sz) {
399 fn->gpos_sz = fn->gpos_sz + 1024;
400 fn->gpos = mextend(fn->gpos, fn->gpos_n, fn->gpos_sz,
401 sizeof(fn->gpos[0]));
403 rule = &fn->gpos[fn->gpos_n++];
404 rule->pats = pats;
405 rule->len = len;
406 rule->feat = feat;
407 rule->scrp = scrp;
408 return rule;
411 static int font_readgpat(struct font *fn, struct gpat *p, char *s)
413 if (s[0] == '@') {
414 p->g = atoi(s + 1);
415 if (iset_len(fn->ggrp, p->g) == 1)
416 p->g = iset_get(fn->ggrp, p->g)[0];
417 else
418 p->flg |= GF_GRP;
419 } else {
420 p->g = font_idx(fn, font_glyph(fn, s));
422 return p->g < 0;
425 static void font_readfeat(struct font *fn, char *tok, int *feat, int *scrp)
427 *scrp = -1;
428 if (strchr(tok, ':')) { /* "feature:script" */
429 *scrp = font_findscrp(fn, strchr(tok, ':') + 1);
430 strchr(tok, ':')[0] = '\0';
432 *feat = font_findfeat(fn, tok);
435 static int font_readgsub(struct font *fn, FILE *fin)
437 char tok[128];
438 struct grule *rule;
439 int feat, scrp;
440 int i, n;
441 if (fscanf(fin, "%s %d", tok, &n) != 2)
442 return 1;
443 font_readfeat(fn, tok, &feat, &scrp);
444 rule = font_gsub(fn, n, feat, scrp);
445 for (i = 0; i < n; i++) {
446 if (fscanf(fin, "%s", tok) != 1)
447 return 1;
448 if (tok[0] == '-')
449 rule->pats[i].flg = GF_PAT;
450 if (tok[0] == '=')
451 rule->pats[i].flg = GF_CON;
452 if (tok[0] == '+')
453 rule->pats[i].flg = GF_REP;
454 if (!tok[0] || font_readgpat(fn, &rule->pats[i], tok + 1))
455 return 0;
457 return 0;
460 static int font_readgpos(struct font *fn, FILE *fin)
462 char tok[128];
463 char *col;
464 struct grule *rule;
465 int feat, scrp;
466 int i, n;
467 if (fscanf(fin, "%s %d", tok, &n) != 2)
468 return 1;
469 font_readfeat(fn, tok, &feat, &scrp);
470 rule = font_gpos(fn, n, feat, scrp);
471 for (i = 0; i < n; i++) {
472 if (fscanf(fin, "%s", tok) != 1)
473 return 1;
474 col = strchr(tok, ':');
475 if (col)
476 *col = '\0';
477 rule->pats[i].flg = GF_PAT;
478 if (!tok[0] || font_readgpat(fn, &rule->pats[i], tok))
479 return 0;
480 if (col)
481 sscanf(col + 1, "%hd%hd%hd%hd",
482 &rule->pats[i].x, &rule->pats[i].y,
483 &rule->pats[i].xadv, &rule->pats[i].yadv);
485 return 0;
488 static int font_readggrp(struct font *fn, FILE *fin)
490 char tok[ILNLEN];
491 int id, n, i, g;
492 if (fscanf(fin, "%d %d", &id, &n) != 2)
493 return 1;
494 for (i = 0; i < n; i++) {
495 if (fscanf(fin, "%s", tok) != 1)
496 return 1;
497 g = font_idx(fn, font_glyph(fn, tok));
498 if (g >= 0)
499 iset_put(fn->ggrp, id, g);
501 return 0;
504 static int font_readkern(struct font *fn, FILE *fin)
506 char c1[ILNLEN], c2[ILNLEN];
507 struct grule *rule;
508 int val;
509 if (fscanf(fin, "%s %s %d", c1, c2, &val) != 3)
510 return 1;
511 rule = font_gpos(fn, 2, font_findfeat(fn, "kern"), -1);
512 rule->pats[0].g = font_idx(fn, font_glyph(fn, c1));
513 rule->pats[1].g = font_idx(fn, font_glyph(fn, c2));
514 rule->pats[0].xadv = val;
515 rule->pats[0].flg = GF_PAT;
516 rule->pats[1].flg = GF_PAT;
517 return 0;
520 static void font_lig(struct font *fn, char *lig)
522 char c[GNLEN];
523 int g[WORDLEN];
524 struct grule *rule;
525 char *s = lig;
526 int j, n = 0;
527 while (utf8read(&s, c) > 0)
528 g[n++] = font_idx(fn, font_find(fn, c));
529 rule = font_gsub(fn, n + 1, font_findfeat(fn, "liga"), -1);
530 for (j = 0; j < n; j++) {
531 rule->pats[j].g = g[j];
532 rule->pats[j].flg = GF_PAT;
534 rule->pats[n].g = font_idx(fn, font_find(fn, lig));
535 rule->pats[n].flg = GF_REP;
538 static void skipline(FILE* filp)
540 int c;
541 do {
542 c = getc(filp);
543 } while (c != '\n' && c != EOF);
546 static struct gpat *font_rulefirstpat(struct font *fn, struct grule *rule)
548 int i;
549 for (i = 0; i < rule->len; i++)
550 if (!(rule->pats[i].flg & (GF_REP | GF_CON)))
551 return &rule->pats[i];
552 return NULL;
555 static void font_isetinsert(struct font *fn, struct iset *iset, int rule, struct gpat *p)
557 if (p->flg & GF_GRP) {
558 int *r = iset_get(fn->ggrp, p->g);
559 while (r && *r >= 0)
560 iset_put(iset, *r++, rule);
561 } else {
562 if (p->g >= 0)
563 iset_put(iset, p->g, rule);
567 struct font *font_open(char *path)
569 struct font *fn;
570 int ch_g = -1; /* last glyph in the charset */
571 int ch_n = 0; /* number of glyphs in the charset */
572 char tok[ILNLEN];
573 FILE *fin;
574 char ligs[512][GNLEN];
575 int ligs_n = 0;
576 int i;
577 fin = fopen(path, "r");
578 if (!fin)
579 return NULL;
580 fn = xmalloc(sizeof(*fn));
581 if (!fn) {
582 fclose(fin);
583 return NULL;
585 memset(fn, 0, sizeof(*fn));
586 fn->gl_dict = dict_make(-1, 1, 0);
587 fn->ch_dict = dict_make(-1, 1, 0);
588 fn->ch_map = dict_make(-1, 1, 0);
589 fn->ggrp = iset_make();
590 while (fscanf(fin, "%s", tok) == 1) {
591 if (!strcmp("char", tok)) {
592 font_readchar(fn, fin, &ch_n, &ch_g);
593 } else if (!strcmp("kern", tok)) {
594 font_readkern(fn, fin);
595 } else if (!strcmp("ligatures", tok)) {
596 while (fscanf(fin, "%s", ligs[ligs_n]) == 1) {
597 if (!strcmp("0", ligs[ligs_n]))
598 break;
599 if (ligs_n < LEN(ligs))
600 ligs_n++;
602 } else if (!strcmp("gsub", tok)) {
603 font_readgsub(fn, fin);
604 } else if (!strcmp("gpos", tok)) {
605 font_readgpos(fn, fin);
606 } else if (!strcmp("ggrp", tok)) {
607 font_readggrp(fn, fin);
608 } else if (!strcmp("spacewidth", tok)) {
609 fscanf(fin, "%d", &fn->spacewid);
610 } else if (!strcmp("special", tok)) {
611 fn->special = 1;
612 } else if (!strcmp("name", tok)) {
613 fscanf(fin, "%s", fn->name);
614 } else if (!strcmp("fontname", tok)) {
615 fscanf(fin, "%s", fn->fontname);
616 } else if (!strcmp("charset", tok)) {
617 while (!font_readchar(fn, fin, &ch_n, &ch_g))
619 break;
621 skipline(fin);
623 for (i = 0; i < ligs_n; i++)
624 font_lig(fn, ligs[i]);
625 fclose(fin);
626 fn->gsub0 = iset_make();
627 fn->gpos0 = iset_make();
628 for (i = 0; i < fn->gsub_n; i++)
629 font_isetinsert(fn, fn->gsub0, i,
630 font_rulefirstpat(fn, &fn->gsub[i]));
631 for (i = 0; i < fn->gpos_n; i++)
632 font_isetinsert(fn, fn->gpos0, i,
633 font_rulefirstpat(fn, &fn->gpos[i]));
634 fn->scrp = -1;
635 return fn;
638 void font_close(struct font *fn)
640 int i;
641 for (i = 0; i < fn->gsub_n; i++)
642 free(fn->gsub[i].pats);
643 for (i = 0; i < fn->gpos_n; i++)
644 free(fn->gpos[i].pats);
645 dict_free(fn->gl_dict);
646 dict_free(fn->ch_dict);
647 dict_free(fn->ch_map);
648 iset_free(fn->gsub0);
649 iset_free(fn->gpos0);
650 iset_free(fn->ggrp);
651 free(fn->gsub);
652 free(fn->gpos);
653 free(fn->gl);
654 free(fn);
657 int font_special(struct font *fn)
659 return fn->special;
662 /* return width w for the given font and size */
663 int font_wid(struct font *fn, int sz, int w)
665 sz = font_zoom(fn, sz);
666 return w >= 0 ? DEVWID(sz, w) : -DEVWID(sz, -w);
669 /* return track kerning width for the given size */
670 static int font_twid(struct font *fn, int sz)
672 if (fn->s1 >= 0 && sz <= fn->s1)
673 return fn->n1 * SC_PT;
674 if (fn->s2 >= 0 && sz >= fn->s2)
675 return fn->n2 * SC_PT;
676 if (sz > fn->s1 && sz < fn->s2)
677 return ((sz - fn->s1) * fn->n1 + (fn->s2 - sz) * fn->n2) *
678 (long) SC_PT / (fn->s2 - fn->s1);
679 return 0;
682 /* glyph width, where cfn is the current font and fn is glyph's font */
683 int font_gwid(struct font *fn, struct font *cfn, int sz, int w)
685 struct font *xfn = cfn ? cfn : fn;
686 if (xfn->cs)
687 return xfn->cs * (font_zoom(fn, xfn->cs_ps ? xfn->cs_ps : sz)
688 * SC_IN / 72) / 36;
689 return font_wid(fn, sz, w) + (cfn ? font_twid(fn, sz) : 0) +
690 (font_getbd(xfn) ? font_getbd(xfn) - 1 : 0);
693 /* space width for the give word space or sentence space */
694 int font_swid(struct font *fn, int sz, int ss)
696 return font_gwid(fn, NULL, sz, (fn->spacewid * ss + 6) / 12);
699 int font_getcs(struct font *fn)
701 return fn->cs;
704 void font_setcs(struct font *fn, int cs, int ps)
706 fn->cs = cs;
707 fn->cs_ps = ps;
710 int font_getbd(struct font *fn)
712 return fn->bd;
715 void font_setbd(struct font *fn, int bd)
717 fn->bd = bd;
720 void font_track(struct font *fn, int s1, int n1, int s2, int n2)
722 fn->s1 = s1;
723 fn->n1 = n1;
724 fn->s2 = s2;
725 fn->n2 = n2;
728 int font_zoom(struct font *fn, int sz)
730 return fn->zoom ? (sz * fn->zoom + 500) / 1000 : sz;
733 void font_setzoom(struct font *fn, int zoom)
735 fn->zoom = zoom;
738 /* enable/disable font features; returns the previous value */
739 int font_feat(struct font *fn, char *name, int val)
741 int idx = font_findfeat(fn, name);
742 int old = idx >= 0 ? fn->feat_set[idx] : 0;
743 if (idx >= 0)
744 fn->feat_set[idx] = val != 0;
745 return old;
748 /* set font script */
749 void font_scrp(struct font *fn, char *name)
751 fn->scrp = name ? font_findscrp(fn, name) : -1;