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
);
572 static char *keshideh_chars
[] = {
573 "ﺒ", "ﺑ", "ﭙ", "ﭘ", "ﺘ", "ﺗ", "ﺜ", "ﺛ", "ﺴ", "ﺳ",
574 "ﺸ", "ﺷ", "ﻔ", "ﻓ", "ﻘ", "ﻗ", "ﮑ", "ﮐ", "ﮕ", "ﮔ",
575 "ﻤ", "ﻣ", "ﻨ", "ﻧ", "ﻬ", "ﻫ", "ﯿ", "ﯾ",
578 static int keshideh(char *c
)
581 for (i
= 0; i
< LEN(keshideh_chars
); i
++)
582 if (!strcmp(keshideh_chars
[i
], c
))
587 /* insert keshideh */
588 int wb_keshideh(char *word
, struct wb
*dst
, int wid
)
591 char *s
, *d
, *s_prev
= NULL
, *s_kesh
= NULL
;
594 /* find the last keshideh position */
596 while ((c
= escread(&s
, &d
)) >= 0) {
598 if (!c
&& keshideh(p
)) {
599 struct glyph
*g
= dev_glyph("ـ", R_F(dst
));
600 int kw
= g
? font_gwid(g
->font
,
601 dev_font(R_F(dst
)), R_S(dst
), g
->wid
) : 0;
608 strcpy(p
, c
? "" : d
);
610 /* insert the keshideh at s_kesh */
613 while ((c
= escread(&s
, &d
)) >= 0) {
616 wb_putc(dst
, 0, "ـ");