font: unmap glyphs with .fmap
[neatroff.git] / wb.c
blobcac88570ba68dd733a7232185abdc184d648ede3
1 /* word buffer */
2 #include <ctype.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include "roff.h"
8 /* the current font, size and color */
9 #define R_F(wb) ((wb)->r_f >= 0 ? (wb)->r_f : n_f) /* current font */
10 #define R_S(wb) ((wb)->r_s >= 0 ? (wb)->r_s : n_s) /* current size */
11 #define R_M(wb) ((wb)->r_m >= 0 ? (wb)->r_m : n_m) /* current color */
12 /* italic correction */
13 #define glyph_ic(g) (MAX(0, (g)->urx - (g)->wid))
14 #define glyph_icleft(g) (MAX(0, -(g)->llx))
15 /* the maximum and minimum values of bounding box coordinates */
16 #define BBMAX (1 << 29)
17 #define BBMIN -BBMAX
19 static void wb_flushsub(struct wb *wb);
21 void wb_init(struct wb *wb)
23 memset(wb, 0, sizeof(*wb));
24 sbuf_init(&wb->sbuf);
25 wb->sub_collect = 1;
26 wb->f = -1;
27 wb->s = -1;
28 wb->m = -1;
29 wb->r_f = -1;
30 wb->r_s = -1;
31 wb->r_m = -1;
32 wb->llx = BBMAX;
33 wb->lly = BBMAX;
34 wb->urx = BBMIN;
35 wb->ury = BBMIN;
38 void wb_done(struct wb *wb)
40 sbuf_done(&wb->sbuf);
43 /* update wb->st and wb->sb */
44 static void wb_stsb(struct wb *wb)
46 wb->st = MIN(wb->st, wb->v - (wb->s * SC_IN / 72));
47 wb->sb = MAX(wb->sb, wb->v);
50 /* update bounding box */
51 static void wb_bbox(struct wb *wb, int llx, int lly, int urx, int ury)
53 wb->llx = MIN(wb->llx, wb->h + llx);
54 wb->lly = MIN(wb->lly, -wb->v + lly);
55 wb->urx = MAX(wb->urx, wb->h + urx);
56 wb->ury = MAX(wb->ury, -wb->v + ury);
59 /* pending font, size or color changes */
60 static int wb_pendingfont(struct wb *wb)
62 return wb->f != R_F(wb) || wb->s != R_S(wb) ||
63 (!n_cp && wb->m != R_M(wb));
66 /* append font and size to the buffer if needed */
67 static void wb_flushfont(struct wb *wb)
69 if (wb->f != R_F(wb)) {
70 sbuf_printf(&wb->sbuf, "%cf(%02d", c_ec, R_F(wb));
71 wb->f = R_F(wb);
73 if (wb->s != R_S(wb)) {
74 if (R_S(wb) < 100)
75 sbuf_printf(&wb->sbuf, "%cs(%02d", c_ec, R_S(wb));
76 else
77 sbuf_printf(&wb->sbuf, "%cs[%d]", c_ec, R_S(wb));
78 wb->s = R_S(wb);
80 if (!n_cp && wb->m != R_M(wb)) {
81 sbuf_printf(&wb->sbuf, "%cm[%s]", c_ec, clr_str(R_M(wb)));
82 wb->m = R_M(wb);
84 wb_stsb(wb);
87 /* apply font and size changes and flush the collected subword */
88 static void wb_flush(struct wb *wb)
90 wb_flushsub(wb);
91 wb_flushfont(wb);
94 void wb_hmov(struct wb *wb, int n)
96 wb_flushsub(wb);
97 wb->h += n;
98 sbuf_printf(&wb->sbuf, "%ch'%du'", c_ec, n);
101 void wb_vmov(struct wb *wb, int n)
103 wb_flushsub(wb);
104 wb->v += n;
105 sbuf_printf(&wb->sbuf, "%cv'%du'", c_ec, n);
108 void wb_els(struct wb *wb, int els)
110 wb_flushsub(wb);
111 if (els > wb->els_pos)
112 wb->els_pos = els;
113 if (els < wb->els_neg)
114 wb->els_neg = els;
115 sbuf_printf(&wb->sbuf, "%cx'%du'", c_ec, els);
118 void wb_etc(struct wb *wb, char *x)
120 wb_flush(wb);
121 sbuf_printf(&wb->sbuf, "%cX\x02%s\x02", c_ec, x);
124 static void wb_putbuf(struct wb *wb, char *c)
126 struct glyph *g;
127 int zerowidth;
128 if (c[0] == '\t' || c[0] == '\x01' ||
129 (c[0] == c_ni && (c[1] == '\t' || c[1] == '\x01'))) {
130 sbuf_append(&wb->sbuf, c);
131 return;
133 g = dev_glyph(c, wb->f);
134 zerowidth = c_hymark(c);
135 if (!g && c[0] == c_ec && !zerowidth) { /* unknown escape */
136 memmove(c, c + 1, strlen(c));
137 g = dev_glyph(c, wb->f);
139 if (g && !zerowidth && wb->icleft && glyph_icleft(g))
140 wb_hmov(wb, font_wid(g->font, wb->s, glyph_icleft(g)));
141 wb->icleft = 0;
142 if (!c[1] || c[0] == c_ec || c[0] == c_ni || utf8one(c)) {
143 if (c[0] == c_ni && c[1] == c_ec)
144 sbuf_printf(&wb->sbuf, "%c%c", c_ec, c_ec);
145 else
146 sbuf_append(&wb->sbuf, c);
147 } else {
148 if (c[1] && !c[2])
149 sbuf_printf(&wb->sbuf, "%c(%s", c_ec, c);
150 else
151 sbuf_printf(&wb->sbuf, "%cC'%s'", c_ec, c);
153 if (!zerowidth) {
154 if (!n_cp && g)
155 wb_bbox(wb, font_wid(g->font, wb->s, g->llx),
156 font_wid(g->font, wb->s, g->lly),
157 font_wid(g->font, wb->s, g->urx),
158 font_wid(g->font, wb->s, g->ury));
159 wb->h += g ? font_gwid(g->font, dev_font(wb->f), wb->s, g->wid) : 0;
160 wb->ct |= g ? g->type : 0;
161 wb_stsb(wb);
165 /* return nonzero if it cannot be hyphenated */
166 static int wb_hyph(char src[][GNLEN], int src_n, char *src_hyph, int flg)
168 char word[WORDLEN * GNLEN]; /* word to pass to hyphenate() */
169 char hyph[WORDLEN * GNLEN]; /* hyphenation points of word */
170 int smap[WORDLEN]; /* the mapping from src[] to word[] */
171 char *s, *d;
172 int i;
173 d = word;
174 *d = '\0';
175 for (i = 0; i < src_n; i++) {
176 s = src[i];
177 smap[i] = d - word;
178 if (c_hystop(s))
179 return 1;
180 if (c_hymark(s))
181 continue;
182 d += hy_cput(d, s);
184 memset(hyph, 0, (d - word) * sizeof(hyph[0]));
185 hyphenate(hyph, word, flg);
186 for (i = 0; i < src_n; i++)
187 src_hyph[i] = hyph[smap[i]];
188 return 0;
191 static int wb_collect(struct wb *wb, int val)
193 int old = wb->sub_collect;
194 wb->sub_collect = val;
195 return old;
198 /* output the collected characters; only for those present in wb->f font */
199 static void wb_flushsub(struct wb *wb)
201 struct font *fn;
202 struct glyph *gsrc[WORDLEN];
203 struct glyph *gdst[WORDLEN];
204 int x[WORDLEN], y[WORDLEN], xadv[WORDLEN], yadv[WORDLEN];
205 int dmap[WORDLEN];
206 char src_hyph[WORDLEN];
207 int dst_n, i;
208 int sidx = 0;
209 if (!wb->sub_n || !wb->sub_collect)
210 return;
211 wb->sub_collect = 0;
212 fn = dev_font(wb->f);
213 if (!n_hy || wb_hyph(wb->sub_c, wb->sub_n, src_hyph, n_hy))
214 memset(src_hyph, 0, sizeof(src_hyph));
215 /* call font_layout() for collected glyphs; skip hyphenation marks */
216 while (sidx < wb->sub_n) {
217 int beg = sidx;
218 for (; sidx < wb->sub_n && !c_hymark(wb->sub_c[sidx]); sidx++)
219 gsrc[sidx - beg] = font_find(fn, wb->sub_c[sidx]);
220 dst_n = font_layout(fn, gsrc, sidx - beg, wb->s,
221 gdst, dmap, x, y, xadv, yadv, n_lg, n_kn);
222 for (i = 0; i < dst_n; i++) {
223 if (x[i])
224 wb_hmov(wb, font_wid(fn, wb->s, x[i]));
225 if (y[i])
226 wb_vmov(wb, font_wid(fn, wb->s, y[i]));
227 if (src_hyph[beg + dmap[i]])
228 wb_putbuf(wb, c_hc);
229 if (gdst[i] == gsrc[dmap[i]])
230 wb_putbuf(wb, wb->sub_c[beg + dmap[i]]);
231 else
232 wb_putbuf(wb, gdst[i]->name);
233 if (x[i] || xadv[i])
234 wb_hmov(wb, font_wid(fn, wb->s, xadv[i] - x[i]));
235 if (y[i] || yadv[i])
236 wb_vmov(wb, font_wid(fn, wb->s, yadv[i] - y[i]));
238 for (; sidx < wb->sub_n && c_hymark(wb->sub_c[sidx]); sidx++)
239 wb_putbuf(wb, wb->sub_c[sidx]);
241 wb->sub_n = 0;
242 wb->icleft = 0;
243 wb->sub_collect = 1;
246 void wb_put(struct wb *wb, char *c)
248 if (c[0] == '\n') {
249 wb->part = 0;
250 return;
252 if (c[0] == ' ') {
253 wb_flushsub(wb);
254 wb_hmov(wb, font_swid(dev_font(R_F(wb)), R_S(wb), n_ss));
255 return;
257 if (!strcmp(c_nb, c)) {
258 wb_flushsub(wb);
259 sbuf_append(&wb->sbuf, c);
260 wb->h += font_swid(dev_font(R_F(wb)), R_S(wb), n_ss);
261 return;
263 if (wb_pendingfont(wb) || wb->sub_n == LEN(wb->sub_c))
264 wb_flush(wb);
265 if (wb->sub_collect) {
266 if (font_find(dev_font(wb->f), c) || c_hymark(c))
267 strcpy(wb->sub_c[wb->sub_n++], c);
268 else
269 wb_putraw(wb, c);
270 } else {
271 wb_putbuf(wb, c);
275 /* just like wb_put() but disable subword collection */
276 void wb_putraw(struct wb *wb, char *c)
278 int collect;
279 wb_flushsub(wb);
280 collect = wb_collect(wb, 0);
281 wb_put(wb, c);
282 wb_collect(wb, collect);
285 /* just like wb_put(), but call cdef_expand() if c is defined */
286 void wb_putexpand(struct wb *wb, char *c)
288 if (cdef_expand(wb, c, R_F(wb)))
289 wb_put(wb, c);
292 int wb_part(struct wb *wb)
294 return wb->part;
297 void wb_setpart(struct wb *wb)
299 wb->part = 1;
302 int wb_cost(struct wb *wb)
304 return wb->cost;
307 void wb_setcost(struct wb *wb, int cost)
309 wb->cost = cost;
312 void wb_drawl(struct wb *wb, int c, int h, int v)
314 wb_flush(wb);
315 sbuf_printf(&wb->sbuf, "%cD'%c %du %du'", c_ec, c, h, v);
316 wb->h += h;
317 wb->v += v;
318 wb_stsb(wb);
321 void wb_drawc(struct wb *wb, int c, int r)
323 wb_flush(wb);
324 sbuf_printf(&wb->sbuf, "%cD'%c %du'", c_ec, c, r);
325 wb->h += r;
328 void wb_drawe(struct wb *wb, int c, int h, int v)
330 wb_flush(wb);
331 sbuf_printf(&wb->sbuf, "%cD'%c %du %du'", c_ec, c, h, v);
332 wb->h += h;
335 void wb_drawa(struct wb *wb, int c, int h1, int v1, int h2, int v2)
337 wb_flush(wb);
338 sbuf_printf(&wb->sbuf, "%cD'%c %du %du %du %du'",
339 c_ec, c, h1, v1, h2, v2);
340 wb->h += h1 + h2;
341 wb->v += v1 + v2;
342 wb_stsb(wb);
345 void wb_drawxbeg(struct wb *wb, int c)
347 wb_flush(wb);
348 sbuf_printf(&wb->sbuf, "%cD'%c", c_ec, c);
351 void wb_drawxdot(struct wb *wb, int h, int v)
353 sbuf_printf(&wb->sbuf, " %du %du", h, v);
354 wb->h += h;
355 wb->v += v;
356 wb_stsb(wb);
359 void wb_drawxcmd(struct wb *wb, char *cmd)
361 sbuf_printf(&wb->sbuf, " %s", cmd);
364 void wb_drawxend(struct wb *wb)
366 sbuf_printf(&wb->sbuf, "'");
369 void wb_reset(struct wb *wb)
371 wb_done(wb);
372 wb_init(wb);
375 char *wb_buf(struct wb *wb)
377 wb_flushsub(wb);
378 return sbuf_buf(&wb->sbuf);
381 static void wb_putc(struct wb *wb, int t, char *s)
383 if (t && t != 'C')
384 wb_flushsub(wb);
385 switch (t) {
386 case 0:
387 case 'C':
388 wb_put(wb, s);
389 break;
390 case 'D':
391 ren_dcmd(wb, s);
392 break;
393 case 'f':
394 wb->r_f = atoi(s);
395 break;
396 case 'h':
397 wb_hmov(wb, atoi(s));
398 break;
399 case 'm':
400 wb->r_m = clr_get(s);
401 break;
402 case 's':
403 wb->r_s = atoi(s);
404 break;
405 case 'v':
406 wb_vmov(wb, atoi(s));
407 break;
408 case 'x':
409 wb_els(wb, atoi(s));
410 break;
411 case 'X':
412 wb_etc(wb, s);
413 break;
417 void wb_cat(struct wb *wb, struct wb *src)
419 char *s, *d;
420 int c, part;
421 int collect;
422 wb_flushsub(src);
423 wb_flushsub(wb);
424 collect = wb_collect(wb, 0);
425 s = sbuf_buf(&src->sbuf);
426 while ((c = escread(&s, &d)) >= 0)
427 wb_putc(wb, c, d);
428 part = src->part;
429 wb->r_s = -1;
430 wb->r_f = -1;
431 wb->r_m = -1;
432 wb_reset(src);
433 src->part = part;
434 wb_collect(wb, collect);
437 int wb_wid(struct wb *wb)
439 wb_flushsub(wb);
440 return wb->h;
443 int wb_hpos(struct wb *wb)
445 wb_flushsub(wb);
446 return wb->h;
449 int wb_vpos(struct wb *wb)
451 wb_flushsub(wb);
452 return wb->v;
455 int wb_empty(struct wb *wb)
457 return !wb->sub_n && sbuf_empty(&wb->sbuf);
460 /* return 1 if wb ends a sentence (.?!) */
461 int wb_eos(struct wb *wb)
463 int i = wb->sub_n - 1;
464 while (i > 0 && c_eostran(wb->sub_c[i]))
465 i--;
466 return i >= 0 && c_eossent(wb->sub_c[i]);
469 void wb_wconf(struct wb *wb, int *ct, int *st, int *sb,
470 int *llx, int *lly, int *urx, int *ury)
472 wb_flushsub(wb);
473 *ct = wb->ct;
474 *st = -wb->st;
475 *sb = -wb->sb;
476 *llx = wb->llx < BBMAX ? wb->llx : 0;
477 *lly = wb->lly < BBMAX ? -wb->lly : 0;
478 *urx = wb->urx > BBMIN ? wb->urx : 0;
479 *ury = wb->ury > BBMIN ? -wb->ury : 0;
482 static struct glyph *wb_prevglyph(struct wb *wb)
484 return wb->sub_n ? dev_glyph(wb->sub_c[wb->sub_n - 1], wb->f) : NULL;
487 void wb_italiccorrection(struct wb *wb)
489 struct glyph *g = wb_prevglyph(wb);
490 if (g && glyph_ic(g))
491 wb_hmov(wb, font_wid(g->font, wb->s, glyph_ic(g)));
494 void wb_italiccorrectionleft(struct wb *wb)
496 wb_flushsub(wb);
497 wb->icleft = 1;
500 void wb_fnszget(struct wb *wb, int *fn, int *sz, int *m)
502 wb_flushsub(wb);
503 *fn = wb->r_f;
504 *sz = wb->r_s;
505 *m = wb->r_m;
508 void wb_fnszset(struct wb *wb, int fn, int sz, int m)
510 wb->r_f = fn;
511 wb->r_s = sz;
512 wb->r_m = m;
515 void wb_catstr(struct wb *wb, char *s, char *end)
517 int collect, c;
518 char *d;
519 wb_flushsub(wb);
520 collect = wb_collect(wb, 0);
521 while (s < end && (c = escread(&s, &d)) >= 0)
522 wb_putc(wb, c, d);
523 wb_collect(wb, collect);
526 /* return the size of \(hy if appended to wb */
527 int wb_hywid(struct wb *wb)
529 struct glyph *g = dev_glyph("hy", wb->f);
530 return g ? font_gwid(g->font, dev_font(R_F(wb)), R_S(wb), g->wid) : 0;
533 /* return the size of space if appended to wb */
534 int wb_swid(struct wb *wb)
536 return font_swid(dev_font(R_F(wb)), R_S(wb), n_ss);