font: "ggrp" lines in font descriptions define character groups
[neatroff.git] / wb.c
blobd54eae1bf036e08e882a236e9297ef9e25f988b6
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 /* like DEVWID() but handles negative w */
16 #define SDEVWID(sz, w) ((w) >= 0 ? DEVWID((sz), (w)) : -DEVWID((sz), -(w)))
17 /* the maximum and minimum values of bounding box coordinates */
18 #define BBMAX (1 << 29)
19 #define BBMIN -BBMAX
21 static void wb_flushsub(struct wb *wb);
23 void wb_init(struct wb *wb)
25 memset(wb, 0, sizeof(*wb));
26 sbuf_init(&wb->sbuf);
27 wb->sub_collect = 1;
28 wb->f = -1;
29 wb->s = -1;
30 wb->m = -1;
31 wb->r_f = -1;
32 wb->r_s = -1;
33 wb->r_m = -1;
34 wb->llx = BBMAX;
35 wb->lly = BBMAX;
36 wb->urx = BBMIN;
37 wb->ury = BBMIN;
40 void wb_done(struct wb *wb)
42 sbuf_done(&wb->sbuf);
45 /* update wb->st and wb->sb */
46 static void wb_stsb(struct wb *wb)
48 wb->st = MIN(wb->st, wb->v - (wb->s * SC_IN / 72));
49 wb->sb = MAX(wb->sb, wb->v);
52 /* update bounding box */
53 static void wb_bbox(struct wb *wb, int llx, int lly, int urx, int ury)
55 wb->llx = MIN(wb->llx, wb->h + llx);
56 wb->lly = MIN(wb->lly, -wb->v + lly);
57 wb->urx = MAX(wb->urx, wb->h + urx);
58 wb->ury = MAX(wb->ury, -wb->v + ury);
61 /* pending font, size or color changes */
62 static int wb_pendingfont(struct wb *wb)
64 return wb->f != R_F(wb) || wb->s != R_S(wb) ||
65 (!n_cp && wb->m != R_M(wb));
68 /* append font and size to the buffer if needed */
69 static void wb_flushfont(struct wb *wb)
71 if (wb->f != R_F(wb)) {
72 sbuf_printf(&wb->sbuf, "%cf(%02d", c_ec, R_F(wb));
73 wb->f = R_F(wb);
75 if (wb->s != R_S(wb)) {
76 sbuf_printf(&wb->sbuf, "%cs(%02d", c_ec, R_S(wb));
77 wb->s = R_S(wb);
79 if (!n_cp && wb->m != R_M(wb)) {
80 sbuf_printf(&wb->sbuf, "%cm[%s]", c_ec, clr_str(R_M(wb)));
81 wb->m = R_M(wb);
83 wb_stsb(wb);
86 /* apply font and size changes and flush the collected subword */
87 static void wb_flush(struct wb *wb)
89 wb_flushsub(wb);
90 wb_flushfont(wb);
93 void wb_hmov(struct wb *wb, int n)
95 wb_flushsub(wb);
96 wb->h += n;
97 sbuf_printf(&wb->sbuf, "%ch'%du'", c_ec, n);
100 void wb_vmov(struct wb *wb, int n)
102 wb_flushsub(wb);
103 wb->v += n;
104 sbuf_printf(&wb->sbuf, "%cv'%du'", c_ec, n);
107 void wb_els(struct wb *wb, int els)
109 wb_flushsub(wb);
110 if (els > wb->els_pos)
111 wb->els_pos = els;
112 if (els < wb->els_neg)
113 wb->els_neg = els;
114 sbuf_printf(&wb->sbuf, "%cx'%du'", c_ec, els);
117 void wb_etc(struct wb *wb, char *x)
119 wb_flush(wb);
120 sbuf_printf(&wb->sbuf, "%cX\x02%s\x02", c_ec, x);
123 static void wb_putbuf(struct wb *wb, char *c)
125 struct glyph *g;
126 int zerowidth;
127 if (c[0] == '\t' || c[0] == '\x01' ||
128 (c[0] == c_ni && (c[1] == '\t' || c[1] == '\x01'))) {
129 sbuf_append(&wb->sbuf, c);
130 return;
132 g = dev_glyph(c, wb->f);
133 zerowidth = !strcmp(c_hc, c) || !strcmp(c_bp, c);
134 if (!g && c[0] == c_ec && !zerowidth) { /* unknown escape */
135 memmove(c, c + 1, strlen(c));
136 g = dev_glyph(c, wb->f);
138 if (g && !zerowidth && wb->icleft && glyph_icleft(g))
139 wb_hmov(wb, SDEVWID(wb->s, glyph_icleft(g)));
140 wb->icleft = 0;
141 if (!c[1] || c[0] == c_ec || c[0] == c_ni || utf8one(c)) {
142 if (c[0] == c_ni && c[1] == c_ec)
143 sbuf_printf(&wb->sbuf, "%c%c", c_ec, c_ec);
144 else
145 sbuf_append(&wb->sbuf, c);
146 } else {
147 if (c[1] && !c[2])
148 sbuf_printf(&wb->sbuf, "%c(%s", c_ec, c);
149 else
150 sbuf_printf(&wb->sbuf, "%cC'%s'", c_ec, c);
152 if (!zerowidth) {
153 if (!n_cp && g)
154 wb_bbox(wb, SDEVWID(wb->s, g->llx),
155 SDEVWID(wb->s, g->lly),
156 SDEVWID(wb->s, g->urx),
157 SDEVWID(wb->s, g->ury));
158 wb->h += charwid(wb->f, wb->s, g ? g->wid : 0);
159 wb->ct |= g ? g->type : 0;
160 wb_stsb(wb);
164 int c_isdash(char *c)
166 return !strcmp("-", c) || !strcmp("em", c) || !strcmp("hy", c);
169 /* return nonzero if it cannot be hyphenated */
170 static int wb_hyph(char src[][GNLEN], int src_n, char *src_hyph, int flg)
172 char word[WORDLEN * GNLEN]; /* word to pass to hyphenate() */
173 char hyph[WORDLEN * GNLEN]; /* hyphenation points of word */
174 int smap[WORDLEN]; /* the mapping from src[] to word[] */
175 char *s, *d;
176 int i;
177 d = word;
178 *d = '\0';
179 for (i = 0; i < src_n; i++) {
180 s = src[i];
181 smap[i] = d - word;
182 if (c_isdash(s) || !strcmp(c_hc, s))
183 return 1;
184 if (!strcmp(c_bp, s))
185 continue;
186 if (!utf8one(s) || (!s[1] && !isalpha((unsigned char) s[0])))
187 strcpy(d, ".");
188 else
189 strcpy(d, s);
190 d = strchr(d, '\0');
192 memset(hyph, 0, (d - word) * sizeof(hyph[0]));
193 hyphenate(hyph, word, flg);
194 for (i = 0; i < src_n; i++)
195 src_hyph[i] = hyph[smap[i]];
196 return 0;
199 static int wb_collect(struct wb *wb, int val)
201 int old = wb->sub_collect;
202 wb->sub_collect = val;
203 return old;
206 static void wb_flushsub(struct wb *wb)
208 struct font *fn;
209 struct glyph *gsrc[WORDLEN];
210 struct glyph *gdst[WORDLEN];
211 int x[WORDLEN], y[WORDLEN], xadv[WORDLEN], yadv[WORDLEN];
212 int dmap[WORDLEN];
213 char src_hyph[WORDLEN];
214 int dst_n, i;
215 if (!wb->sub_n || !wb->sub_collect)
216 return;
217 wb->sub_collect = 0;
218 fn = dev_font(wb->f);
219 if (!n_hy || wb_hyph(wb->sub_c, wb->sub_n, src_hyph, n_hy))
220 memset(src_hyph, 0, sizeof(src_hyph));
221 for (i = 0; i < wb->sub_n; i++)
222 gsrc[i] = font_find(fn, wb->sub_c[i]);
223 dst_n = font_layout(fn, gsrc, wb->sub_n, wb->s,
224 gdst, dmap, x, y, xadv, yadv, n_lg, n_kn);
225 for (i = 0; i < dst_n; i++) {
226 if (x[i])
227 wb_hmov(wb, DEVWID(wb->s, x[i]));
228 if (y[i])
229 wb_vmov(wb, DEVWID(wb->s, y[i]));
230 if (src_hyph[dmap[i]])
231 wb_putbuf(wb, c_hc);
232 if (gdst[i] == gsrc[dmap[i]])
233 wb_putbuf(wb, wb->sub_c[dmap[i]]);
234 else
235 wb_putbuf(wb, gdst[i]->name);
236 if (x[i] || xadv[i])
237 wb_hmov(wb, DEVWID(wb->s, xadv[i] - x[i]));
238 if (y[i] || yadv[i])
239 wb_vmov(wb, DEVWID(wb->s, yadv[i] - y[i]));
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, N_SS(R_F(wb), R_S(wb)));
255 return;
257 if (wb_pendingfont(wb) || wb->sub_n == LEN(wb->sub_c))
258 wb_flush(wb);
259 if (wb->sub_collect) {
260 if (font_find(dev_font(wb->f), c))
261 strcpy(wb->sub_c[wb->sub_n++], c);
262 else
263 wb_putraw(wb, c);
264 } else {
265 wb_putbuf(wb, c);
269 /* just like wb_put() but disable subword collection */
270 void wb_putraw(struct wb *wb, char *c)
272 int collect;
273 wb_flushsub(wb);
274 collect = wb_collect(wb, 0);
275 wb_put(wb, c);
276 wb_collect(wb, collect);
279 /* just like wb_put(), but call cdef_expand() if c is defined */
280 void wb_putexpand(struct wb *wb, char *c)
282 if (cdef_expand(wb, c, R_F(wb)))
283 wb_put(wb, c);
286 int wb_part(struct wb *wb)
288 return wb->part;
291 void wb_setpart(struct wb *wb)
293 wb->part = 1;
296 void wb_drawl(struct wb *wb, int c, int h, int v)
298 wb_flush(wb);
299 sbuf_printf(&wb->sbuf, "%cD'%c %du %du'", c_ec, c, h, v);
300 wb->h += h;
301 wb->v += v;
302 wb_stsb(wb);
305 void wb_drawc(struct wb *wb, int c, int r)
307 wb_flush(wb);
308 sbuf_printf(&wb->sbuf, "%cD'%c %du'", c_ec, c, r);
309 wb->h += r;
312 void wb_drawe(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;
319 void wb_drawa(struct wb *wb, int c, int h1, int v1, int h2, int v2)
321 wb_flush(wb);
322 sbuf_printf(&wb->sbuf, "%cD'%c %du %du %du %du'",
323 c_ec, c, h1, v1, h2, v2);
324 wb->h += h1 + h2;
325 wb->v += v1 + v2;
326 wb_stsb(wb);
329 void wb_drawxbeg(struct wb *wb, int c)
331 wb_flush(wb);
332 sbuf_printf(&wb->sbuf, "%cD'%c", c_ec, c);
335 void wb_drawxdot(struct wb *wb, int h, int v)
337 sbuf_printf(&wb->sbuf, " %du %du", h, v);
338 wb->h += h;
339 wb->v += v;
340 wb_stsb(wb);
343 void wb_drawxend(struct wb *wb)
345 sbuf_printf(&wb->sbuf, "'");
348 void wb_reset(struct wb *wb)
350 wb_done(wb);
351 wb_init(wb);
354 char *wb_buf(struct wb *wb)
356 wb_flushsub(wb);
357 return sbuf_buf(&wb->sbuf);
360 static void wb_putc(struct wb *wb, int t, char *s)
362 if (t && t != 'C')
363 wb_flushsub(wb);
364 switch (t) {
365 case 0:
366 case 'C':
367 wb_put(wb, s);
368 break;
369 case 'D':
370 ren_dcmd(wb, s);
371 break;
372 case 'f':
373 wb->r_f = atoi(s);
374 break;
375 case 'h':
376 wb_hmov(wb, atoi(s));
377 break;
378 case 'm':
379 wb->r_m = clr_get(s);
380 break;
381 case 's':
382 wb->r_s = atoi(s);
383 break;
384 case 'v':
385 wb_vmov(wb, atoi(s));
386 break;
387 case 'x':
388 wb_els(wb, atoi(s));
389 break;
390 case 'X':
391 wb_etc(wb, s);
392 break;
396 void wb_cat(struct wb *wb, struct wb *src)
398 char *s;
399 char d[ILNLEN];
400 int c, part;
401 int collect;
402 wb_flushsub(src);
403 wb_flushsub(wb);
404 collect = wb_collect(wb, 0);
405 s = sbuf_buf(&src->sbuf);
406 while ((c = escread(&s, d)) >= 0)
407 wb_putc(wb, c, d);
408 part = src->part;
409 wb->r_s = -1;
410 wb->r_f = -1;
411 wb->r_m = -1;
412 wb_reset(src);
413 src->part = part;
414 wb_collect(wb, collect);
417 int wb_wid(struct wb *wb)
419 wb_flushsub(wb);
420 return wb->h;
423 int wb_hpos(struct wb *wb)
425 wb_flushsub(wb);
426 return wb->h;
429 int wb_vpos(struct wb *wb)
431 wb_flushsub(wb);
432 return wb->v;
435 int wb_empty(struct wb *wb)
437 return !wb->sub_n && sbuf_empty(&wb->sbuf);
440 /* return 1 if wb ends a sentence (.?!) */
441 int wb_eos(struct wb *wb)
443 int i = wb->sub_n - 1;
444 while (i > 0 && strchr("'\")]*", wb->sub_c[i][0]))
445 i--;
446 return i >= 0 && strchr(".?!", wb->sub_c[i][0]);
449 void wb_wconf(struct wb *wb, int *ct, int *st, int *sb,
450 int *llx, int *lly, int *urx, int *ury)
452 wb_flushsub(wb);
453 *ct = wb->ct;
454 *st = -wb->st;
455 *sb = -wb->sb;
456 *llx = wb->llx < BBMAX ? wb->llx : 0;
457 *lly = wb->lly < BBMAX ? -wb->lly : 0;
458 *urx = wb->urx > BBMIN ? wb->urx : 0;
459 *ury = wb->ury > BBMIN ? -wb->ury : 0;
462 static struct glyph *wb_prevglyph(struct wb *wb)
464 return wb->sub_n ? dev_glyph(wb->sub_c[wb->sub_n - 1], wb->f) : NULL;
467 void wb_italiccorrection(struct wb *wb)
469 struct glyph *g = wb_prevglyph(wb);
470 if (g && glyph_ic(g))
471 wb_hmov(wb, SDEVWID(wb->s, glyph_ic(g)));
474 void wb_italiccorrectionleft(struct wb *wb)
476 wb_flushsub(wb);
477 wb->icleft = 1;
480 void wb_fnszget(struct wb *wb, int *fn, int *sz, int *m)
482 wb_flushsub(wb);
483 *fn = wb->r_f;
484 *sz = wb->r_s;
485 *m = wb->r_m;
488 void wb_fnszset(struct wb *wb, int fn, int sz, int m)
490 wb->r_f = fn;
491 wb->r_s = sz;
492 wb->r_m = m;
495 void wb_catstr(struct wb *wb, char *s, char *end)
497 char d[ILNLEN];
498 int collect, c;
499 wb_flushsub(wb);
500 collect = wb_collect(wb, 0);
501 while (s < end && (c = escread(&s, d)) >= 0)
502 wb_putc(wb, c, d);
503 wb_collect(wb, collect);
506 /* return the size of \(hy if appended to wb */
507 int wb_dashwid(struct wb *wb)
509 struct glyph *g = dev_glyph("hy", wb->f);
510 return charwid(wb->f, wb->s, g ? g->wid : 0);