7 /* convert wid in device unitwidth size to size sz */
8 #define DEVWID(sz, wid) (((wid) * (sz) + (dev_uwid / 2)) / dev_uwid)
9 #define GHASH(g1, g2) ((((g2) + 1) << 16) | ((g1) + 1))
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 pattern for gsub and gpos tables; each grule has some gpats */
18 short g
; /* glyph index */
19 short flg
; /* pattern flags; GF_* */
20 short x
, y
, xadv
, yadv
; /* gpos data */
23 /* glyph substitution and positioning rules */
26 short len
; /* pats[] length */
27 short feat
; /* feature owning this rule */
28 short pos
; /* position of this rule in the file */
29 int hash
; /* hash of this rule for sorting and comparison */
37 int cs
, cs_ps
, bd
, zoom
; /* for .cs, .bd, .fzoom requests */
38 struct glyph gl
[NGLYPHS
]; /* glyphs present in the font */
39 int gl_n
; /* number of glyphs in the font */
40 struct dict gl_dict
; /* mapping from gl[i].id to i */
41 struct dict ch_dict
; /* charset mapping */
42 struct dict ch_map
; /* characters mapped via font_map() */
44 char feat_name
[NFEATS
][8]; /* feature names */
45 int feat_set
[NFEATS
]; /* feature enabled */
47 /* glyph substitution and positioning */
48 struct grule gsub
[NGRULES
]; /* glyph substitution rules */
50 struct grule gpos
[NGRULES
]; /* glyph positioning rules */
52 int *ggrp
[NGRULES
]; /* glyph groups */
53 int ggrp_len
[NGRULES
];
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
);
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 struct glyph
*font_glyphput(struct font
*fn
, char *id
, char *name
, int type
)
78 strcpy(g
->name
, name
);
81 dict_put(&fn
->gl_dict
, g
->id
, i
);
85 /* map character name to the given glyph; remove the mapping if id is NULL */
86 int font_map(struct font
*fn
, char *name
, char *id
)
90 gidx
= font_glyph(fn
, id
) ? font_glyph(fn
, id
) - fn
->gl
: -2;
91 dict_put(&fn
->ch_map
, name
, gidx
);
95 /* return nonzero if character name has been mapped with font_map() */
96 int font_mapped(struct font
*fn
, char *name
)
98 return dict_get(&fn
->ch_map
, name
) != -1;
101 /* enable/disable ligatures; first bit for liga and the second bit for rlig */
102 static int font_featlg(struct font
*fn
, int val
)
105 ret
|= font_feat(fn
, "liga", val
& 1);
106 ret
|= font_feat(fn
, "rlig", val
& 2) << 1;
110 /* enable/disable pairwise kerning */
111 static int font_featkn(struct font
*fn
, int val
)
113 return font_feat(fn
, "kern", val
);
116 /* glyph index in fn->glyphs[] */
117 static int font_idx(struct font
*fn
, struct glyph
*g
)
119 return g
? g
- fn
->gl
: -1;
122 /* compare their hashes, then their positions to make qsort() stable */
123 static int grulecmp(void *v1
, void *v2
)
125 struct grule
*r1
= v1
;
126 struct grule
*r2
= v2
;
127 return r1
->hash
== r2
->hash
? r1
->pos
- r2
->pos
: r1
->hash
- r2
->hash
;
130 /* the hashing function for grule structs, based on their first two glyphs */
131 static int grule_hash(struct grule
*rule
)
133 int g1
= -1, g2
= -1;
135 /* finding the first glyph; -1 if FG_GRP */
136 while (i
< rule
->len
&& rule
->pats
[i
].flg
& (GF_REP
| GF_CON
))
137 i
++; /* skipping replacement and context glyphs */
138 if (i
< rule
->len
&& rule
->pats
[i
].flg
== GF_PAT
)
139 g1
= rule
->pats
[i
].g
;
141 /* finding the second glyph; -1 if FG_GRP */
142 while (i
< rule
->len
&& rule
->pats
[i
].flg
& GF_REP
)
143 i
++; /* skipping replacement glyphs */
144 if (i
< rule
->len
&& rule
->pats
[i
].flg
== GF_PAT
)
145 g2
= rule
->pats
[i
].g
;
146 return GHASH(g1
, g2
);
149 static int grule_find(struct grule
*rules
, int n
, int hash
)
154 int m
= (l
+ h
) >> 1;
155 if (rules
[m
].hash
>= hash
)
163 static int font_gpatmatch(struct font
*fn
, struct gpat
*p
, int g
)
166 if (!(p
->flg
& GF_GRP
))
168 for (i
= 0; i
< fn
->ggrp_len
[p
->g
]; i
++)
169 if (fn
->ggrp
[p
->g
][i
] == g
)
174 static int font_rulematch(struct font
*fn
, struct grule
*rule
,
175 int *src
, int slen
, int *dst
, int dlen
)
177 int sidx
= 0; /* the index of matched glyphs in src */
178 int ncon
= 0; /* number of initial context glyphs */
179 struct gpat
*pats
= rule
->pats
;
181 if (!fn
->feat_set
[rule
->feat
])
183 /* the number of initial context glyphs */
184 for (j
= 0; j
< rule
->len
&& pats
[j
].flg
& GF_CON
; j
++)
188 /* matching the base pattern */
189 for (; j
< rule
->len
; j
++) {
190 if (pats
[j
].flg
& GF_REP
)
192 if (sidx
>= slen
|| !font_gpatmatch(fn
, &pats
[j
], src
[sidx
]))
196 /* matching the initial context */
197 for (j
= 0; j
< rule
->len
&& pats
[j
].flg
& GF_CON
; j
++)
198 if (!font_gpatmatch(fn
, &pats
[j
], dst
[j
- ncon
]))
203 /* perform all possible gpos rules on src */
204 static void font_performgpos(struct font
*fn
, int *src
, int slen
,
205 int *x
, int *y
, int *xadv
, int *yadv
)
207 struct grule
*gpos
= fn
->gpos
;
210 for (i
= 0; i
< slen
; i
++) {
211 /* possible hash values for matching gpos rules at src + slen */
212 for (j
= 0; j
< 4 && j
< (slen
<< 1); j
++) {
213 int hash
= GHASH(j
& 1 ? src
[i
] : -1, j
& 2 ? src
[i
+ 1] : -1);
214 int idx
= grule_find(gpos
, n
, hash
);
215 while (idx
< n
&& gpos
[idx
].hash
== hash
) {
216 if (font_rulematch(fn
, &gpos
[idx
],
217 src
+ i
, slen
- i
, src
+ i
, i
)) {
218 struct gpat
*pats
= gpos
[idx
].pats
;
219 /* we should accumulate the values... */
220 for (k
= 0; k
< gpos
[idx
].len
; k
++) {
221 x
[i
+ k
] = pats
[k
].x
;
222 y
[i
+ k
] = pats
[k
].y
;
223 xadv
[i
+ k
] = pats
[k
].xadv
;
224 yadv
[i
+ k
] = pats
[k
].yadv
;
233 /* find the first gsub rule after pos that matches any glyph in src */
234 static struct grule
*font_firstgsub(struct font
*fn
, int pos
, int *src
, int slen
)
236 struct grule
*rules
= fn
->gsub
;
238 struct grule
*best
= NULL
;
240 for (i
= 0; i
< slen
; i
++) {
241 /* possible hash values for matching gsub rules at src + slen */
242 for (j
= 0; j
< 2 && i
+ j
< slen
; j
++) {
243 int hash
= GHASH(src
[i
], j
? src
[i
+ 1] : -1);
244 int idx
= grule_find(rules
, n
, hash
);
245 while (idx
< n
&& rules
[idx
].hash
== hash
&&
246 (!best
|| rules
[idx
].pos
< best
->pos
)) {
247 if (rules
[idx
].pos
>= pos
)
248 if (font_rulematch(fn
, &rules
[idx
],
249 src
+ i
, slen
- i
, src
+ i
, i
))
258 /* apply the given gsub rule to all matches in src */
259 static int font_gsubapply(struct font
*fn
, struct grule
*rule
,
260 int *src
, int slen
, int *smap
)
266 memset(dmap
, 0, slen
* sizeof(dmap
[i
]));
267 for (i
= 0; i
< slen
; i
++) {
268 int hash1
= GHASH(src
[i
], -1);
269 int hash2
= GHASH(src
[i
], i
+ 1 < slen
? src
[i
+ 1] : -1);
270 int hmatch
= rule
->hash
== hash1
|| rule
->hash
== hash2
;
271 dmap
[dlen
] = smap
[i
];
272 if (hmatch
&& font_rulematch(fn
, rule
, src
+ i
,
273 slen
- i
, dst
+ dlen
, dlen
)) {
274 for (j
= 0; j
< rule
->len
; j
++) {
275 if (rule
->pats
[j
].flg
& GF_REP
)
276 dst
[dlen
++] = rule
->pats
[j
].g
;
277 if (rule
->pats
[j
].flg
& GF_PAT
)
282 dst
[dlen
++] = src
[i
];
285 memcpy(src
, dst
, dlen
* sizeof(dst
[0]));
286 memcpy(smap
, dmap
, dlen
* sizeof(dmap
[0]));
290 /* perform all possible gsub rules on src */
291 static int font_performgsub(struct font
*fn
, int *src
, int slen
, int *smap
)
295 struct grule
*rule
= font_firstgsub(fn
, i
, src
, slen
);
297 slen
= font_gsubapply(fn
, rule
, src
, slen
, smap
);
298 i
= rule
? rule
->pos
+ 1 : -1;
303 int font_layout(struct font
*fn
, struct glyph
**gsrc
, int nsrc
, int sz
,
304 struct glyph
**gdst
, int *dmap
,
305 int *x
, int *y
, int *xadv
, int *yadv
, int lg
, int kn
)
311 /* initialising dst */
312 for (i
= 0; i
< nsrc
; i
++)
313 dst
[i
] = font_idx(fn
, gsrc
[i
]);
314 for (i
= 0; i
< ndst
; i
++)
316 memset(x
, 0, ndst
* sizeof(x
[0]));
317 memset(y
, 0, ndst
* sizeof(y
[0]));
318 memset(xadv
, 0, ndst
* sizeof(xadv
[0]));
319 memset(yadv
, 0, ndst
* sizeof(yadv
[0]));
320 /* substitution rules */
322 featlg
= font_featlg(fn
, 3);
323 ndst
= font_performgsub(fn
, dst
, ndst
, dmap
);
325 font_featlg(fn
, featlg
);
326 /* positioning rules */
328 featkn
= font_featkn(fn
, 1);
329 font_performgpos(fn
, dst
, ndst
, x
, y
, xadv
, yadv
);
331 font_featkn(fn
, featkn
);
332 for (i
= 0; i
< ndst
; i
++)
333 gdst
[i
] = fn
->gl
+ dst
[i
];
337 static int font_readchar(struct font
*fn
, FILE *fin
, int *n
, struct glyph
**g
)
343 if (*n
+ 1 == NGLYPHS
)
344 errmsg("neatroff: NGLYPHS too low\n");
347 if (fscanf(fin
, "%s %s", name
, tok
) != 2)
349 if (!strcmp("---", name
))
350 sprintf(name
, "c%04d", *n
);
351 if (strcmp("\"", tok
)) {
352 if (fscanf(fin
, "%d %s", &type
, id
) != 2)
354 *g
= font_glyph(fn
, id
);
356 *g
= font_glyphput(fn
, id
, name
, type
);
357 sscanf(tok
, "%hd,%hd,%hd,%hd,%hd", &(*g
)->wid
,
358 &(*g
)->llx
, &(*g
)->lly
, &(*g
)->urx
, &(*g
)->ury
);
361 dict_put(&fn
->ch_dict
, name
, *g
- fn
->gl
);
366 static int font_findfeat(struct font
*fn
, char *feat
, int mk
)
369 for (i
= 0; i
< fn
->feat_n
; i
++)
370 if (!strcmp(feat
, fn
->feat_name
[i
]))
373 strcpy(fn
->feat_name
[fn
->feat_n
], feat
);
374 return mk
? fn
->feat_n
++ : -1;
377 static struct gpat
*font_gpat(struct font
*fn
, int len
)
379 struct gpat
*pats
= xmalloc(len
* sizeof(pats
[0]));
380 memset(pats
, 0, len
* sizeof(pats
[0]));
384 static struct grule
*font_gsub(struct font
*fn
, char *feat
, int len
)
387 struct gpat
*pats
= font_gpat(fn
, len
);
388 if (fn
->gsub_n
+ 1 == LEN(fn
->gsub
))
389 errmsg("neatroff: NGRULES too low\n");
390 if (fn
->gsub_n
>= LEN(fn
->gsub
) || !pats
)
392 rule
= &fn
->gsub
[fn
->gsub_n
++];
395 rule
->feat
= font_findfeat(fn
, feat
, 1);
399 static struct grule
*font_gpos(struct font
*fn
, char *feat
, int len
)
402 struct gpat
*pats
= font_gpat(fn
, len
);
403 if (fn
->gpos_n
+ 1 == LEN(fn
->gpos
))
404 errmsg("neatroff: NGRULES too low\n");
405 if (fn
->gpos_n
>= LEN(fn
->gpos
) || !pats
)
407 rule
= &fn
->gpos
[fn
->gpos_n
++];
410 rule
->feat
= font_findfeat(fn
, feat
, 1);
414 static int font_readgpat(struct font
*fn
, struct gpat
*p
, char *s
)
418 if (fn
->ggrp_len
[p
->g
] == 1)
419 p
->g
= fn
->ggrp
[p
->g
][0];
423 p
->g
= font_idx(fn
, font_glyph(fn
, s
));
428 static int font_readgsub(struct font
*fn
, FILE *fin
)
433 if (fscanf(fin
, "%s %d", tok
, &n
) != 2)
435 if (!(rule
= font_gsub(fn
, tok
, n
)))
437 for (i
= 0; i
< n
; i
++) {
438 if (fscanf(fin
, "%s", tok
) != 1)
441 rule
->pats
[i
].flg
= GF_PAT
;
443 rule
->pats
[i
].flg
= GF_CON
;
445 rule
->pats
[i
].flg
= GF_REP
;
446 if (!tok
[0] || font_readgpat(fn
, &rule
->pats
[i
], tok
+ 1))
452 static int font_readgpos(struct font
*fn
, FILE *fin
)
458 if (fscanf(fin
, "%s %d", tok
, &n
) != 2)
460 if (!(rule
= font_gpos(fn
, tok
, n
)))
462 for (i
= 0; i
< n
; i
++) {
463 if (fscanf(fin
, "%s", tok
) != 1)
465 col
= strchr(tok
, ':');
468 rule
->pats
[i
].flg
= GF_PAT
;
469 if (!tok
[0] || font_readgpat(fn
, &rule
->pats
[i
], tok
))
472 sscanf(col
+ 1, "%hd%hd%hd%hd",
473 &rule
->pats
[i
].x
, &rule
->pats
[i
].y
,
474 &rule
->pats
[i
].xadv
, &rule
->pats
[i
].yadv
);
479 static int font_readggrp(struct font
*fn
, FILE *fin
)
483 if (fscanf(fin
, "%d %d", &id
, &n
) != 2)
485 if (id
>= LEN(fn
->ggrp
)) {
486 errmsg("neatroff: NGRULES too low\n");
491 fn
->ggrp
[id
] = xmalloc(n
* sizeof(fn
->ggrp
[id
][0]));
492 fn
->ggrp_len
[id
] = 0;
493 for (i
= 0; i
< n
; i
++) {
494 if (fscanf(fin
, "%s", tok
) != 1)
496 g
= font_idx(fn
, font_glyph(fn
, tok
));
498 fn
->ggrp
[id
][fn
->ggrp_len
[id
]++] = g
;
503 static int font_readkern(struct font
*fn
, FILE *fin
)
505 char c1
[ILNLEN
], c2
[ILNLEN
];
508 if (fscanf(fin
, "%s %s %d", c1
, c2
, &val
) != 3)
510 if (!(rule
= font_gpos(fn
, "kern", 2)))
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
;
520 static void font_lig(struct font
*fn
, char *lig
)
527 while (utf8read(&s
, c
) > 0)
528 g
[n
++] = font_idx(fn
, font_find(fn
, c
));
529 if (!(rule
= font_gsub(fn
, "liga", n
+ 1)))
531 for (j
= 0; j
< n
; j
++) {
532 rule
->pats
[j
].g
= g
[j
];
533 rule
->pats
[j
].flg
= GF_PAT
;
535 rule
->pats
[n
].g
= font_idx(fn
, font_find(fn
, lig
));
536 rule
->pats
[n
].flg
= GF_REP
;
539 static void skipline(FILE* filp
)
544 } while (c
!= '\n' && c
!= EOF
);
547 struct font
*font_open(char *path
)
550 struct glyph
*ch_g
= NULL
; /* last glyph in the charset */
551 int ch_n
= 0; /* number of glyphs in the charset */
554 char ligs
[512][GNLEN
];
557 fin
= fopen(path
, "r");
560 fn
= xmalloc(sizeof(*fn
));
565 memset(fn
, 0, sizeof(*fn
));
566 dict_init(&fn
->gl_dict
, NGLYPHS
, -1, 0, 0);
567 dict_init(&fn
->ch_dict
, NGLYPHS
, -1, 1, 0);
568 dict_init(&fn
->ch_map
, NGLYPHS
, -1, 1, 0);
569 while (fscanf(fin
, "%s", tok
) == 1) {
570 if (!strcmp("char", tok
)) {
571 font_readchar(fn
, fin
, &ch_n
, &ch_g
);
572 } else if (!strcmp("kern", tok
)) {
573 font_readkern(fn
, fin
);
574 } else if (!strcmp("ligatures", tok
)) {
575 while (fscanf(fin
, "%s", ligs
[ligs_n
]) == 1) {
576 if (!strcmp("0", ligs
[ligs_n
]))
578 if (ligs_n
< LEN(ligs
))
581 } else if (!strcmp("gsub", tok
)) {
582 font_readgsub(fn
, fin
);
583 } else if (!strcmp("gpos", tok
)) {
584 font_readgpos(fn
, fin
);
585 } else if (!strcmp("ggrp", tok
)) {
586 font_readggrp(fn
, fin
);
587 } else if (!strcmp("spacewidth", tok
)) {
588 fscanf(fin
, "%d", &fn
->spacewid
);
589 } else if (!strcmp("special", tok
)) {
591 } else if (!strcmp("name", tok
)) {
592 fscanf(fin
, "%s", fn
->name
);
593 } else if (!strcmp("fontname", tok
)) {
594 fscanf(fin
, "%s", fn
->fontname
);
595 } else if (!strcmp("charset", tok
)) {
596 while (!font_readchar(fn
, fin
, &ch_n
, &ch_g
))
602 for (i
= 0; i
< ligs_n
; i
++)
603 font_lig(fn
, ligs
[i
]);
605 for (i
= 0; i
< fn
->gsub_n
; i
++)
607 for (i
= 0; i
< fn
->gpos_n
; i
++)
609 for (i
= 0; i
< fn
->gsub_n
; i
++)
610 fn
->gsub
[i
].hash
= grule_hash(&fn
->gsub
[i
]);
611 for (i
= 0; i
< fn
->gpos_n
; i
++)
612 fn
->gpos
[i
].hash
= grule_hash(&fn
->gpos
[i
]);
613 qsort(fn
->gsub
, fn
->gsub_n
, sizeof(fn
->gsub
[0]), (void *) grulecmp
);
614 qsort(fn
->gpos
, fn
->gpos_n
, sizeof(fn
->gpos
[0]), (void *) grulecmp
);
618 void font_close(struct font
*fn
)
621 for (i
= 0; i
< fn
->gsub_n
; i
++)
622 free(fn
->gsub
[i
].pats
);
623 for (i
= 0; i
< fn
->gpos_n
; i
++)
624 free(fn
->gpos
[i
].pats
);
625 for (i
= 0; i
< LEN(fn
->ggrp
); i
++)
627 dict_done(&fn
->gl_dict
);
628 dict_done(&fn
->ch_dict
);
629 dict_done(&fn
->ch_map
);
633 int font_special(struct font
*fn
)
638 /* return width w for the given font and size */
639 int font_wid(struct font
*fn
, int sz
, int w
)
641 sz
= font_zoom(fn
, sz
);
642 return w
>= 0 ? DEVWID(sz
, w
) : -DEVWID(sz
, -w
);
645 /* glyph width, where cfn is the current font and fn is glyph's font */
646 int font_gwid(struct font
*fn
, struct font
*cfn
, int sz
, int w
)
649 return cfn
->cs
* (font_zoom(fn
, cfn
->cs_ps
? cfn
->cs_ps
: sz
)
651 return font_wid(fn
, sz
, w
) + (font_getbd(cfn
) ? font_getbd(cfn
) - 1 : 0);
654 /* space width for the give word space or sentence space */
655 int font_swid(struct font
*fn
, int sz
, int ss
)
657 return font_gwid(fn
, fn
, sz
, (fn
->spacewid
* ss
+ 6) / 12);
660 int font_getcs(struct font
*fn
)
665 void font_setcs(struct font
*fn
, int cs
, int ps
)
671 int font_getbd(struct font
*fn
)
676 void font_setbd(struct font
*fn
, int bd
)
681 int font_zoom(struct font
*fn
, int sz
)
683 return fn
->zoom
? (sz
* fn
->zoom
+ 500) / 1000 : sz
;
686 void font_setzoom(struct font
*fn
, int zoom
)
691 /* enable/disable font features; returns the previous value */
692 int font_feat(struct font
*fn
, char *name
, int val
)
694 int idx
= font_findfeat(fn
, name
, 0);
695 int old
= idx
>= 0 ? fn
->feat_set
[idx
] : 0;
697 fn
->feat_set
[idx
] = val
!= 0;