tr: change the behaviour of of .co request
[neatroff.git] / font.c
blob952644ea79b1c079b86e10c6d9385b11ae2669a8
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 = font_glyphput(fn, id, name, type);
336 g = &fn->gl[*gid];
337 sscanf(tok, "%hd,%hd,%hd,%hd,%hd", &g->wid,
338 &g->llx, &g->lly, &g->urx, &g->ury);
339 dict_put(fn->ch_dict, name, *gid);
340 (*n)++;
341 } else {
342 dict_put(fn->ch_map, name, *gid);
344 return 0;
347 static int font_findfeat(struct font *fn, char *feat)
349 int i;
350 for (i = 0; i < LEN(fn->feat_name) && fn->feat_name[i][0]; i++)
351 if (!strcmp(feat, fn->feat_name[i]))
352 return i;
353 if (i < LEN(fn->feat_name)) {
354 snprintf(fn->feat_name[i], sizeof(fn->feat_name[i]), "%s", feat);
355 return i;
357 return -1;
360 static int font_findscrp(struct font *fn, char *scrp)
362 int i;
363 for (i = 0; i < LEN(fn->scrp_name) && fn->scrp_name[i][0]; i++)
364 if (!strcmp(scrp, fn->scrp_name[i]))
365 return i;
366 if (i == LEN(fn->scrp_name))
367 return -1;
368 snprintf(fn->scrp_name[i], sizeof(fn->scrp_name[i]), "%s", scrp);
369 return i;
372 static int font_findlang(struct font *fn, char *lang)
374 int i;
375 for (i = 0; i < LEN(fn->lang_name) && fn->lang_name[i][0]; i++)
376 if (!strcmp(lang, fn->lang_name[i]))
377 return i;
378 if (i == LEN(fn->lang_name))
379 return -1;
380 snprintf(fn->lang_name[i], sizeof(fn->lang_name[i]), "%s", lang);
381 return i;
384 static struct gpat *font_gpat(struct font *fn, int len)
386 struct gpat *pats = xmalloc(len * sizeof(pats[0]));
387 memset(pats, 0, len * sizeof(pats[0]));
388 return pats;
391 static struct grule *font_gsub(struct font *fn, int len, int feat, int scrp, int lang)
393 struct grule *rule;
394 struct gpat *pats = font_gpat(fn, len);
395 if (fn->gsub_n == fn->gsub_sz) {
396 fn->gsub_sz = fn->gsub_sz + 1024;
397 fn->gsub = mextend(fn->gsub, fn->gsub_n, fn->gsub_sz,
398 sizeof(fn->gsub[0]));
400 rule = &fn->gsub[fn->gsub_n++];
401 rule->pats = pats;
402 rule->len = len;
403 rule->feat = feat;
404 rule->scrp = scrp;
405 rule->lang = lang;
406 return rule;
409 static struct grule *font_gpos(struct font *fn, int len, int feat, int scrp, int lang)
411 struct grule *rule;
412 struct gpat *pats = font_gpat(fn, len);
413 if (fn->gpos_n == fn->gpos_sz) {
414 fn->gpos_sz = fn->gpos_sz + 1024;
415 fn->gpos = mextend(fn->gpos, fn->gpos_n, fn->gpos_sz,
416 sizeof(fn->gpos[0]));
418 rule = &fn->gpos[fn->gpos_n++];
419 rule->pats = pats;
420 rule->len = len;
421 rule->feat = feat;
422 rule->scrp = scrp;
423 rule->lang = lang;
424 return rule;
427 static int font_readgpat(struct font *fn, struct gpat *p, char *s)
429 if (s[0] == '@') {
430 p->g = atoi(s + 1);
431 if (iset_len(fn->ggrp, p->g) == 1)
432 p->g = iset_get(fn->ggrp, p->g)[0];
433 else
434 p->flg |= GF_GRP;
435 } else {
436 p->g = font_idx(fn, font_glyph(fn, s));
438 return p->g < 0;
441 static void font_readfeat(struct font *fn, char *tok, int *feat, int *scrp, int *lang)
443 char *ftag = tok;
444 char *stag = NULL;
445 char *ltag = NULL;
446 *scrp = -1;
447 *lang = -1;
448 if (strchr(ftag, ':')) {
449 stag = strchr(ftag, ':') + 1;
450 stag[-1] = '\0';
452 if (strchr(stag, ':')) {
453 ltag = strchr(stag, ':') + 1;
454 ltag[-1] = '\0';
456 if (stag)
457 *scrp = font_findscrp(fn, stag);
458 if (ltag)
459 *lang = font_findlang(fn, ltag);
460 *feat = font_findfeat(fn, tok);
463 static int font_readgsub(struct font *fn, FILE *fin)
465 char tok[128];
466 struct grule *rule;
467 int feat, scrp, lang;
468 int i, n;
469 if (fscanf(fin, "%s %d", tok, &n) != 2)
470 return 1;
471 font_readfeat(fn, tok, &feat, &scrp, &lang);
472 rule = font_gsub(fn, n, feat, scrp, lang);
473 for (i = 0; i < n; i++) {
474 if (fscanf(fin, "%s", tok) != 1)
475 return 1;
476 if (tok[0] == '-')
477 rule->pats[i].flg = GF_PAT;
478 if (tok[0] == '=')
479 rule->pats[i].flg = GF_CON;
480 if (tok[0] == '+')
481 rule->pats[i].flg = GF_REP;
482 if (!tok[0] || font_readgpat(fn, &rule->pats[i], tok + 1))
483 return 0;
485 return 0;
488 static int font_readgpos(struct font *fn, FILE *fin)
490 char tok[128];
491 char *col;
492 struct grule *rule;
493 int feat, scrp, lang;
494 int i, n;
495 if (fscanf(fin, "%s %d", tok, &n) != 2)
496 return 1;
497 font_readfeat(fn, tok, &feat, &scrp, &lang);
498 rule = font_gpos(fn, n, feat, scrp, lang);
499 for (i = 0; i < n; i++) {
500 if (fscanf(fin, "%s", tok) != 1)
501 return 1;
502 col = strchr(tok, ':');
503 if (col)
504 *col = '\0';
505 rule->pats[i].flg = GF_PAT;
506 if (!tok[0] || font_readgpat(fn, &rule->pats[i], tok))
507 return 0;
508 if (col)
509 sscanf(col + 1, "%hd%hd%hd%hd",
510 &rule->pats[i].x, &rule->pats[i].y,
511 &rule->pats[i].xadv, &rule->pats[i].yadv);
513 return 0;
516 static int font_readggrp(struct font *fn, FILE *fin)
518 char tok[ILNLEN];
519 int id, n, i, g;
520 if (fscanf(fin, "%d %d", &id, &n) != 2)
521 return 1;
522 for (i = 0; i < n; i++) {
523 if (fscanf(fin, "%s", tok) != 1)
524 return 1;
525 g = font_idx(fn, font_glyph(fn, tok));
526 if (g >= 0)
527 iset_put(fn->ggrp, id, g);
529 return 0;
532 static int font_readkern(struct font *fn, FILE *fin)
534 char c1[ILNLEN], c2[ILNLEN];
535 struct grule *rule;
536 int val;
537 if (fscanf(fin, "%s %s %d", c1, c2, &val) != 3)
538 return 1;
539 rule = font_gpos(fn, 2, font_findfeat(fn, "kern"), -1, -1);
540 rule->pats[0].g = font_idx(fn, font_glyph(fn, c1));
541 rule->pats[1].g = font_idx(fn, font_glyph(fn, c2));
542 rule->pats[0].xadv = val;
543 rule->pats[0].flg = GF_PAT;
544 rule->pats[1].flg = GF_PAT;
545 return 0;
548 static void font_lig(struct font *fn, char *lig)
550 char c[GNLEN];
551 int g[WORDLEN];
552 struct grule *rule;
553 char *s = lig;
554 int j, n = 0;
555 while (utf8read(&s, c) > 0)
556 g[n++] = font_idx(fn, font_find(fn, c));
557 rule = font_gsub(fn, n + 1, font_findfeat(fn, "liga"), -1, -1);
558 for (j = 0; j < n; j++) {
559 rule->pats[j].g = g[j];
560 rule->pats[j].flg = GF_PAT;
562 rule->pats[n].g = font_idx(fn, font_find(fn, lig));
563 rule->pats[n].flg = GF_REP;
566 static void skipline(FILE* filp)
568 int c;
569 do {
570 c = getc(filp);
571 } while (c != '\n' && c != EOF);
574 static struct gpat *font_rulefirstpat(struct font *fn, struct grule *rule)
576 int i;
577 for (i = 0; i < rule->len; i++)
578 if (!(rule->pats[i].flg & (GF_REP | GF_CON)))
579 return &rule->pats[i];
580 return NULL;
583 static void font_isetinsert(struct font *fn, struct iset *iset, int rule, struct gpat *p)
585 if (p->flg & GF_GRP) {
586 int *r = iset_get(fn->ggrp, p->g);
587 while (r && *r >= 0)
588 iset_put(iset, *r++, rule);
589 } else {
590 if (p->g >= 0)
591 iset_put(iset, p->g, rule);
595 struct font *font_open(char *path)
597 struct font *fn;
598 int ch_g = -1; /* last glyph in the charset */
599 int ch_n = 0; /* number of glyphs in the charset */
600 char tok[ILNLEN];
601 FILE *fin;
602 char ligs[512][GNLEN];
603 int ligs_n = 0;
604 int i;
605 fin = fopen(path, "r");
606 if (!fin)
607 return NULL;
608 fn = xmalloc(sizeof(*fn));
609 if (!fn) {
610 fclose(fin);
611 return NULL;
613 memset(fn, 0, sizeof(*fn));
614 fn->gl_dict = dict_make(-1, 1, 0);
615 fn->ch_dict = dict_make(-1, 1, 0);
616 fn->ch_map = dict_make(-1, 1, 0);
617 fn->ggrp = iset_make();
618 while (fscanf(fin, "%s", tok) == 1) {
619 if (!strcmp("char", tok)) {
620 font_readchar(fn, fin, &ch_n, &ch_g);
621 } else if (!strcmp("kern", tok)) {
622 font_readkern(fn, fin);
623 } else if (!strcmp("ligatures", tok)) {
624 while (fscanf(fin, "%s", ligs[ligs_n]) == 1) {
625 if (!strcmp("0", ligs[ligs_n]))
626 break;
627 if (ligs_n < LEN(ligs))
628 ligs_n++;
630 } else if (!strcmp("gsub", tok)) {
631 font_readgsub(fn, fin);
632 } else if (!strcmp("gpos", tok)) {
633 font_readgpos(fn, fin);
634 } else if (!strcmp("ggrp", tok)) {
635 font_readggrp(fn, fin);
636 } else if (!strcmp("spacewidth", tok)) {
637 fscanf(fin, "%d", &fn->spacewid);
638 } else if (!strcmp("special", tok)) {
639 fn->special = 1;
640 } else if (!strcmp("name", tok)) {
641 fscanf(fin, "%s", fn->name);
642 } else if (!strcmp("fontname", tok)) {
643 fscanf(fin, "%s", fn->fontname);
644 } else if (!strcmp("charset", tok)) {
645 while (!font_readchar(fn, fin, &ch_n, &ch_g))
647 break;
649 skipline(fin);
651 for (i = 0; i < ligs_n; i++)
652 font_lig(fn, ligs[i]);
653 fclose(fin);
654 fn->gsub0 = iset_make();
655 fn->gpos0 = iset_make();
656 for (i = 0; i < fn->gsub_n; i++)
657 font_isetinsert(fn, fn->gsub0, i,
658 font_rulefirstpat(fn, &fn->gsub[i]));
659 for (i = 0; i < fn->gpos_n; i++)
660 font_isetinsert(fn, fn->gpos0, i,
661 font_rulefirstpat(fn, &fn->gpos[i]));
662 fn->scrp = -1;
663 fn->lang = -1;
664 return fn;
667 void font_close(struct font *fn)
669 int i;
670 for (i = 0; i < fn->gsub_n; i++)
671 free(fn->gsub[i].pats);
672 for (i = 0; i < fn->gpos_n; i++)
673 free(fn->gpos[i].pats);
674 dict_free(fn->gl_dict);
675 dict_free(fn->ch_dict);
676 dict_free(fn->ch_map);
677 iset_free(fn->gsub0);
678 iset_free(fn->gpos0);
679 iset_free(fn->ggrp);
680 free(fn->gsub);
681 free(fn->gpos);
682 free(fn->gl);
683 free(fn);
686 int font_special(struct font *fn)
688 return fn->special;
691 /* return width w for the given font and size */
692 int font_wid(struct font *fn, int sz, int w)
694 sz = font_zoom(fn, sz);
695 return w >= 0 ? DEVWID(sz, w) : -DEVWID(sz, -w);
698 /* return track kerning width for the given size */
699 static int font_twid(struct font *fn, int sz)
701 if (fn->s1 >= 0 && sz <= fn->s1)
702 return fn->n1 * SC_PT;
703 if (fn->s2 >= 0 && sz >= fn->s2)
704 return fn->n2 * SC_PT;
705 if (sz > fn->s1 && sz < fn->s2)
706 return ((sz - fn->s1) * fn->n1 + (fn->s2 - sz) * fn->n2) *
707 (long) SC_PT / (fn->s2 - fn->s1);
708 return 0;
711 /* glyph width, where cfn is the current font and fn is glyph's font */
712 int font_gwid(struct font *fn, struct font *cfn, int sz, int w)
714 struct font *xfn = cfn ? cfn : fn;
715 if (xfn->cs)
716 return xfn->cs * (font_zoom(fn, xfn->cs_ps ? xfn->cs_ps : sz)
717 * SC_IN / 72) / 36;
718 return font_wid(fn, sz, w) + (cfn ? font_twid(fn, sz) : 0) +
719 (font_getbd(xfn) ? font_getbd(xfn) - 1 : 0);
722 /* space width for the give word space or sentence space */
723 int font_swid(struct font *fn, int sz, int ss)
725 return font_gwid(fn, NULL, sz, (fn->spacewid * ss + 6) / 12);
728 int font_getcs(struct font *fn)
730 return fn->cs;
733 void font_setcs(struct font *fn, int cs, int ps)
735 fn->cs = cs;
736 fn->cs_ps = ps;
739 int font_getbd(struct font *fn)
741 return fn->bd;
744 void font_setbd(struct font *fn, int bd)
746 fn->bd = bd;
749 void font_track(struct font *fn, int s1, int n1, int s2, int n2)
751 fn->s1 = s1;
752 fn->n1 = n1;
753 fn->s2 = s2;
754 fn->n2 = n2;
757 int font_zoom(struct font *fn, int sz)
759 return fn->zoom ? (sz * fn->zoom + 500) / 1000 : sz;
762 void font_setzoom(struct font *fn, int zoom)
764 fn->zoom = zoom;
767 /* enable/disable font features; returns the previous value */
768 int font_feat(struct font *fn, char *name, int val)
770 int idx = font_findfeat(fn, name);
771 int old = idx >= 0 ? fn->feat_set[idx] : 0;
772 if (idx >= 0)
773 fn->feat_set[idx] = val != 0;
774 return old;
777 /* set font script */
778 void font_scrp(struct font *fn, char *name)
780 fn->scrp = name ? font_findscrp(fn, name) : -1;
783 /* set font language */
784 void font_lang(struct font *fn, char *name)
786 fn->lang = name ? font_findlang(fn, name) : -1;