7 /* the current font, size and color */
8 #define R_F(wb) ((wb)->r_f >= 0 ? (wb)->r_f : n_f) /* current font */
9 #define R_S(wb) ((wb)->r_s >= 0 ? (wb)->r_s : n_s) /* current size */
10 #define R_M(wb) ((wb)->r_m >= 0 ? (wb)->r_m : n_m) /* current color */
11 /* italic correction */
12 #define glyph_ic(g) (MAX(0, (g)->urx - (g)->wid))
13 #define glyph_icleft(g) (MAX(0, -(g)->llx))
14 /* like DEVWID() but handles negative w */
15 #define SDEVWID(sz, w) ((w) >= 0 ? DEVWID((sz), (w)) : -DEVWID((sz), -(w)))
16 /* the maximum and minimum values of bounding box coordinates */
17 #define BBMAX (1 << 29)
20 void wb_init(struct wb
*wb
)
22 memset(wb
, 0, sizeof(*wb
));
37 void wb_done(struct wb
*wb
)
42 /* update wb->st and wb->sb */
43 static void wb_stsb(struct wb
*wb
)
45 wb
->st
= MIN(wb
->st
, wb
->v
- (wb
->s
* SC_IN
/ 72));
46 wb
->sb
= MAX(wb
->sb
, wb
->v
);
49 /* update bounding box */
50 static void wb_bbox(struct wb
*wb
, int llx
, int lly
, int urx
, int ury
)
52 wb
->llx
= MIN(wb
->llx
, wb
->h
+ llx
);
53 wb
->lly
= MIN(wb
->lly
, -wb
->v
+ lly
);
54 wb
->urx
= MAX(wb
->urx
, wb
->h
+ urx
);
55 wb
->ury
= MAX(wb
->ury
, -wb
->v
+ ury
);
58 /* append font and size to the buffer if needed */
59 static void wb_font(struct wb
*wb
)
61 if (wb
->f
!= R_F(wb
)) {
62 sbuf_printf(&wb
->sbuf
, "%cf(%02d", c_ec
, R_F(wb
));
65 if (wb
->s
!= R_S(wb
)) {
66 sbuf_printf(&wb
->sbuf
, "%cs(%02d", c_ec
, R_S(wb
));
69 if (!n_cp
&& wb
->m
!= R_M(wb
)) {
70 sbuf_printf(&wb
->sbuf
, "%cm[%s]", c_ec
, clr_str(R_M(wb
)));
76 /* pending font, size or color changes */
77 static int wb_pendingfont(struct wb
*wb
)
79 return wb
->f
!= R_F(wb
) || wb
->s
!= R_S(wb
) ||
80 (!n_cp
&& wb
->m
!= R_M(wb
));
83 void wb_hmov(struct wb
*wb
, int n
)
86 sbuf_printf(&wb
->sbuf
, "%ch'%du'", c_ec
, n
);
89 void wb_vmov(struct wb
*wb
, int n
)
92 sbuf_printf(&wb
->sbuf
, "%cv'%du'", c_ec
, n
);
95 void wb_els(struct wb
*wb
, int els
)
97 if (els
> wb
->els_pos
)
99 if (els
< wb
->els_neg
)
101 sbuf_printf(&wb
->sbuf
, "%cx'%du'", c_ec
, els
);
104 void wb_etc(struct wb
*wb
, char *x
)
107 sbuf_printf(&wb
->sbuf
, "%cX\x02%s\x02", c_ec
, x
);
110 /* make sure nothing is appended to wb after the last wb_put() */
111 static void wb_prevcheck(struct wb
*wb
)
113 if (wb
->prev_ll
!= sbuf_len(&wb
->sbuf
))
117 /* mark wb->prev_c[] as valid */
118 static void wb_prevok(struct wb
*wb
)
120 wb
->prev_ll
= sbuf_len(&wb
->sbuf
);
123 /* append c to wb->prev_c[] */
124 static void wb_prevput(struct wb
*wb
, char *c
, int ll
)
126 if (wb
->prev_n
== LEN(wb
->prev_c
))
128 memmove(wb
->prev_l
+ 1, wb
->prev_l
, wb
->prev_n
* sizeof(wb
->prev_l
[0]));
129 memmove(wb
->prev_h
+ 1, wb
->prev_h
, wb
->prev_n
* sizeof(wb
->prev_h
[0]));
130 memmove(wb
->prev_c
+ 1, wb
->prev_c
, wb
->prev_n
* sizeof(wb
->prev_c
[0]));
132 wb
->prev_h
[0] = wb
->h
;
133 strcpy(wb
->prev_c
[0], c
);
138 /* strip the last i characters from wb */
139 static void wb_prevpop(struct wb
*wb
, int i
)
141 int n
= wb
->prev_n
- i
;
142 sbuf_cut(&wb
->sbuf
, wb
->prev_l
[i
- 1]);
143 wb
->h
= wb
->prev_h
[i
- 1];
144 memmove(wb
->prev_l
, wb
->prev_l
+ i
, n
* sizeof(wb
->prev_l
[0]));
145 memmove(wb
->prev_h
, wb
->prev_h
+ i
, n
* sizeof(wb
->prev_h
[0]));
146 memmove(wb
->prev_c
, wb
->prev_c
+ i
, n
* sizeof(wb
->prev_c
[0]));
148 wb
->prev_ll
= sbuf_len(&wb
->sbuf
);
151 /* return the i-th last character inserted via wb_put() */
152 static char *wb_prev(struct wb
*wb
, int i
)
155 return i
< wb
->prev_n
? wb
->prev_c
[i
] : NULL
;
158 static struct glyph
*wb_prevglyph(struct wb
*wb
)
160 return wb_prev(wb
, 0) ? dev_glyph(wb_prev(wb
, 0), wb
->f
) : NULL
;
163 void wb_put(struct wb
*wb
, char *c
)
172 wb_hmov(wb
, N_SS(R_F(wb
), R_S(wb
)));
175 if (c
[0] == '\t' || c
[0] == '\x01' ||
176 (c
[0] == c_ni
&& (c
[1] == '\t' || c
[1] == '\x01'))) {
177 sbuf_append(&wb
->sbuf
, c
);
180 g
= dev_glyph(c
, R_F(wb
));
181 zerowidth
= !strcmp(c_hc
, c
) || !strcmp(c_bp
, c
);
182 if (!g
&& c
[0] == c_ec
&& !zerowidth
) { /* unknown escape */
183 memmove(c
, c
+ 1, strlen(c
));
184 g
= dev_glyph(c
, R_F(wb
));
186 if (g
&& !zerowidth
&& wb
->icleft_ll
== sbuf_len(&wb
->sbuf
))
188 wb_hmov(wb
, SDEVWID(R_S(wb
), glyph_icleft(g
)));
191 wb_prevcheck(wb
); /* make sure wb->prev_c[] is valid */
192 ll
= sbuf_len(&wb
->sbuf
); /* sbuf length before inserting c */
193 if (!c
[1] || c
[0] == c_ec
|| c
[0] == c_ni
|| utf8one(c
)) {
194 if (c
[0] == c_ni
&& c
[1] == c_ec
)
195 sbuf_printf(&wb
->sbuf
, "%c%c", c_ec
, c_ec
);
197 sbuf_append(&wb
->sbuf
, c
);
200 sbuf_printf(&wb
->sbuf
, "%c(%s", c_ec
, c
);
202 sbuf_printf(&wb
->sbuf
, "%cC'%s'", c_ec
, c
);
205 wb_prevput(wb
, c
, ll
);
207 wb_bbox(wb
, SDEVWID(wb
->s
, g
->llx
),
208 SDEVWID(wb
->s
, g
->lly
),
209 SDEVWID(wb
->s
, g
->urx
),
210 SDEVWID(wb
->s
, g
->ury
));
211 wb
->h
+= charwid(wb
->f
, wb
->s
, g
? g
->wid
: 0);
212 wb
->ct
|= g
? g
->type
: 0;
217 /* just like wb_put(), but call cdef_expand() if c is defined */
218 void wb_putexpand(struct wb
*wb
, char *c
)
220 if (cdef_expand(wb
, c
, R_F(wb
)))
224 /* return zero if c formed a ligature with its previous character */
225 int wb_lig(struct wb
*wb
, char *c
)
227 char lig
[GNLEN
] = "";
228 char *cs
[LIGLEN
+ 2];
231 if (wb_pendingfont(wb
)) /* font changes disable ligatures */
234 while (wb_prev(wb
, ++i
))
235 cs
[i
+ 1] = wb_prev(wb
, i
);
236 ligpos
= font_lig(dev_font(R_F(wb
)), cs
, i
+ 1);
238 for (i
= 0; i
< ligpos
- 1; i
++)
239 strcat(lig
, wb_prev(wb
, ligpos
- i
- 2));
241 wb_prevpop(wb
, ligpos
- 1);
248 /* return 0 if pairwise kerning was done */
249 int wb_kern(struct wb
*wb
, char *c
)
252 if (wb_pendingfont(wb
) || !wb_prev(wb
, 0))
254 val
= font_kern(dev_font(R_F(wb
)), wb_prev(wb
, 0), c
);
256 wb_hmov(wb
, charwid(R_F(wb
), R_S(wb
), val
));
257 wb_prevok(wb
); /* kerning should not prevent ligatures */
261 int wb_part(struct wb
*wb
)
266 void wb_setpart(struct wb
*wb
)
271 void wb_drawl(struct wb
*wb
, int c
, int h
, int v
)
274 sbuf_printf(&wb
->sbuf
, "%cD'%c %du %du'", c_ec
, c
, h
, v
);
280 void wb_drawc(struct wb
*wb
, int c
, int r
)
283 sbuf_printf(&wb
->sbuf
, "%cD'%c %du'", c_ec
, c
, r
);
287 void wb_drawe(struct wb
*wb
, int c
, int h
, int v
)
290 sbuf_printf(&wb
->sbuf
, "%cD'%c %du %du'", c_ec
, c
, h
, v
);
294 void wb_drawa(struct wb
*wb
, int c
, int h1
, int v1
, int h2
, int v2
)
297 sbuf_printf(&wb
->sbuf
, "%cD'%c %du %du %du %du'", c_ec
, c
, h1
, v1
, h2
, v2
);
303 void wb_drawxbeg(struct wb
*wb
, int c
)
306 sbuf_printf(&wb
->sbuf
, "%cD'%c", c_ec
, c
);
309 void wb_drawxdot(struct wb
*wb
, int h
, int v
)
311 sbuf_printf(&wb
->sbuf
, " %du %du", h
, v
);
317 void wb_drawxend(struct wb
*wb
)
319 sbuf_printf(&wb
->sbuf
, "'");
322 void wb_reset(struct wb
*wb
)
328 char *wb_buf(struct wb
*wb
)
330 return sbuf_buf(&wb
->sbuf
);
333 static void wb_putc(struct wb
*wb
, int t
, char *s
)
347 wb_hmov(wb
, atoi(s
));
350 wb
->r_m
= clr_get(s
);
356 wb_vmov(wb
, atoi(s
));
367 void wb_cat(struct wb
*wb
, struct wb
*src
)
369 char *s
= sbuf_buf(&src
->sbuf
);
372 while ((c
= escread(&s
, d
)) >= 0)
382 int wb_wid(struct wb
*wb
)
387 int wb_empty(struct wb
*wb
)
389 return sbuf_empty(&wb
->sbuf
);
392 /* return 1 if wb ends a sentence (.?!) */
393 int wb_eos(struct wb
*wb
)
396 while (wb_prev(wb
, i
) && strchr("'\")]*", wb_prev(wb
, i
)[0]))
398 return wb_prev(wb
, i
) && strchr(".?!", wb_prev(wb
, i
)[0]);
401 void wb_wconf(struct wb
*wb
, int *ct
, int *st
, int *sb
,
402 int *llx
, int *lly
, int *urx
, int *ury
)
407 *llx
= wb
->llx
< BBMAX
? wb
->llx
: 0;
408 *lly
= wb
->lly
< BBMAX
? -wb
->lly
: 0;
409 *urx
= wb
->urx
> BBMIN
? wb
->urx
: 0;
410 *ury
= wb
->ury
> BBMIN
? -wb
->ury
: 0;
413 /* skip troff requests; return 1 if read c_hc */
414 static int skipreqs(char **s
, struct wb
*w1
)
421 while ((c
= escread(s
, d
)) > 0) {
426 if (c
< 0 || !strcmp(c_hc
, d
))
432 /* return the size of \(hy if appended to wb */
433 int wb_dashwid(struct wb
*wb
)
435 struct glyph
*g
= dev_glyph("hy", R_F(wb
));
436 return charwid(R_F(wb
), R_S(wb
), g
? g
->wid
: 0);
439 /* find explicit hyphenation positions: dashes, \: and \% */
440 int wb_hyphmark(char *word
, int *hyidx
, int *hyins
)
445 if (skipreqs(&s
, NULL
))
447 while ((c
= escread(&s
, d
)) >= 0 && n
< NHYPHS
) {
448 if (!c
&& !strcmp(c_hc
, d
)) {
450 hyidx
[n
++] = s
- word
;
452 if (!c
&& (!strcmp(c_bp
, d
) || !strcmp("-", d
) ||
453 (!strcmp("em", d
) || !strcmp("hy", d
)))) {
455 hyidx
[n
++] = s
- word
;
461 /* find the hyphenation positions of the given word */
462 int wb_hyph(char *src
, int *hyidx
, int flg
)
464 char word
[ILNLEN
]; /* word to pass to hyphenate() */
465 char hyph
[ILNLEN
]; /* hyphenation points returned from hyphenate() */
466 char *iw
[ILNLEN
]; /* beginning of i-th char in word */
467 char *is
[ILNLEN
]; /* beginning of i-th char in s */
468 int n
= 0; /* the number of characters in word */
469 int nhy
= 0; /* number of hyphenations found */
474 char *wp
= word
, *we
= word
+ sizeof(word
);
478 while ((c
= escread(&s
, d
)) >= 0 && (c
> 0 || strlen(d
) + 1 < we
- wp
)) {
483 /* ignore multi-char aliases except for ligatures */
484 if (!utf8one(d
) && !font_islig(dev_font(R_F(&wb
)), d
))
487 wp
= strchr(wp
, '\0');
495 hyphenate(hyph
, word
, flg
);
496 for (i
= 1; i
< n
- 1 && nhy
< NHYPHS
; i
++)
497 if (hyph
[iw
[i
] - word
])
498 hyidx
[nhy
++] = is
[i
] - src
;
502 void wb_italiccorrection(struct wb
*wb
)
504 struct glyph
*g
= wb_prevglyph(wb
);
505 if (g
&& glyph_ic(g
))
506 wb_hmov(wb
, SDEVWID(wb
->s
, glyph_ic(g
)));
509 void wb_italiccorrectionleft(struct wb
*wb
)
511 wb
->icleft_ll
= sbuf_len(&wb
->sbuf
);
514 void wb_fnszget(struct wb
*wb
, int *fn
, int *sz
, int *m
)
521 void wb_fnszset(struct wb
*wb
, int fn
, int sz
, int m
)
528 void wb_catstr(struct wb
*wb
, char *s
, char *end
)
532 while (s
< end
&& (c
= escread(&s
, d
)) >= 0)