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 #define R_CD(b) ((wb)->r_cd >= 0 ? (wb)->r_cd : n_cd) /* current direction */
13 /* italic correction */
14 #define glyph_ic(g) (MAX(0, (g)->urx - (g)->wid))
15 #define glyph_icleft(g) (MAX(0, -(g)->llx))
16 /* the maximum and minimum values of bounding box coordinates */
17 #define BBMAX (1 << 29)
20 static void wb_flushsub(struct wb
*wb
);
22 void wb_init(struct wb
*wb
)
24 memset(wb
, 0, sizeof(*wb
));
41 void wb_done(struct wb
*wb
)
46 /* update wb->st and wb->sb */
47 static void wb_stsb(struct wb
*wb
)
49 wb
->st
= MIN(wb
->st
, wb
->v
- (wb
->s
* SC_IN
/ 72));
50 wb
->sb
= MAX(wb
->sb
, wb
->v
);
53 /* update bounding box */
54 static void wb_bbox(struct wb
*wb
, int llx
, int lly
, int urx
, int ury
)
56 wb
->llx
= MIN(wb
->llx
, wb
->h
+ llx
);
57 wb
->lly
= MIN(wb
->lly
, -wb
->v
+ lly
);
58 wb
->urx
= MAX(wb
->urx
, wb
->h
+ urx
);
59 wb
->ury
= MAX(wb
->ury
, -wb
->v
+ ury
);
62 /* pending font, size or color changes */
63 static int wb_pendingfont(struct wb
*wb
)
65 return wb
->f
!= R_F(wb
) || wb
->s
!= R_S(wb
) ||
66 (!n_cp
&& wb
->m
!= R_M(wb
));
69 /* pending direction change */
70 static int wb_pendingdir(struct wb
*wb
)
72 return wb
->cd
!= R_CD(wb
);
75 /* append font and size to the buffer if needed */
76 static void wb_flushfont(struct wb
*wb
)
78 if (wb
->f
!= R_F(wb
)) {
79 sbuf_printf(&wb
->sbuf
, "%cf(%02d", c_ec
, R_F(wb
));
82 if (wb
->s
!= R_S(wb
)) {
84 sbuf_printf(&wb
->sbuf
, "%cs(%02d", c_ec
, R_S(wb
));
86 sbuf_printf(&wb
->sbuf
, "%cs[%d]", c_ec
, R_S(wb
));
89 if (!n_cp
&& wb
->m
!= R_M(wb
)) {
90 sbuf_printf(&wb
->sbuf
, "%cm[%s]", c_ec
, clr_str(R_M(wb
)));
96 /* append current text direction to the buffer if needed */
97 void wb_flushdir(struct wb
*wb
)
99 if (wb
->cd
!= R_CD(wb
)) {
102 sbuf_printf(&wb
->sbuf
, "%c%c", c_ec
, R_CD(wb
) > 0 ? '<' : '>');
107 /* apply font and size changes and flush the collected subword */
108 static void wb_flush(struct wb
*wb
)
115 void wb_hmov(struct wb
*wb
, int n
)
119 sbuf_printf(&wb
->sbuf
, "%ch'%du'", c_ec
, n
);
122 void wb_vmov(struct wb
*wb
, int n
)
126 sbuf_printf(&wb
->sbuf
, "%cv'%du'", c_ec
, n
);
129 void wb_els(struct wb
*wb
, int els
)
132 if (els
> wb
->els_pos
)
134 if (els
< wb
->els_neg
)
136 sbuf_printf(&wb
->sbuf
, "%cx'%du'", c_ec
, els
);
139 void wb_etc(struct wb
*wb
, char *x
)
142 sbuf_printf(&wb
->sbuf
, "%cX\x02%s\x02", c_ec
, x
);
145 static void wb_putbuf(struct wb
*wb
, char *c
)
149 if (c
[0] == '\t' || c
[0] == '\x01' ||
150 (c
[0] == c_ni
&& (c
[1] == '\t' || c
[1] == '\x01'))) {
151 sbuf_append(&wb
->sbuf
, c
);
154 g
= dev_glyph(c
, wb
->f
);
155 zerowidth
= c_hymark(c
);
156 if (!g
&& c
[0] == c_ec
&& !zerowidth
) { /* unknown escape */
157 memmove(c
, c
+ 1, strlen(c
));
158 g
= dev_glyph(c
, wb
->f
);
160 if (g
&& !zerowidth
&& wb
->icleft
&& glyph_icleft(g
))
161 wb_hmov(wb
, font_wid(g
->font
, wb
->s
, glyph_icleft(g
)));
163 if (!c
[1] || c
[0] == c_ec
|| c
[0] == c_ni
|| utf8one(c
)) {
164 if (c
[0] == c_ni
&& c
[1] == c_ec
)
165 sbuf_printf(&wb
->sbuf
, "%c%c", c_ec
, c_ec
);
167 sbuf_append(&wb
->sbuf
, c
);
170 sbuf_printf(&wb
->sbuf
, "%c(%s", c_ec
, c
);
172 sbuf_printf(&wb
->sbuf
, "%cC'%s'", c_ec
, c
);
176 wb_bbox(wb
, font_wid(g
->font
, wb
->s
, g
->llx
),
177 font_wid(g
->font
, wb
->s
, g
->lly
),
178 font_wid(g
->font
, wb
->s
, g
->urx
),
179 font_wid(g
->font
, wb
->s
, g
->ury
));
180 wb
->h
+= g
? font_gwid(g
->font
, dev_font(wb
->f
), wb
->s
, g
->wid
) : 0;
181 wb
->ct
|= g
? g
->type
: 0;
186 /* return nonzero if it cannot be hyphenated */
187 static int wb_hyph(char src
[][GNLEN
], int src_n
, char *src_hyph
, int flg
)
189 char word
[WORDLEN
* GNLEN
]; /* word to pass to hyphenate() */
190 char hyph
[WORDLEN
* GNLEN
]; /* hyphenation points of word */
191 int smap
[WORDLEN
]; /* the mapping from src[] to word[] */
196 for (i
= 0; i
< src_n
; i
++) {
205 memset(hyph
, 0, (d
- word
) * sizeof(hyph
[0]));
206 hyphenate(hyph
, word
, flg
);
207 for (i
= 0; i
< src_n
; i
++)
208 src_hyph
[i
] = hyph
[smap
[i
]];
212 static int wb_collect(struct wb
*wb
, int val
)
214 int old
= wb
->sub_collect
;
215 wb
->sub_collect
= val
;
219 /* output the collected characters; only for those present in wb->f font */
220 static void wb_flushsub(struct wb
*wb
)
223 struct glyph
*gsrc
[WORDLEN
];
224 struct glyph
*gdst
[WORDLEN
];
225 int x
[WORDLEN
], y
[WORDLEN
], xadv
[WORDLEN
], yadv
[WORDLEN
];
227 char src_hyph
[WORDLEN
];
230 if (!wb
->sub_n
|| !wb
->sub_collect
)
233 fn
= dev_font(wb
->f
);
234 if (!n_hy
|| wb_hyph(wb
->sub_c
, wb
->sub_n
, src_hyph
, n_hy
))
235 memset(src_hyph
, 0, sizeof(src_hyph
));
236 /* call font_layout() for collected glyphs; skip hyphenation marks */
237 while (sidx
< wb
->sub_n
) {
239 for (; sidx
< wb
->sub_n
&& !c_hymark(wb
->sub_c
[sidx
]); sidx
++)
240 gsrc
[sidx
- beg
] = font_find(fn
, wb
->sub_c
[sidx
]);
241 dst_n
= font_layout(fn
, gsrc
, sidx
- beg
, wb
->s
,
242 gdst
, dmap
, x
, y
, xadv
, yadv
, n_lg
, n_kn
);
243 for (i
= 0; i
< dst_n
; i
++) {
244 int xd
[2] = {x
[i
], xadv
[i
] - x
[i
]};
245 int yd
[2] = {y
[i
], yadv
[i
] - y
[i
]};
247 wb_hmov(wb
, font_wid(fn
, wb
->s
, xd
[wb
->cd
]));
249 wb_vmov(wb
, font_wid(fn
, wb
->s
, yd
[wb
->cd
]));
250 if (src_hyph
[beg
+ dmap
[i
]])
252 if (gdst
[i
] == gsrc
[dmap
[i
]])
253 wb_putbuf(wb
, wb
->sub_c
[beg
+ dmap
[i
]]);
255 wb_putbuf(wb
, gdst
[i
]->name
);
257 wb_hmov(wb
, font_wid(fn
, wb
->s
, xd
[1 - wb
->cd
]));
259 wb_vmov(wb
, font_wid(fn
, wb
->s
, yd
[1 - wb
->cd
]));
261 for (; sidx
< wb
->sub_n
&& c_hymark(wb
->sub_c
[sidx
]); sidx
++)
262 wb_putbuf(wb
, wb
->sub_c
[sidx
]);
269 void wb_put(struct wb
*wb
, char *c
)
275 if (wb_pendingdir(wb
))
279 wb_hmov(wb
, font_swid(dev_font(R_F(wb
)), R_S(wb
), n_ss
));
282 if (!strcmp(c_nb
, c
)) {
284 sbuf_append(&wb
->sbuf
, c
);
285 wb
->h
+= font_swid(dev_font(R_F(wb
)), R_S(wb
), n_ss
);
288 if (wb_pendingfont(wb
) || wb
->sub_n
== LEN(wb
->sub_c
))
290 if (wb
->sub_collect
) {
291 if (font_find(dev_font(wb
->f
), c
) || c_hymark(c
))
292 strcpy(wb
->sub_c
[wb
->sub_n
++], c
);
300 /* just like wb_put() but disable subword collection */
301 void wb_putraw(struct wb
*wb
, char *c
)
305 collect
= wb_collect(wb
, 0);
307 wb_collect(wb
, collect
);
310 /* just like wb_put(), but call cdef_expand() if c is defined */
311 void wb_putexpand(struct wb
*wb
, char *c
)
313 if (cdef_expand(wb
, c
, R_F(wb
)))
317 int wb_part(struct wb
*wb
)
322 void wb_setpart(struct wb
*wb
)
327 int wb_cost(struct wb
*wb
)
332 void wb_setcost(struct wb
*wb
, int cost
)
337 void wb_drawl(struct wb
*wb
, int c
, int h
, int v
)
340 sbuf_printf(&wb
->sbuf
, "%cD'%c %du %du'", c_ec
, c
, h
, v
);
346 void wb_drawc(struct wb
*wb
, int c
, int r
)
349 sbuf_printf(&wb
->sbuf
, "%cD'%c %du'", c_ec
, c
, r
);
353 void wb_drawe(struct wb
*wb
, int c
, int h
, int v
)
356 sbuf_printf(&wb
->sbuf
, "%cD'%c %du %du'", c_ec
, c
, h
, v
);
360 void wb_drawa(struct wb
*wb
, int c
, int h1
, int v1
, int h2
, int v2
)
363 sbuf_printf(&wb
->sbuf
, "%cD'%c %du %du %du %du'",
364 c_ec
, c
, h1
, v1
, h2
, v2
);
370 void wb_drawxbeg(struct wb
*wb
, int c
)
373 sbuf_printf(&wb
->sbuf
, "%cD'%c", c_ec
, c
);
376 void wb_drawxdot(struct wb
*wb
, int h
, int v
)
378 sbuf_printf(&wb
->sbuf
, " %du %du", h
, v
);
384 void wb_drawxcmd(struct wb
*wb
, char *cmd
)
386 sbuf_printf(&wb
->sbuf
, " %s", cmd
);
389 void wb_drawxend(struct wb
*wb
)
391 sbuf_printf(&wb
->sbuf
, "'");
394 void wb_reset(struct wb
*wb
)
400 char *wb_buf(struct wb
*wb
)
403 return sbuf_buf(&wb
->sbuf
);
406 static void wb_putc(struct wb
*wb
, int t
, char *s
)
422 wb_hmov(wb
, atoi(s
));
425 wb
->r_m
= clr_get(s
);
431 wb_vmov(wb
, atoi(s
));
447 void wb_cat(struct wb
*wb
, struct wb
*src
)
454 collect
= wb_collect(wb
, 0);
455 s
= sbuf_buf(&src
->sbuf
);
456 while ((c
= escread(&s
, &d
)) >= 0)
465 wb_collect(wb
, collect
);
468 int wb_wid(struct wb
*wb
)
474 int wb_hpos(struct wb
*wb
)
480 int wb_vpos(struct wb
*wb
)
486 int wb_empty(struct wb
*wb
)
488 return !wb
->sub_n
&& sbuf_empty(&wb
->sbuf
);
491 /* return 1 if wb ends a sentence (.?!) */
492 int wb_eos(struct wb
*wb
)
494 int i
= wb
->sub_n
- 1;
495 while (i
> 0 && c_eostran(wb
->sub_c
[i
]))
497 return i
>= 0 && c_eossent(wb
->sub_c
[i
]);
500 void wb_wconf(struct wb
*wb
, int *ct
, int *st
, int *sb
,
501 int *llx
, int *lly
, int *urx
, int *ury
)
507 *llx
= wb
->llx
< BBMAX
? wb
->llx
: 0;
508 *lly
= wb
->lly
< BBMAX
? -wb
->lly
: 0;
509 *urx
= wb
->urx
> BBMIN
? wb
->urx
: 0;
510 *ury
= wb
->ury
> BBMIN
? -wb
->ury
: 0;
513 static struct glyph
*wb_prevglyph(struct wb
*wb
)
515 return wb
->sub_n
? dev_glyph(wb
->sub_c
[wb
->sub_n
- 1], wb
->f
) : NULL
;
518 void wb_italiccorrection(struct wb
*wb
)
520 struct glyph
*g
= wb_prevglyph(wb
);
521 if (g
&& glyph_ic(g
))
522 wb_hmov(wb
, font_wid(g
->font
, wb
->s
, glyph_ic(g
)));
525 void wb_italiccorrectionleft(struct wb
*wb
)
531 void wb_fnszget(struct wb
*wb
, int *fn
, int *sz
, int *m
, int *cd
)
540 void wb_fnszset(struct wb
*wb
, int fn
, int sz
, int m
, int cd
)
548 void wb_catstr(struct wb
*wb
, char *s
, char *end
)
553 collect
= wb_collect(wb
, 0);
554 while (s
< end
&& (c
= escread(&s
, &d
)) >= 0)
556 wb_collect(wb
, collect
);
559 /* return the size of \(hy if appended to wb */
560 int wb_hywid(struct wb
*wb
)
562 struct glyph
*g
= dev_glyph("hy", wb
->f
);
563 return g
? font_gwid(g
->font
, dev_font(R_F(wb
)), R_S(wb
), g
->wid
) : 0;
566 /* return the size of space if appended to wb */
567 int wb_swid(struct wb
*wb
)
569 return font_swid(dev_font(R_F(wb
)), R_S(wb
), n_ss
);