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 if (g
->llx
|| g
->lly
|| g
->urx
|| g
->ury
) {
177 int llx
= font_wid(g
->font
, wb
->s
, g
->llx
);
178 int lly
= font_wid(g
->font
, wb
->s
, g
->lly
);
179 int urx
= font_wid(g
->font
, wb
->s
, g
->urx
);
180 int ury
= font_wid(g
->font
, wb
->s
, g
->ury
);
181 wb_bbox(wb
, llx
, lly
, urx
, ury
);
182 } else { /* no bounding box information */
183 int ht
= wb
->s
* SC_PT
;
184 int urx
= font_wid(g
->font
, wb
->s
, g
->wid
);
185 int lly
= (g
->type
& 1) ? -ht
/ 2 : 0;
186 int ury
= (g
->type
& 2) ? ht
: ht
/ 2;
187 wb_bbox(wb
, 0, lly
, urx
, ury
);
190 wb
->h
+= g
? font_gwid(g
->font
, dev_font(wb
->f
), wb
->s
, g
->wid
) : 0;
191 wb
->ct
|= g
? g
->type
: 0;
196 /* return nonzero if it cannot be hyphenated */
197 static int wb_hyph(char src
[][GNLEN
], int src_n
, char *src_hyph
, int flg
)
199 char word
[WORDLEN
* GNLEN
]; /* word to pass to hyphenate() */
200 char hyph
[WORDLEN
* GNLEN
]; /* hyphenation points of word */
201 int smap
[WORDLEN
]; /* the mapping from src[] to word[] */
206 for (i
= 0; i
< src_n
; i
++) {
215 memset(hyph
, 0, (d
- word
) * sizeof(hyph
[0]));
216 hyphenate(hyph
, word
, flg
);
217 for (i
= 0; i
< src_n
; i
++)
218 src_hyph
[i
] = hyph
[smap
[i
]];
222 static int wb_collect(struct wb
*wb
, int val
)
224 int old
= wb
->sub_collect
;
225 wb
->sub_collect
= val
;
229 /* output the collected characters; only for those present in wb->f font */
230 static void wb_flushsub(struct wb
*wb
)
233 struct glyph
*gsrc
[WORDLEN
];
234 struct glyph
*gdst
[WORDLEN
];
235 int x
[WORDLEN
], y
[WORDLEN
], xadv
[WORDLEN
], yadv
[WORDLEN
];
237 char src_hyph
[WORDLEN
];
240 if (!wb
->sub_n
|| !wb
->sub_collect
)
243 fn
= dev_font(wb
->f
);
244 if (!n_hy
|| wb_hyph(wb
->sub_c
, wb
->sub_n
, src_hyph
, n_hy
))
245 memset(src_hyph
, 0, sizeof(src_hyph
));
246 /* call font_layout() for collected glyphs; skip hyphenation marks */
247 while (sidx
< wb
->sub_n
) {
249 for (; sidx
< wb
->sub_n
&& !c_hymark(wb
->sub_c
[sidx
]); sidx
++)
250 gsrc
[sidx
- beg
] = font_find(fn
, wb
->sub_c
[sidx
]);
251 dst_n
= font_layout(fn
, gsrc
, sidx
- beg
, wb
->s
,
252 gdst
, dmap
, x
, y
, xadv
, yadv
, n_lg
, n_kn
);
253 for (i
= 0; i
< dst_n
; i
++) {
254 int xd
[2] = {x
[i
], xadv
[i
] - x
[i
]};
255 int yd
[2] = {y
[i
], yadv
[i
] - y
[i
]};
257 wb_hmov(wb
, font_wid(fn
, wb
->s
, xd
[wb
->cd
]));
259 wb_vmov(wb
, font_wid(fn
, wb
->s
, yd
[wb
->cd
]));
260 if (src_hyph
[beg
+ dmap
[i
]])
262 if (gdst
[i
] == gsrc
[dmap
[i
]])
263 wb_putbuf(wb
, wb
->sub_c
[beg
+ dmap
[i
]]);
265 wb_putbuf(wb
, gdst
[i
]->name
);
267 wb_hmov(wb
, font_wid(fn
, wb
->s
, xd
[1 - wb
->cd
]));
269 wb_vmov(wb
, font_wid(fn
, wb
->s
, yd
[1 - wb
->cd
]));
271 for (; sidx
< wb
->sub_n
&& c_hymark(wb
->sub_c
[sidx
]); sidx
++)
272 wb_putbuf(wb
, wb
->sub_c
[sidx
]);
279 void wb_put(struct wb
*wb
, char *c
)
285 if (wb_pendingdir(wb
))
289 wb_hmov(wb
, font_swid(dev_font(R_F(wb
)), R_S(wb
), n_ss
));
292 if (!strcmp(c_nb
, c
)) {
294 sbuf_append(&wb
->sbuf
, c
);
295 wb
->h
+= font_swid(dev_font(R_F(wb
)), R_S(wb
), n_ss
);
298 if (wb_pendingfont(wb
) || wb
->sub_n
== LEN(wb
->sub_c
))
300 if (wb
->sub_collect
) {
301 if (font_find(dev_font(wb
->f
), c
) || c_hymark(c
))
302 strcpy(wb
->sub_c
[wb
->sub_n
++], c
);
310 /* just like wb_put() but disable subword collection */
311 void wb_putraw(struct wb
*wb
, char *c
)
315 collect
= wb_collect(wb
, 0);
317 wb_collect(wb
, collect
);
320 /* just like wb_put(), but call cdef_expand() if c is defined */
321 void wb_putexpand(struct wb
*wb
, char *c
)
323 if (cdef_expand(wb
, c
, R_F(wb
)))
327 int wb_part(struct wb
*wb
)
332 void wb_setpart(struct wb
*wb
)
337 int wb_cost(struct wb
*wb
)
342 void wb_setcost(struct wb
*wb
, int cost
)
347 void wb_drawl(struct wb
*wb
, int c
, int h
, int v
)
350 sbuf_printf(&wb
->sbuf
, "%cD'%c %du %du'", c_ec
, c
, h
, v
);
356 void wb_drawc(struct wb
*wb
, int c
, int r
)
359 sbuf_printf(&wb
->sbuf
, "%cD'%c %du'", c_ec
, c
, r
);
363 void wb_drawe(struct wb
*wb
, int c
, int h
, int v
)
366 sbuf_printf(&wb
->sbuf
, "%cD'%c %du %du'", c_ec
, c
, h
, v
);
370 void wb_drawa(struct wb
*wb
, int c
, int h1
, int v1
, int h2
, int v2
)
373 sbuf_printf(&wb
->sbuf
, "%cD'%c %du %du %du %du'",
374 c_ec
, c
, h1
, v1
, h2
, v2
);
380 void wb_drawxbeg(struct wb
*wb
, int c
)
383 sbuf_printf(&wb
->sbuf
, "%cD'%c", c_ec
, c
);
386 void wb_drawxdot(struct wb
*wb
, int h
, int v
)
388 sbuf_printf(&wb
->sbuf
, " %du %du", h
, v
);
394 void wb_drawxcmd(struct wb
*wb
, char *cmd
)
396 sbuf_printf(&wb
->sbuf
, " %s", cmd
);
399 void wb_drawxend(struct wb
*wb
)
401 sbuf_printf(&wb
->sbuf
, "'");
404 void wb_reset(struct wb
*wb
)
410 char *wb_buf(struct wb
*wb
)
413 return sbuf_buf(&wb
->sbuf
);
416 static void wb_putc(struct wb
*wb
, int t
, char *s
)
432 wb_hmov(wb
, atoi(s
));
435 wb
->r_m
= clr_get(s
);
441 wb_vmov(wb
, atoi(s
));
457 void wb_cat(struct wb
*wb
, struct wb
*src
)
464 collect
= wb_collect(wb
, 0);
465 s
= sbuf_buf(&src
->sbuf
);
466 while ((c
= escread(&s
, &d
)) >= 0)
475 wb_collect(wb
, collect
);
478 int wb_wid(struct wb
*wb
)
484 int wb_hpos(struct wb
*wb
)
490 int wb_vpos(struct wb
*wb
)
496 int wb_empty(struct wb
*wb
)
498 return !wb
->sub_n
&& sbuf_empty(&wb
->sbuf
);
501 /* return 1 if wb ends a sentence (.?!) */
502 int wb_eos(struct wb
*wb
)
504 int i
= wb
->sub_n
- 1;
505 while (i
> 0 && c_eostran(wb
->sub_c
[i
]))
507 return i
>= 0 && c_eossent(wb
->sub_c
[i
]);
510 void wb_wconf(struct wb
*wb
, int *ct
, int *st
, int *sb
,
511 int *llx
, int *lly
, int *urx
, int *ury
)
517 *llx
= wb
->llx
< BBMAX
? wb
->llx
: 0;
518 *lly
= wb
->lly
< BBMAX
? -wb
->lly
: 0;
519 *urx
= wb
->urx
> BBMIN
? wb
->urx
: 0;
520 *ury
= wb
->ury
> BBMIN
? -wb
->ury
: 0;
523 static struct glyph
*wb_prevglyph(struct wb
*wb
)
525 return wb
->sub_n
? dev_glyph(wb
->sub_c
[wb
->sub_n
- 1], wb
->f
) : NULL
;
528 void wb_italiccorrection(struct wb
*wb
)
530 struct glyph
*g
= wb_prevglyph(wb
);
531 if (g
&& glyph_ic(g
))
532 wb_hmov(wb
, font_wid(g
->font
, wb
->s
, glyph_ic(g
)));
535 void wb_italiccorrectionleft(struct wb
*wb
)
541 void wb_fnszget(struct wb
*wb
, int *fn
, int *sz
, int *m
, int *cd
)
550 void wb_fnszset(struct wb
*wb
, int fn
, int sz
, int m
, int cd
)
558 void wb_catstr(struct wb
*wb
, char *s
, char *end
)
563 collect
= wb_collect(wb
, 0);
564 while (s
< end
&& (c
= escread(&s
, &d
)) >= 0)
566 wb_collect(wb
, collect
);
569 /* return the size of \(hy if appended to wb */
570 int wb_hywid(struct wb
*wb
)
572 struct glyph
*g
= dev_glyph("hy", wb
->f
);
573 return g
? font_gwid(g
->font
, dev_font(R_F(wb
)), R_S(wb
), g
->wid
) : 0;
576 /* return the size of space if appended to wb */
577 int wb_swid(struct wb
*wb
)
579 return font_swid(dev_font(R_F(wb
)), R_S(wb
), n_ss
);
582 static char *keshideh_chars
[] = {
583 "ﺒ", "ﺑ", "ﭙ", "ﭘ", "ﺘ", "ﺗ", "ﺜ", "ﺛ", "ﺴ", "ﺳ",
584 "ﺸ", "ﺷ", "ﻔ", "ﻓ", "ﻘ", "ﻗ", "ﮑ", "ﮐ", "ﮕ", "ﮔ",
585 "ﻤ", "ﻣ", "ﻨ", "ﻧ", "ﻬ", "ﻫ", "ﯿ", "ﯾ",
588 static int keshideh(char *c
)
591 for (i
= 0; i
< LEN(keshideh_chars
); i
++)
592 if (!strcmp(keshideh_chars
[i
], c
))
597 /* insert keshideh */
598 int wb_keshideh(char *word
, struct wb
*dst
, int wid
)
601 char *s
, *d
, *s_prev
= NULL
, *s_kesh
= NULL
;
604 /* find the last keshideh position */
606 while ((c
= escread(&s
, &d
)) >= 0) {
608 if (!c
&& keshideh(p
)) {
609 struct glyph
*g
= dev_glyph("ـ", R_F(dst
));
610 int kw
= g
? font_gwid(g
->font
,
611 dev_font(R_F(dst
)), R_S(dst
), g
->wid
) : 0;
618 strcpy(p
, c
? "" : d
);
620 /* insert the keshideh at s_kesh */
623 while ((c
= escread(&s
, &d
)) >= 0) {
626 wb_putc(dst
, 0, "ـ");