font: specifying OpenType font language with .ffsc
[neatroff.git] / font.c
blobcd2212cb48131dcbb029c90d97b08d8eb44fa192
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, lang; /* 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 char lang_name[NLANGS][8]; /* language names */
45 int lang; /* current language */
46 /* glyph substitution and positioning */
47 struct grule *gsub; /* glyph substitution rules */
48 int gsub_n, gsub_sz;
49 struct grule *gpos; /* glyph positioning rules */
50 int gpos_n, gpos_sz;
51 struct iset *gsub0; /* rules matching a glyph at pos 0 */
52 struct iset *gpos0; /* rules matching a glyph at pos 0 */
53 struct iset *ggrp; /* glyph groups */
56 /* find a glyph by its name */
57 struct glyph *font_find(struct font *fn, char *name)
59 int i = dict_get(fn->ch_map, name);
60 if (i == -1) /* -2 means the glyph has been unmapped */
61 i = dict_get(fn->ch_dict, name);
62 return i >= 0 ? fn->gl + i : NULL;
65 /* find a glyph by its device-dependent identifier */
66 struct glyph *font_glyph(struct font *fn, char *id)
68 int i = dict_get(fn->gl_dict, id);
69 return i >= 0 ? &fn->gl[i] : NULL;
72 static int font_glyphput(struct font *fn, char *id, char *name, int type)
74 struct glyph *g;
75 if (fn->gl_n == fn->gl_sz) {
76 fn->gl_sz = fn->gl_sz + 1024;
77 fn->gl = mextend(fn->gl, fn->gl_n, fn->gl_sz, sizeof(fn->gl[0]));
79 g = &fn->gl[fn->gl_n];
80 snprintf(g->id, sizeof(g->id), "%s", id);
81 snprintf(g->name, sizeof(g->name), "%s", name);
82 g->type = type;
83 g->font = fn;
84 dict_put(fn->gl_dict, g->id, fn->gl_n);
85 return fn->gl_n++;
88 /* map character name to the given glyph; remove the mapping if id is NULL */
89 int font_map(struct font *fn, char *name, char *id)
91 int gidx = -1;
92 if (id)
93 gidx = font_glyph(fn, id) ? font_glyph(fn, id) - fn->gl : -2;
94 dict_put(fn->ch_map, name, gidx);
95 return 0;
98 /* return nonzero if character name has been mapped with font_map() */
99 int font_mapped(struct font *fn, char *name)
101 return dict_get(fn->ch_map, name) != -1;
104 static int font_findfeat(struct font *fn, char *feat);
106 /* enable/disable ligatures; first bit for liga and the second bit for rlig */
107 static int font_featlg(struct font *fn, int val)
109 int ret = 0;
110 ret |= font_feat(fn, "liga", val & 1);
111 ret |= font_feat(fn, "rlig", val & 2) << 1;
112 return ret;
115 /* enable/disable pairwise kerning */
116 static int font_featkn(struct font *fn, int val)
118 return font_feat(fn, "kern", val);
121 /* glyph index in fn->glyphs[] */
122 static int font_idx(struct font *fn, struct glyph *g)
124 return g ? g - fn->gl : -1;
127 static int font_gpatmatch(struct font *fn, struct gpat *p, int g)
129 int *r;
130 if (!(p->flg & GF_GRP))
131 return p->g == g;
132 r = iset_get(fn->ggrp, p->g);
133 while (r && *r >= 0)
134 if (*r++ == g)
135 return 1;
136 return 0;
139 static int font_rulematch(struct font *fn, struct grule *rule,
140 int *src, int slen, int *dst, int dlen)
142 int sidx = 0; /* the index of matched glyphs in src */
143 int ncon = 0; /* number of initial context glyphs */
144 struct gpat *pats = rule->pats;
145 int j;
146 /* enable only the active script if set */
147 if (fn->scrp >= 0 && fn->scrp != rule->scrp)
148 return 0;
149 /* enable common script features and those in the active language */
150 if (rule->lang >= 0 && fn->lang != rule->lang)
151 return 0;
152 if (!fn->feat_set[rule->feat])
153 return 0;
154 /* the number of initial context glyphs */
155 for (j = 0; j < rule->len && pats[j].flg & GF_CON; j++)
156 ncon++;
157 if (dlen < ncon)
158 return 0;
159 /* matching the base pattern */
160 for (; j < rule->len; j++) {
161 if (pats[j].flg & GF_REP)
162 continue;
163 if (sidx >= slen || !font_gpatmatch(fn, &pats[j], src[sidx]))
164 return 0;
165 sidx++;
167 /* matching the initial context */
168 for (j = 0; j < rule->len && pats[j].flg & GF_CON; j++)
169 if (!font_gpatmatch(fn, &pats[j], dst[j - ncon]))
170 return 0;
171 return 1;
174 /* find a matching gsub/gpos rule; *idx should be -1 initially */
175 static int font_findrule(struct font *fn, int gsub, int pos,
176 int *fwd, int fwdlen, int *ctx, int ctxlen, int *idx)
178 struct grule *rules = gsub ? fn->gsub : fn->gpos;
179 int *r1 = iset_get(gsub ? fn->gsub0 : fn->gpos0, fwd[0]);
180 while (r1 && r1[++*idx] >= 0) {
181 if (r1[*idx] >= pos && font_rulematch(fn, &rules[r1[*idx]],
182 fwd, fwdlen, ctx, ctxlen))
183 return r1[*idx];
185 return -1;
188 /* perform all possible gpos rules on src */
189 static void font_performgpos(struct font *fn, int *src, int slen,
190 int *x, int *y, int *xadv, int *yadv)
192 struct grule *gpos = fn->gpos;
193 struct gpat *pats;
194 int curs_feat = dir_do ? font_findfeat(fn, "curs") : -1;
195 int curs_beg = -1;
196 int curs_dif = 0;
197 int i, k;
198 for (i = 0; i < slen; i++) {
199 int idx = -1;
200 int curs_cur = 0;
201 while (1) {
202 int r = font_findrule(fn, 0, 0, src + i, slen - i,
203 src + i, i, &idx);
204 if (r < 0)
205 break;
206 pats = gpos[r].pats;
207 for (k = 0; k < gpos[r].len; k++) {
208 x[i + k] += pats[k].x;
209 y[i + k] += pats[k].y;
210 xadv[i + k] += pats[k].xadv;
211 yadv[i + k] += pats[k].yadv;
213 if (gpos[r].feat == curs_feat) {
214 curs_cur = 1;
215 if (curs_beg < 0)
216 curs_beg = i;
217 for (k = 0; k < gpos[r].len; k++)
218 curs_dif += pats[k].yadv;
221 if (curs_beg >= 0 && !curs_cur) {
222 yadv[curs_beg] -= curs_dif;
223 curs_beg = -1;
224 curs_dif = 0;
227 if (curs_beg >= 0)
228 yadv[curs_beg] -= curs_dif;
231 /* find the first gsub rule after pos that matches any glyph in src */
232 static int font_firstgsub(struct font *fn, int pos, int *src, int slen)
234 int best = -1;
235 int i;
236 for (i = 0; i < slen; i++) {
237 int idx = -1;
238 int r = font_findrule(fn, 1, pos, src + i, slen - i,
239 src + i, i, &idx);
240 if (r >= 0 && (best < 0 || r < best))
241 best = r;
243 return best;
246 /* apply the given gsub rule to all matches in src */
247 static int font_gsubapply(struct font *fn, struct grule *rule,
248 int *src, int slen, int *smap)
250 int dst[WORDLEN];
251 int dlen = 0;
252 int dmap[WORDLEN];
253 int i, j;
254 memset(dmap, 0, slen * sizeof(dmap[i]));
255 for (i = 0; i < slen; i++) {
256 dmap[dlen] = smap[i];
257 if (font_rulematch(fn, rule, src + i, slen - i,
258 dst + dlen, dlen)) {
259 for (j = 0; j < rule->len; j++) {
260 if (rule->pats[j].flg & GF_REP)
261 dst[dlen++] = rule->pats[j].g;
262 if (rule->pats[j].flg & GF_PAT)
263 i++;
265 i--;
266 } else {
267 dst[dlen++] = src[i];
270 memcpy(src, dst, dlen * sizeof(dst[0]));
271 memcpy(smap, dmap, dlen * sizeof(dmap[0]));
272 return dlen;
275 /* perform all possible gsub rules on src */
276 static int font_performgsub(struct font *fn, int *src, int slen, int *smap)
278 int i = -1;
279 while (++i >= 0) {
280 if ((i = font_firstgsub(fn, i, src, slen)) < 0)
281 break;
282 slen = font_gsubapply(fn, &fn->gsub[i], src, slen, smap);
284 return slen;
287 int font_layout(struct font *fn, struct glyph **gsrc, int nsrc, int sz,
288 struct glyph **gdst, int *dmap,
289 int *x, int *y, int *xadv, int *yadv, int lg, int kn)
291 int dst[WORDLEN];
292 int ndst = nsrc;
293 int i;
294 int featlg, featkn;
295 /* initialising dst */
296 for (i = 0; i < nsrc; i++)
297 dst[i] = font_idx(fn, gsrc[i]);
298 for (i = 0; i < ndst; i++)
299 dmap[i] = i;
300 memset(x, 0, ndst * sizeof(x[0]));
301 memset(y, 0, ndst * sizeof(y[0]));
302 memset(xadv, 0, ndst * sizeof(xadv[0]));
303 memset(yadv, 0, ndst * sizeof(yadv[0]));
304 /* substitution rules */
305 if (lg)
306 featlg = font_featlg(fn, 3);
307 ndst = font_performgsub(fn, dst, ndst, dmap);
308 if (lg)
309 font_featlg(fn, featlg);
310 /* positioning rules */
311 if (kn)
312 featkn = font_featkn(fn, 1);
313 font_performgpos(fn, dst, ndst, x, y, xadv, yadv);
314 if (kn)
315 font_featkn(fn, featkn);
316 for (i = 0; i < ndst; i++)
317 gdst[i] = fn->gl + dst[i];
318 return ndst;
321 static int font_readchar(struct font *fn, FILE *fin, int *n, int *gid)
323 struct glyph *g;
324 char tok[ILNLEN];
325 char name[ILNLEN];
326 char id[ILNLEN];
327 int type;
328 if (fscanf(fin, "%s %s", name, tok) != 2)
329 return 1;
330 if (!strcmp("---", name))
331 sprintf(name, "c%04d", *n);
332 if (strcmp("\"", tok)) {
333 if (fscanf(fin, "%d %s", &type, id) != 2)
334 return 1;
335 *gid = dict_get(fn->gl_dict, id);
336 if (*gid < 0) {
337 *gid = font_glyphput(fn, id, name, type);
338 g = &fn->gl[*gid];
339 sscanf(tok, "%hd,%hd,%hd,%hd,%hd", &g->wid,
340 &g->llx, &g->lly, &g->urx, &g->ury);
342 dict_put(fn->ch_dict, name, *gid);
343 (*n)++;
344 } else {
345 dict_put(fn->ch_map, name, *gid);
347 return 0;
350 static int font_findfeat(struct font *fn, char *feat)
352 int i;
353 for (i = 0; i < LEN(fn->feat_name) && fn->feat_name[i][0]; i++)
354 if (!strcmp(feat, fn->feat_name[i]))
355 return i;
356 if (i < LEN(fn->feat_name)) {
357 snprintf(fn->feat_name[i], sizeof(fn->feat_name[i]), "%s", feat);
358 return i;
360 return -1;
363 static int font_findscrp(struct font *fn, char *scrp)
365 int i;
366 for (i = 0; i < LEN(fn->scrp_name) && fn->scrp_name[i][0]; i++)
367 if (!strcmp(scrp, fn->scrp_name[i]))
368 return i;
369 if (i == LEN(fn->scrp_name))
370 return -1;
371 snprintf(fn->scrp_name[i], sizeof(fn->scrp_name[i]), "%s", scrp);
372 return i;
375 static int font_findlang(struct font *fn, char *lang)
377 int i;
378 for (i = 0; i < LEN(fn->lang_name) && fn->lang_name[i][0]; i++)
379 if (!strcmp(lang, fn->lang_name[i]))
380 return i;
381 if (i == LEN(fn->lang_name))
382 return -1;
383 snprintf(fn->lang_name[i], sizeof(fn->lang_name[i]), "%s", lang);
384 return i;
387 static struct gpat *font_gpat(struct font *fn, int len)
389 struct gpat *pats = xmalloc(len * sizeof(pats[0]));
390 memset(pats, 0, len * sizeof(pats[0]));
391 return pats;
394 static struct grule *font_gsub(struct font *fn, int len, int feat, int scrp, int lang)
396 struct grule *rule;
397 struct gpat *pats = font_gpat(fn, len);
398 if (fn->gsub_n == fn->gsub_sz) {
399 fn->gsub_sz = fn->gsub_sz + 1024;
400 fn->gsub = mextend(fn->gsub, fn->gsub_n, fn->gsub_sz,
401 sizeof(fn->gsub[0]));
403 rule = &fn->gsub[fn->gsub_n++];
404 rule->pats = pats;
405 rule->len = len;
406 rule->feat = feat;
407 rule->scrp = scrp;
408 rule->lang = lang;
409 return rule;
412 static struct grule *font_gpos(struct font *fn, int len, int feat, int scrp, int lang)
414 struct grule *rule;
415 struct gpat *pats = font_gpat(fn, len);
416 if (fn->gpos_n == fn->gpos_sz) {
417 fn->gpos_sz = fn->gpos_sz + 1024;
418 fn->gpos = mextend(fn->gpos, fn->gpos_n, fn->gpos_sz,
419 sizeof(fn->gpos[0]));
421 rule = &fn->gpos[fn->gpos_n++];
422 rule->pats = pats;
423 rule->len = len;
424 rule->feat = feat;
425 rule->scrp = scrp;
426 rule->lang = lang;
427 return rule;
430 static int font_readgpat(struct font *fn, struct gpat *p, char *s)
432 if (s[0] == '@') {
433 p->g = atoi(s + 1);
434 if (iset_len(fn->ggrp, p->g) == 1)
435 p->g = iset_get(fn->ggrp, p->g)[0];
436 else
437 p->flg |= GF_GRP;
438 } else {
439 p->g = font_idx(fn, font_glyph(fn, s));
441 return p->g < 0;
444 static void font_readfeat(struct font *fn, char *tok, int *feat, int *scrp, int *lang)
446 char *ftag = tok;
447 char *stag = NULL;
448 char *ltag = NULL;
449 *scrp = -1;
450 *lang = -1;
451 if (strchr(ftag, ':')) {
452 stag = strchr(ftag, ':') + 1;
453 stag[-1] = '\0';
455 if (strchr(stag, ':')) {
456 ltag = strchr(stag, ':') + 1;
457 ltag[-1] = '\0';
459 if (stag)
460 *scrp = font_findscrp(fn, stag);
461 if (ltag)
462 *lang = font_findlang(fn, ltag);
463 *feat = font_findfeat(fn, tok);
466 static int font_readgsub(struct font *fn, FILE *fin)
468 char tok[128];
469 struct grule *rule;
470 int feat, scrp, lang;
471 int i, n;
472 if (fscanf(fin, "%s %d", tok, &n) != 2)
473 return 1;
474 font_readfeat(fn, tok, &feat, &scrp, &lang);
475 rule = font_gsub(fn, n, feat, scrp, lang);
476 for (i = 0; i < n; i++) {
477 if (fscanf(fin, "%s", tok) != 1)
478 return 1;
479 if (tok[0] == '-')
480 rule->pats[i].flg = GF_PAT;
481 if (tok[0] == '=')
482 rule->pats[i].flg = GF_CON;
483 if (tok[0] == '+')
484 rule->pats[i].flg = GF_REP;
485 if (!tok[0] || font_readgpat(fn, &rule->pats[i], tok + 1))
486 return 0;
488 return 0;
491 static int font_readgpos(struct font *fn, FILE *fin)
493 char tok[128];
494 char *col;
495 struct grule *rule;
496 int feat, scrp, lang;
497 int i, n;
498 if (fscanf(fin, "%s %d", tok, &n) != 2)
499 return 1;
500 font_readfeat(fn, tok, &feat, &scrp, &lang);
501 rule = font_gpos(fn, n, feat, scrp, lang);
502 for (i = 0; i < n; i++) {
503 if (fscanf(fin, "%s", tok) != 1)
504 return 1;
505 col = strchr(tok, ':');
506 if (col)
507 *col = '\0';
508 rule->pats[i].flg = GF_PAT;
509 if (!tok[0] || font_readgpat(fn, &rule->pats[i], tok))
510 return 0;
511 if (col)
512 sscanf(col + 1, "%hd%hd%hd%hd",
513 &rule->pats[i].x, &rule->pats[i].y,
514 &rule->pats[i].xadv, &rule->pats[i].yadv);
516 return 0;
519 static int font_readggrp(struct font *fn, FILE *fin)
521 char tok[ILNLEN];
522 int id, n, i, g;
523 if (fscanf(fin, "%d %d", &id, &n) != 2)
524 return 1;
525 for (i = 0; i < n; i++) {
526 if (fscanf(fin, "%s", tok) != 1)
527 return 1;
528 g = font_idx(fn, font_glyph(fn, tok));
529 if (g >= 0)
530 iset_put(fn->ggrp, id, g);
532 return 0;
535 static int font_readkern(struct font *fn, FILE *fin)
537 char c1[ILNLEN], c2[ILNLEN];
538 struct grule *rule;
539 int val;
540 if (fscanf(fin, "%s %s %d", c1, c2, &val) != 3)
541 return 1;
542 rule = font_gpos(fn, 2, font_findfeat(fn, "kern"), -1, -1);
543 rule->pats[0].g = font_idx(fn, font_glyph(fn, c1));
544 rule->pats[1].g = font_idx(fn, font_glyph(fn, c2));
545 rule->pats[0].xadv = val;
546 rule->pats[0].flg = GF_PAT;
547 rule->pats[1].flg = GF_PAT;
548 return 0;
551 static void font_lig(struct font *fn, char *lig)
553 char c[GNLEN];
554 int g[WORDLEN];
555 struct grule *rule;
556 char *s = lig;
557 int j, n = 0;
558 while (utf8read(&s, c) > 0)
559 g[n++] = font_idx(fn, font_find(fn, c));
560 rule = font_gsub(fn, n + 1, font_findfeat(fn, "liga"), -1, -1);
561 for (j = 0; j < n; j++) {
562 rule->pats[j].g = g[j];
563 rule->pats[j].flg = GF_PAT;
565 rule->pats[n].g = font_idx(fn, font_find(fn, lig));
566 rule->pats[n].flg = GF_REP;
569 static void skipline(FILE* filp)
571 int c;
572 do {
573 c = getc(filp);
574 } while (c != '\n' && c != EOF);
577 static struct gpat *font_rulefirstpat(struct font *fn, struct grule *rule)
579 int i;
580 for (i = 0; i < rule->len; i++)
581 if (!(rule->pats[i].flg & (GF_REP | GF_CON)))
582 return &rule->pats[i];
583 return NULL;
586 static void font_isetinsert(struct font *fn, struct iset *iset, int rule, struct gpat *p)
588 if (p->flg & GF_GRP) {
589 int *r = iset_get(fn->ggrp, p->g);
590 while (r && *r >= 0)
591 iset_put(iset, *r++, rule);
592 } else {
593 if (p->g >= 0)
594 iset_put(iset, p->g, rule);
598 struct font *font_open(char *path)
600 struct font *fn;
601 int ch_g = -1; /* last glyph in the charset */
602 int ch_n = 0; /* number of glyphs in the charset */
603 char tok[ILNLEN];
604 FILE *fin;
605 char ligs[512][GNLEN];
606 int ligs_n = 0;
607 int i;
608 fin = fopen(path, "r");
609 if (!fin)
610 return NULL;
611 fn = xmalloc(sizeof(*fn));
612 if (!fn) {
613 fclose(fin);
614 return NULL;
616 memset(fn, 0, sizeof(*fn));
617 fn->gl_dict = dict_make(-1, 1, 0);
618 fn->ch_dict = dict_make(-1, 1, 0);
619 fn->ch_map = dict_make(-1, 1, 0);
620 fn->ggrp = iset_make();
621 while (fscanf(fin, "%s", tok) == 1) {
622 if (!strcmp("char", tok)) {
623 font_readchar(fn, fin, &ch_n, &ch_g);
624 } else if (!strcmp("kern", tok)) {
625 font_readkern(fn, fin);
626 } else if (!strcmp("ligatures", tok)) {
627 while (fscanf(fin, "%s", ligs[ligs_n]) == 1) {
628 if (!strcmp("0", ligs[ligs_n]))
629 break;
630 if (ligs_n < LEN(ligs))
631 ligs_n++;
633 } else if (!strcmp("gsub", tok)) {
634 font_readgsub(fn, fin);
635 } else if (!strcmp("gpos", tok)) {
636 font_readgpos(fn, fin);
637 } else if (!strcmp("ggrp", tok)) {
638 font_readggrp(fn, fin);
639 } else if (!strcmp("spacewidth", tok)) {
640 fscanf(fin, "%d", &fn->spacewid);
641 } else if (!strcmp("special", tok)) {
642 fn->special = 1;
643 } else if (!strcmp("name", tok)) {
644 fscanf(fin, "%s", fn->name);
645 } else if (!strcmp("fontname", tok)) {
646 fscanf(fin, "%s", fn->fontname);
647 } else if (!strcmp("charset", tok)) {
648 while (!font_readchar(fn, fin, &ch_n, &ch_g))
650 break;
652 skipline(fin);
654 for (i = 0; i < ligs_n; i++)
655 font_lig(fn, ligs[i]);
656 fclose(fin);
657 fn->gsub0 = iset_make();
658 fn->gpos0 = iset_make();
659 for (i = 0; i < fn->gsub_n; i++)
660 font_isetinsert(fn, fn->gsub0, i,
661 font_rulefirstpat(fn, &fn->gsub[i]));
662 for (i = 0; i < fn->gpos_n; i++)
663 font_isetinsert(fn, fn->gpos0, i,
664 font_rulefirstpat(fn, &fn->gpos[i]));
665 fn->scrp = -1;
666 fn->lang = -1;
667 return fn;
670 void font_close(struct font *fn)
672 int i;
673 for (i = 0; i < fn->gsub_n; i++)
674 free(fn->gsub[i].pats);
675 for (i = 0; i < fn->gpos_n; i++)
676 free(fn->gpos[i].pats);
677 dict_free(fn->gl_dict);
678 dict_free(fn->ch_dict);
679 dict_free(fn->ch_map);
680 iset_free(fn->gsub0);
681 iset_free(fn->gpos0);
682 iset_free(fn->ggrp);
683 free(fn->gsub);
684 free(fn->gpos);
685 free(fn->gl);
686 free(fn);
689 int font_special(struct font *fn)
691 return fn->special;
694 /* return width w for the given font and size */
695 int font_wid(struct font *fn, int sz, int w)
697 sz = font_zoom(fn, sz);
698 return w >= 0 ? DEVWID(sz, w) : -DEVWID(sz, -w);
701 /* return track kerning width for the given size */
702 static int font_twid(struct font *fn, int sz)
704 if (fn->s1 >= 0 && sz <= fn->s1)
705 return fn->n1 * SC_PT;
706 if (fn->s2 >= 0 && sz >= fn->s2)
707 return fn->n2 * SC_PT;
708 if (sz > fn->s1 && sz < fn->s2)
709 return ((sz - fn->s1) * fn->n1 + (fn->s2 - sz) * fn->n2) *
710 (long) SC_PT / (fn->s2 - fn->s1);
711 return 0;
714 /* glyph width, where cfn is the current font and fn is glyph's font */
715 int font_gwid(struct font *fn, struct font *cfn, int sz, int w)
717 struct font *xfn = cfn ? cfn : fn;
718 if (xfn->cs)
719 return xfn->cs * (font_zoom(fn, xfn->cs_ps ? xfn->cs_ps : sz)
720 * SC_IN / 72) / 36;
721 return font_wid(fn, sz, w) + (cfn ? font_twid(fn, sz) : 0) +
722 (font_getbd(xfn) ? font_getbd(xfn) - 1 : 0);
725 /* space width for the give word space or sentence space */
726 int font_swid(struct font *fn, int sz, int ss)
728 return font_gwid(fn, NULL, sz, (fn->spacewid * ss + 6) / 12);
731 int font_getcs(struct font *fn)
733 return fn->cs;
736 void font_setcs(struct font *fn, int cs, int ps)
738 fn->cs = cs;
739 fn->cs_ps = ps;
742 int font_getbd(struct font *fn)
744 return fn->bd;
747 void font_setbd(struct font *fn, int bd)
749 fn->bd = bd;
752 void font_track(struct font *fn, int s1, int n1, int s2, int n2)
754 fn->s1 = s1;
755 fn->n1 = n1;
756 fn->s2 = s2;
757 fn->n2 = n2;
760 int font_zoom(struct font *fn, int sz)
762 return fn->zoom ? (sz * fn->zoom + 500) / 1000 : sz;
765 void font_setzoom(struct font *fn, int zoom)
767 fn->zoom = zoom;
770 /* enable/disable font features; returns the previous value */
771 int font_feat(struct font *fn, char *name, int val)
773 int idx = font_findfeat(fn, name);
774 int old = idx >= 0 ? fn->feat_set[idx] : 0;
775 if (idx >= 0)
776 fn->feat_set[idx] = val != 0;
777 return old;
780 /* set font script */
781 void font_scrp(struct font *fn, char *name)
783 fn->scrp = name ? font_findscrp(fn, name) : -1;
786 /* set font language */
787 void font_lang(struct font *fn, char *name)
789 fn->lang = name ? font_findlang(fn, name) : -1;