1*99db7d0eSSascha Wildner /* $Id: term_ps.c,v 1.92 2020/09/06 14:45:22 schwarze Exp $ */
280387638SSascha Wildner /*
336342e81SSascha Wildner * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*99db7d0eSSascha Wildner * Copyright (c) 2014,2015,2016,2017,2020 Ingo Schwarze <schwarze@openbsd.org>
554ba9607SSascha Wildner * Copyright (c) 2017 Marc Espie <espie@openbsd.org>
680387638SSascha Wildner *
780387638SSascha Wildner * Permission to use, copy, modify, and distribute this software for any
880387638SSascha Wildner * purpose with or without fee is hereby granted, provided that the above
980387638SSascha Wildner * copyright notice and this permission notice appear in all copies.
1080387638SSascha Wildner *
1154ba9607SSascha Wildner * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1280387638SSascha Wildner * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1354ba9607SSascha Wildner * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1480387638SSascha Wildner * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1580387638SSascha Wildner * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1680387638SSascha Wildner * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1780387638SSascha Wildner * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1880387638SSascha Wildner */
1980387638SSascha Wildner #include "config.h"
2080387638SSascha Wildner
2180387638SSascha Wildner #include <sys/types.h>
2280387638SSascha Wildner
2380387638SSascha Wildner #include <assert.h>
2454ba9607SSascha Wildner #if HAVE_ERR
2554ba9607SSascha Wildner #include <err.h>
2654ba9607SSascha Wildner #endif
2780387638SSascha Wildner #include <stdarg.h>
2880387638SSascha Wildner #include <stdint.h>
2980387638SSascha Wildner #include <stdio.h>
3080387638SSascha Wildner #include <stdlib.h>
3180387638SSascha Wildner #include <string.h>
3280387638SSascha Wildner #include <unistd.h>
3380387638SSascha Wildner
34070c62a6SFranco Fichtner #include "mandoc_aux.h"
3580387638SSascha Wildner #include "out.h"
3680387638SSascha Wildner #include "term.h"
3754ba9607SSascha Wildner #include "manconf.h"
3854ba9607SSascha Wildner #include "main.h"
3980387638SSascha Wildner
40a4c7eb57SSascha Wildner /* These work the buffer used by the header and footer. */
41a4c7eb57SSascha Wildner #define PS_BUFSLOP 128
42a4c7eb57SSascha Wildner
4380387638SSascha Wildner /* Convert PostScript point "x" to an AFM unit. */
44070c62a6SFranco Fichtner #define PNT2AFM(p, x) \
45a4c7eb57SSascha Wildner (size_t)((double)(x) * (1000.0 / (double)(p)->ps->scale))
4680387638SSascha Wildner
4780387638SSascha Wildner /* Convert an AFM unit "x" to a PostScript points */
48070c62a6SFranco Fichtner #define AFM2PNT(p, x) \
49a4c7eb57SSascha Wildner ((double)(x) / (1000.0 / (double)(p)->ps->scale))
5080387638SSascha Wildner
5180387638SSascha Wildner struct glyph {
5280387638SSascha Wildner unsigned short wx; /* WX in AFM */
5380387638SSascha Wildner };
5480387638SSascha Wildner
5580387638SSascha Wildner struct font {
5680387638SSascha Wildner const char *name; /* FontName in AFM */
5780387638SSascha Wildner #define MAXCHAR 95 /* total characters we can handle */
5880387638SSascha Wildner struct glyph gly[MAXCHAR]; /* glyph metrics */
5980387638SSascha Wildner };
6080387638SSascha Wildner
61a4c7eb57SSascha Wildner struct termp_ps {
62a4c7eb57SSascha Wildner int flags;
63a4c7eb57SSascha Wildner #define PS_INLINE (1 << 0) /* we're in a word */
64a4c7eb57SSascha Wildner #define PS_MARGINS (1 << 1) /* we're in the margins */
65a4c7eb57SSascha Wildner #define PS_NEWPAGE (1 << 2) /* new page, no words yet */
6654ba9607SSascha Wildner #define PS_BACKSP (1 << 3) /* last character was backspace */
67a4c7eb57SSascha Wildner size_t pscol; /* visible column (AFM units) */
6854ba9607SSascha Wildner size_t pscolnext; /* used for overstrike */
69a4c7eb57SSascha Wildner size_t psrow; /* visible row (AFM units) */
7054ba9607SSascha Wildner size_t lastrow; /* psrow of the previous word */
71a4c7eb57SSascha Wildner char *psmarg; /* margin buf */
72a4c7eb57SSascha Wildner size_t psmargsz; /* margin buf size */
73a4c7eb57SSascha Wildner size_t psmargcur; /* cur index in margin buf */
7454ba9607SSascha Wildner char last; /* last non-backspace seen */
75a4c7eb57SSascha Wildner enum termfont lastf; /* last set font */
7654ba9607SSascha Wildner enum termfont nextf; /* building next font here */
77a4c7eb57SSascha Wildner size_t scale; /* font scaling factor */
78a4c7eb57SSascha Wildner size_t pages; /* number of pages shown */
79a4c7eb57SSascha Wildner size_t lineheight; /* line height (AFM units) */
80a4c7eb57SSascha Wildner size_t top; /* body top (AFM units) */
81a4c7eb57SSascha Wildner size_t bottom; /* body bottom (AFM units) */
8254ba9607SSascha Wildner const char *medianame; /* for DocumentMedia and PageSize */
83a4c7eb57SSascha Wildner size_t height; /* page height (AFM units */
84a4c7eb57SSascha Wildner size_t width; /* page width (AFM units) */
85070c62a6SFranco Fichtner size_t lastwidth; /* page width before last ll */
86a4c7eb57SSascha Wildner size_t left; /* body left (AFM units) */
87a4c7eb57SSascha Wildner size_t header; /* header pos (AFM units) */
88a4c7eb57SSascha Wildner size_t footer; /* footer pos (AFM units) */
89a4c7eb57SSascha Wildner size_t pdfbytes; /* current output byte */
90a4c7eb57SSascha Wildner size_t pdflastpg; /* byte of last page mark */
91a4c7eb57SSascha Wildner size_t pdfbody; /* start of body object */
92a4c7eb57SSascha Wildner size_t *pdfobjs; /* table of object offsets */
93a4c7eb57SSascha Wildner size_t pdfobjsz; /* size of pdfobjs */
94a4c7eb57SSascha Wildner };
95a4c7eb57SSascha Wildner
9654ba9607SSascha Wildner static int ps_hspan(const struct termp *,
97a4c7eb57SSascha Wildner const struct roffsu *);
98a4c7eb57SSascha Wildner static size_t ps_width(const struct termp *, int);
99a4c7eb57SSascha Wildner static void ps_advance(struct termp *, size_t);
100a4c7eb57SSascha Wildner static void ps_begin(struct termp *);
101a4c7eb57SSascha Wildner static void ps_closepage(struct termp *);
102a4c7eb57SSascha Wildner static void ps_end(struct termp *);
103a4c7eb57SSascha Wildner static void ps_endline(struct termp *);
104a4c7eb57SSascha Wildner static void ps_growbuf(struct termp *, size_t);
105a4c7eb57SSascha Wildner static void ps_letter(struct termp *, int);
106a4c7eb57SSascha Wildner static void ps_pclose(struct termp *);
10754ba9607SSascha Wildner static void ps_plast(struct termp *);
108a4c7eb57SSascha Wildner static void ps_pletter(struct termp *, int);
10954ba9607SSascha Wildner static void ps_printf(struct termp *, const char *, ...)
11054ba9607SSascha Wildner __attribute__((__format__ (__printf__, 2, 3)));
111a4c7eb57SSascha Wildner static void ps_putchar(struct termp *, char);
112a4c7eb57SSascha Wildner static void ps_setfont(struct termp *, enum termfont);
11354ba9607SSascha Wildner static void ps_setwidth(struct termp *, int, int);
11454ba9607SSascha Wildner static struct termp *pspdf_alloc(const struct manoutput *, enum termtype);
115a4c7eb57SSascha Wildner static void pdf_obj(struct termp *, size_t);
116a4c7eb57SSascha Wildner
11780387638SSascha Wildner /*
11880387638SSascha Wildner * We define, for the time being, three fonts: bold, oblique/italic, and
11980387638SSascha Wildner * normal (roman). The following table hard-codes the font metrics for
12080387638SSascha Wildner * ASCII, i.e., 32--127.
12180387638SSascha Wildner */
12280387638SSascha Wildner
12380387638SSascha Wildner static const struct font fonts[TERMFONT__MAX] = {
12480387638SSascha Wildner { "Times-Roman", {
12580387638SSascha Wildner { 250 },
12680387638SSascha Wildner { 333 },
12780387638SSascha Wildner { 408 },
12880387638SSascha Wildner { 500 },
12980387638SSascha Wildner { 500 },
13080387638SSascha Wildner { 833 },
13180387638SSascha Wildner { 778 },
13280387638SSascha Wildner { 333 },
13380387638SSascha Wildner { 333 },
13480387638SSascha Wildner { 333 },
13580387638SSascha Wildner { 500 },
13680387638SSascha Wildner { 564 },
13780387638SSascha Wildner { 250 },
13880387638SSascha Wildner { 333 },
13980387638SSascha Wildner { 250 },
14080387638SSascha Wildner { 278 },
14180387638SSascha Wildner { 500 },
14280387638SSascha Wildner { 500 },
14380387638SSascha Wildner { 500 },
14480387638SSascha Wildner { 500 },
14580387638SSascha Wildner { 500 },
14680387638SSascha Wildner { 500 },
14780387638SSascha Wildner { 500 },
14880387638SSascha Wildner { 500 },
14980387638SSascha Wildner { 500 },
15080387638SSascha Wildner { 500 },
15180387638SSascha Wildner { 278 },
15280387638SSascha Wildner { 278 },
15380387638SSascha Wildner { 564 },
15480387638SSascha Wildner { 564 },
15580387638SSascha Wildner { 564 },
15680387638SSascha Wildner { 444 },
15780387638SSascha Wildner { 921 },
15880387638SSascha Wildner { 722 },
15980387638SSascha Wildner { 667 },
16080387638SSascha Wildner { 667 },
16180387638SSascha Wildner { 722 },
16280387638SSascha Wildner { 611 },
16380387638SSascha Wildner { 556 },
16480387638SSascha Wildner { 722 },
16580387638SSascha Wildner { 722 },
16680387638SSascha Wildner { 333 },
16780387638SSascha Wildner { 389 },
16880387638SSascha Wildner { 722 },
16980387638SSascha Wildner { 611 },
17080387638SSascha Wildner { 889 },
17180387638SSascha Wildner { 722 },
17280387638SSascha Wildner { 722 },
17380387638SSascha Wildner { 556 },
17480387638SSascha Wildner { 722 },
17580387638SSascha Wildner { 667 },
17680387638SSascha Wildner { 556 },
17780387638SSascha Wildner { 611 },
17880387638SSascha Wildner { 722 },
17980387638SSascha Wildner { 722 },
18080387638SSascha Wildner { 944 },
18180387638SSascha Wildner { 722 },
18280387638SSascha Wildner { 722 },
18380387638SSascha Wildner { 611 },
18480387638SSascha Wildner { 333 },
18580387638SSascha Wildner { 278 },
18680387638SSascha Wildner { 333 },
18780387638SSascha Wildner { 469 },
18880387638SSascha Wildner { 500 },
18980387638SSascha Wildner { 333 },
19080387638SSascha Wildner { 444 },
19180387638SSascha Wildner { 500 },
19280387638SSascha Wildner { 444 },
19380387638SSascha Wildner { 500},
19480387638SSascha Wildner { 444},
19580387638SSascha Wildner { 333},
19680387638SSascha Wildner { 500},
19780387638SSascha Wildner { 500},
19880387638SSascha Wildner { 278},
19980387638SSascha Wildner { 278},
20080387638SSascha Wildner { 500},
20180387638SSascha Wildner { 278},
20280387638SSascha Wildner { 778},
20380387638SSascha Wildner { 500},
20480387638SSascha Wildner { 500},
20580387638SSascha Wildner { 500},
20680387638SSascha Wildner { 500},
20780387638SSascha Wildner { 333},
20880387638SSascha Wildner { 389},
20980387638SSascha Wildner { 278},
21080387638SSascha Wildner { 500},
21180387638SSascha Wildner { 500},
21280387638SSascha Wildner { 722},
21380387638SSascha Wildner { 500},
21480387638SSascha Wildner { 500},
21580387638SSascha Wildner { 444},
21680387638SSascha Wildner { 480},
21780387638SSascha Wildner { 200},
21880387638SSascha Wildner { 480},
21980387638SSascha Wildner { 541},
22080387638SSascha Wildner } },
22180387638SSascha Wildner { "Times-Bold", {
22280387638SSascha Wildner { 250 },
22380387638SSascha Wildner { 333 },
22480387638SSascha Wildner { 555 },
22580387638SSascha Wildner { 500 },
22680387638SSascha Wildner { 500 },
22780387638SSascha Wildner { 1000 },
22880387638SSascha Wildner { 833 },
22980387638SSascha Wildner { 333 },
23080387638SSascha Wildner { 333 },
23180387638SSascha Wildner { 333 },
23280387638SSascha Wildner { 500 },
23380387638SSascha Wildner { 570 },
23480387638SSascha Wildner { 250 },
23580387638SSascha Wildner { 333 },
23680387638SSascha Wildner { 250 },
23780387638SSascha Wildner { 278 },
23880387638SSascha Wildner { 500 },
23980387638SSascha Wildner { 500 },
24080387638SSascha Wildner { 500 },
24180387638SSascha Wildner { 500 },
24280387638SSascha Wildner { 500 },
24380387638SSascha Wildner { 500 },
24480387638SSascha Wildner { 500 },
24580387638SSascha Wildner { 500 },
24680387638SSascha Wildner { 500 },
24780387638SSascha Wildner { 500 },
24880387638SSascha Wildner { 333 },
24980387638SSascha Wildner { 333 },
25080387638SSascha Wildner { 570 },
25180387638SSascha Wildner { 570 },
25280387638SSascha Wildner { 570 },
25380387638SSascha Wildner { 500 },
25480387638SSascha Wildner { 930 },
25580387638SSascha Wildner { 722 },
25680387638SSascha Wildner { 667 },
25780387638SSascha Wildner { 722 },
25880387638SSascha Wildner { 722 },
25980387638SSascha Wildner { 667 },
26080387638SSascha Wildner { 611 },
26180387638SSascha Wildner { 778 },
26280387638SSascha Wildner { 778 },
26380387638SSascha Wildner { 389 },
26480387638SSascha Wildner { 500 },
26580387638SSascha Wildner { 778 },
26680387638SSascha Wildner { 667 },
26780387638SSascha Wildner { 944 },
26880387638SSascha Wildner { 722 },
26980387638SSascha Wildner { 778 },
27080387638SSascha Wildner { 611 },
27180387638SSascha Wildner { 778 },
27280387638SSascha Wildner { 722 },
27380387638SSascha Wildner { 556 },
27480387638SSascha Wildner { 667 },
27580387638SSascha Wildner { 722 },
27680387638SSascha Wildner { 722 },
27780387638SSascha Wildner { 1000 },
27880387638SSascha Wildner { 722 },
27980387638SSascha Wildner { 722 },
28080387638SSascha Wildner { 667 },
28180387638SSascha Wildner { 333 },
28280387638SSascha Wildner { 278 },
28380387638SSascha Wildner { 333 },
28480387638SSascha Wildner { 581 },
28580387638SSascha Wildner { 500 },
28680387638SSascha Wildner { 333 },
28780387638SSascha Wildner { 500 },
28880387638SSascha Wildner { 556 },
28980387638SSascha Wildner { 444 },
29080387638SSascha Wildner { 556 },
29180387638SSascha Wildner { 444 },
29280387638SSascha Wildner { 333 },
29380387638SSascha Wildner { 500 },
29480387638SSascha Wildner { 556 },
29580387638SSascha Wildner { 278 },
29680387638SSascha Wildner { 333 },
29780387638SSascha Wildner { 556 },
29880387638SSascha Wildner { 278 },
29980387638SSascha Wildner { 833 },
30080387638SSascha Wildner { 556 },
30180387638SSascha Wildner { 500 },
30280387638SSascha Wildner { 556 },
30380387638SSascha Wildner { 556 },
30480387638SSascha Wildner { 444 },
30580387638SSascha Wildner { 389 },
30680387638SSascha Wildner { 333 },
30780387638SSascha Wildner { 556 },
30880387638SSascha Wildner { 500 },
30980387638SSascha Wildner { 722 },
31080387638SSascha Wildner { 500 },
31180387638SSascha Wildner { 500 },
31280387638SSascha Wildner { 444 },
31380387638SSascha Wildner { 394 },
31480387638SSascha Wildner { 220 },
31580387638SSascha Wildner { 394 },
31680387638SSascha Wildner { 520 },
31780387638SSascha Wildner } },
31880387638SSascha Wildner { "Times-Italic", {
31980387638SSascha Wildner { 250 },
32080387638SSascha Wildner { 333 },
32180387638SSascha Wildner { 420 },
32280387638SSascha Wildner { 500 },
32380387638SSascha Wildner { 500 },
32480387638SSascha Wildner { 833 },
32580387638SSascha Wildner { 778 },
32680387638SSascha Wildner { 333 },
32780387638SSascha Wildner { 333 },
32880387638SSascha Wildner { 333 },
32980387638SSascha Wildner { 500 },
33080387638SSascha Wildner { 675 },
33180387638SSascha Wildner { 250 },
33280387638SSascha Wildner { 333 },
33380387638SSascha Wildner { 250 },
33480387638SSascha Wildner { 278 },
33580387638SSascha Wildner { 500 },
33680387638SSascha Wildner { 500 },
33780387638SSascha Wildner { 500 },
33880387638SSascha Wildner { 500 },
33980387638SSascha Wildner { 500 },
34080387638SSascha Wildner { 500 },
34180387638SSascha Wildner { 500 },
34280387638SSascha Wildner { 500 },
34380387638SSascha Wildner { 500 },
34480387638SSascha Wildner { 500 },
34580387638SSascha Wildner { 333 },
34680387638SSascha Wildner { 333 },
34780387638SSascha Wildner { 675 },
34880387638SSascha Wildner { 675 },
34980387638SSascha Wildner { 675 },
35080387638SSascha Wildner { 500 },
35180387638SSascha Wildner { 920 },
35280387638SSascha Wildner { 611 },
35380387638SSascha Wildner { 611 },
35480387638SSascha Wildner { 667 },
35580387638SSascha Wildner { 722 },
35680387638SSascha Wildner { 611 },
35780387638SSascha Wildner { 611 },
35880387638SSascha Wildner { 722 },
35980387638SSascha Wildner { 722 },
36080387638SSascha Wildner { 333 },
36180387638SSascha Wildner { 444 },
36280387638SSascha Wildner { 667 },
36380387638SSascha Wildner { 556 },
36480387638SSascha Wildner { 833 },
36580387638SSascha Wildner { 667 },
36680387638SSascha Wildner { 722 },
36780387638SSascha Wildner { 611 },
36880387638SSascha Wildner { 722 },
36980387638SSascha Wildner { 611 },
37080387638SSascha Wildner { 500 },
37180387638SSascha Wildner { 556 },
37280387638SSascha Wildner { 722 },
37380387638SSascha Wildner { 611 },
37480387638SSascha Wildner { 833 },
37580387638SSascha Wildner { 611 },
37680387638SSascha Wildner { 556 },
37780387638SSascha Wildner { 556 },
37880387638SSascha Wildner { 389 },
37980387638SSascha Wildner { 278 },
38080387638SSascha Wildner { 389 },
38180387638SSascha Wildner { 422 },
38280387638SSascha Wildner { 500 },
38380387638SSascha Wildner { 333 },
38480387638SSascha Wildner { 500 },
38580387638SSascha Wildner { 500 },
38680387638SSascha Wildner { 444 },
38780387638SSascha Wildner { 500 },
38880387638SSascha Wildner { 444 },
38980387638SSascha Wildner { 278 },
39080387638SSascha Wildner { 500 },
39180387638SSascha Wildner { 500 },
39280387638SSascha Wildner { 278 },
39380387638SSascha Wildner { 278 },
39480387638SSascha Wildner { 444 },
39580387638SSascha Wildner { 278 },
39680387638SSascha Wildner { 722 },
39780387638SSascha Wildner { 500 },
39880387638SSascha Wildner { 500 },
39980387638SSascha Wildner { 500 },
40080387638SSascha Wildner { 500 },
40180387638SSascha Wildner { 389 },
40280387638SSascha Wildner { 389 },
40380387638SSascha Wildner { 278 },
40480387638SSascha Wildner { 500 },
40580387638SSascha Wildner { 444 },
40680387638SSascha Wildner { 667 },
40780387638SSascha Wildner { 444 },
40880387638SSascha Wildner { 444 },
40980387638SSascha Wildner { 389 },
41080387638SSascha Wildner { 400 },
41180387638SSascha Wildner { 275 },
41280387638SSascha Wildner { 400 },
41380387638SSascha Wildner { 541 },
41480387638SSascha Wildner } },
41554ba9607SSascha Wildner { "Times-BoldItalic", {
41654ba9607SSascha Wildner { 250 },
41754ba9607SSascha Wildner { 389 },
41854ba9607SSascha Wildner { 555 },
41954ba9607SSascha Wildner { 500 },
42054ba9607SSascha Wildner { 500 },
42154ba9607SSascha Wildner { 833 },
42254ba9607SSascha Wildner { 778 },
42354ba9607SSascha Wildner { 333 },
42454ba9607SSascha Wildner { 333 },
42554ba9607SSascha Wildner { 333 },
42654ba9607SSascha Wildner { 500 },
42754ba9607SSascha Wildner { 570 },
42854ba9607SSascha Wildner { 250 },
42954ba9607SSascha Wildner { 333 },
43054ba9607SSascha Wildner { 250 },
43154ba9607SSascha Wildner { 278 },
43254ba9607SSascha Wildner { 500 },
43354ba9607SSascha Wildner { 500 },
43454ba9607SSascha Wildner { 500 },
43554ba9607SSascha Wildner { 500 },
43654ba9607SSascha Wildner { 500 },
43754ba9607SSascha Wildner { 500 },
43854ba9607SSascha Wildner { 500 },
43954ba9607SSascha Wildner { 500 },
44054ba9607SSascha Wildner { 500 },
44154ba9607SSascha Wildner { 500 },
44254ba9607SSascha Wildner { 333 },
44354ba9607SSascha Wildner { 333 },
44454ba9607SSascha Wildner { 570 },
44554ba9607SSascha Wildner { 570 },
44654ba9607SSascha Wildner { 570 },
44754ba9607SSascha Wildner { 500 },
44854ba9607SSascha Wildner { 832 },
44954ba9607SSascha Wildner { 667 },
45054ba9607SSascha Wildner { 667 },
45154ba9607SSascha Wildner { 667 },
45254ba9607SSascha Wildner { 722 },
45354ba9607SSascha Wildner { 667 },
45454ba9607SSascha Wildner { 667 },
45554ba9607SSascha Wildner { 722 },
45654ba9607SSascha Wildner { 778 },
45754ba9607SSascha Wildner { 389 },
45854ba9607SSascha Wildner { 500 },
45954ba9607SSascha Wildner { 667 },
46054ba9607SSascha Wildner { 611 },
46154ba9607SSascha Wildner { 889 },
46254ba9607SSascha Wildner { 722 },
46354ba9607SSascha Wildner { 722 },
46454ba9607SSascha Wildner { 611 },
46554ba9607SSascha Wildner { 722 },
46654ba9607SSascha Wildner { 667 },
46754ba9607SSascha Wildner { 556 },
46854ba9607SSascha Wildner { 611 },
46954ba9607SSascha Wildner { 722 },
47054ba9607SSascha Wildner { 667 },
47154ba9607SSascha Wildner { 889 },
47254ba9607SSascha Wildner { 667 },
47354ba9607SSascha Wildner { 611 },
47454ba9607SSascha Wildner { 611 },
47554ba9607SSascha Wildner { 333 },
47654ba9607SSascha Wildner { 278 },
47754ba9607SSascha Wildner { 333 },
47854ba9607SSascha Wildner { 570 },
47954ba9607SSascha Wildner { 500 },
48054ba9607SSascha Wildner { 333 },
48154ba9607SSascha Wildner { 500 },
48254ba9607SSascha Wildner { 500 },
48354ba9607SSascha Wildner { 444 },
48454ba9607SSascha Wildner { 500 },
48554ba9607SSascha Wildner { 444 },
48654ba9607SSascha Wildner { 333 },
48754ba9607SSascha Wildner { 500 },
48854ba9607SSascha Wildner { 556 },
48954ba9607SSascha Wildner { 278 },
49054ba9607SSascha Wildner { 278 },
49154ba9607SSascha Wildner { 500 },
49254ba9607SSascha Wildner { 278 },
49354ba9607SSascha Wildner { 778 },
49454ba9607SSascha Wildner { 556 },
49554ba9607SSascha Wildner { 500 },
49654ba9607SSascha Wildner { 500 },
49754ba9607SSascha Wildner { 500 },
49854ba9607SSascha Wildner { 389 },
49954ba9607SSascha Wildner { 389 },
50054ba9607SSascha Wildner { 278 },
50154ba9607SSascha Wildner { 556 },
50254ba9607SSascha Wildner { 444 },
50354ba9607SSascha Wildner { 667 },
50454ba9607SSascha Wildner { 500 },
50554ba9607SSascha Wildner { 444 },
50654ba9607SSascha Wildner { 389 },
50754ba9607SSascha Wildner { 348 },
50854ba9607SSascha Wildner { 220 },
50954ba9607SSascha Wildner { 348 },
51054ba9607SSascha Wildner { 570 },
51154ba9607SSascha Wildner } },
51280387638SSascha Wildner };
51380387638SSascha Wildner
51480387638SSascha Wildner void *
pdf_alloc(const struct manoutput * outopts)51554ba9607SSascha Wildner pdf_alloc(const struct manoutput *outopts)
51680387638SSascha Wildner {
51754ba9607SSascha Wildner return pspdf_alloc(outopts, TERMTYPE_PDF);
51880387638SSascha Wildner }
51980387638SSascha Wildner
52080387638SSascha Wildner void *
ps_alloc(const struct manoutput * outopts)52154ba9607SSascha Wildner ps_alloc(const struct manoutput *outopts)
52280387638SSascha Wildner {
52354ba9607SSascha Wildner return pspdf_alloc(outopts, TERMTYPE_PS);
52480387638SSascha Wildner }
52580387638SSascha Wildner
52680387638SSascha Wildner static struct termp *
pspdf_alloc(const struct manoutput * outopts,enum termtype type)52754ba9607SSascha Wildner pspdf_alloc(const struct manoutput *outopts, enum termtype type)
52880387638SSascha Wildner {
52980387638SSascha Wildner struct termp *p;
53036342e81SSascha Wildner unsigned int pagex, pagey;
53136342e81SSascha Wildner size_t marginx, marginy, lineheight;
53280387638SSascha Wildner const char *pp;
53380387638SSascha Wildner
53454ba9607SSascha Wildner p = mandoc_calloc(1, sizeof(*p));
53554ba9607SSascha Wildner p->tcol = p->tcols = mandoc_calloc(1, sizeof(*p->tcol));
53654ba9607SSascha Wildner p->maxtcol = 1;
53754ba9607SSascha Wildner p->type = type;
53854ba9607SSascha Wildner
539a4c7eb57SSascha Wildner p->enc = TERMENC_ASCII;
54054ba9607SSascha Wildner p->fontq = mandoc_reallocarray(NULL,
54154ba9607SSascha Wildner (p->fontsz = 8), sizeof(*p->fontq));
54254ba9607SSascha Wildner p->fontq[0] = p->fontl = TERMFONT_NONE;
54354ba9607SSascha Wildner p->ps = mandoc_calloc(1, sizeof(*p->ps));
54480387638SSascha Wildner
54580387638SSascha Wildner p->advance = ps_advance;
54680387638SSascha Wildner p->begin = ps_begin;
54780387638SSascha Wildner p->end = ps_end;
54880387638SSascha Wildner p->endline = ps_endline;
54980387638SSascha Wildner p->hspan = ps_hspan;
55080387638SSascha Wildner p->letter = ps_letter;
551070c62a6SFranco Fichtner p->setwidth = ps_setwidth;
55280387638SSascha Wildner p->width = ps_width;
55380387638SSascha Wildner
55480387638SSascha Wildner /* Default to US letter (millimetres). */
55580387638SSascha Wildner
55654ba9607SSascha Wildner p->ps->medianame = "Letter";
55780387638SSascha Wildner pagex = 216;
55880387638SSascha Wildner pagey = 279;
55980387638SSascha Wildner
56080387638SSascha Wildner /*
56180387638SSascha Wildner * The ISO-269 paper sizes can be calculated automatically, but
56280387638SSascha Wildner * it would require bringing in -lm for pow() and I'd rather not
56380387638SSascha Wildner * do that. So just do it the easy way for now. Since this
56480387638SSascha Wildner * only happens once, I'm not terribly concerned.
56580387638SSascha Wildner */
56680387638SSascha Wildner
56754ba9607SSascha Wildner pp = outopts->paper;
56854ba9607SSascha Wildner if (pp != NULL && strcasecmp(pp, "letter") != 0) {
56954ba9607SSascha Wildner if (strcasecmp(pp, "a3") == 0) {
57054ba9607SSascha Wildner p->ps->medianame = "A3";
57180387638SSascha Wildner pagex = 297;
57280387638SSascha Wildner pagey = 420;
57354ba9607SSascha Wildner } else if (strcasecmp(pp, "a4") == 0) {
57454ba9607SSascha Wildner p->ps->medianame = "A4";
57580387638SSascha Wildner pagex = 210;
57680387638SSascha Wildner pagey = 297;
57754ba9607SSascha Wildner } else if (strcasecmp(pp, "a5") == 0) {
57854ba9607SSascha Wildner p->ps->medianame = "A5";
57980387638SSascha Wildner pagex = 148;
58080387638SSascha Wildner pagey = 210;
58154ba9607SSascha Wildner } else if (strcasecmp(pp, "legal") == 0) {
58254ba9607SSascha Wildner p->ps->medianame = "Legal";
58380387638SSascha Wildner pagex = 216;
58480387638SSascha Wildner pagey = 356;
58554ba9607SSascha Wildner } else if (sscanf(pp, "%ux%u", &pagex, &pagey) == 2)
58654ba9607SSascha Wildner p->ps->medianame = "CustomSize";
58754ba9607SSascha Wildner else
58854ba9607SSascha Wildner warnx("%s: Unknown paper", pp);
58936342e81SSascha Wildner }
59080387638SSascha Wildner
59180387638SSascha Wildner /*
59280387638SSascha Wildner * This MUST be defined before any PNT2AFM or AFM2PNT
59380387638SSascha Wildner * calculations occur.
59480387638SSascha Wildner */
59580387638SSascha Wildner
596a4c7eb57SSascha Wildner p->ps->scale = 11;
59780387638SSascha Wildner
59880387638SSascha Wildner /* Remember millimetres -> AFM units. */
59980387638SSascha Wildner
60054ba9607SSascha Wildner pagex = PNT2AFM(p, ((double)pagex * 72.0 / 25.4));
60154ba9607SSascha Wildner pagey = PNT2AFM(p, ((double)pagey * 72.0 / 25.4));
60280387638SSascha Wildner
60380387638SSascha Wildner /* Margins are 1/9 the page x and y. */
60480387638SSascha Wildner
605070c62a6SFranco Fichtner marginx = (size_t)((double)pagex / 9.0);
606070c62a6SFranco Fichtner marginy = (size_t)((double)pagey / 9.0);
60780387638SSascha Wildner
60880387638SSascha Wildner /* Line-height is 1.4em. */
60980387638SSascha Wildner
610a4c7eb57SSascha Wildner lineheight = PNT2AFM(p, ((double)p->ps->scale * 1.4));
61180387638SSascha Wildner
612070c62a6SFranco Fichtner p->ps->width = p->ps->lastwidth = (size_t)pagex;
61336342e81SSascha Wildner p->ps->height = (size_t)pagey;
614a4c7eb57SSascha Wildner p->ps->header = pagey - (marginy / 2) - (lineheight / 2);
615a4c7eb57SSascha Wildner p->ps->top = pagey - marginy;
616a4c7eb57SSascha Wildner p->ps->footer = (marginy / 2) - (lineheight / 2);
617a4c7eb57SSascha Wildner p->ps->bottom = marginy;
618a4c7eb57SSascha Wildner p->ps->left = marginx;
619a4c7eb57SSascha Wildner p->ps->lineheight = lineheight;
62080387638SSascha Wildner
62180387638SSascha Wildner p->defrmargin = pagex - (marginx * 2);
62254ba9607SSascha Wildner return p;
62380387638SSascha Wildner }
62480387638SSascha Wildner
625070c62a6SFranco Fichtner static void
ps_setwidth(struct termp * p,int iop,int width)62654ba9607SSascha Wildner ps_setwidth(struct termp *p, int iop, int width)
627070c62a6SFranco Fichtner {
628070c62a6SFranco Fichtner size_t lastwidth;
629070c62a6SFranco Fichtner
630070c62a6SFranco Fichtner lastwidth = p->ps->width;
63154ba9607SSascha Wildner if (iop > 0)
632070c62a6SFranco Fichtner p->ps->width += width;
63354ba9607SSascha Wildner else if (iop == 0)
63454ba9607SSascha Wildner p->ps->width = width ? (size_t)width : p->ps->lastwidth;
63554ba9607SSascha Wildner else if (p->ps->width > (size_t)width)
636070c62a6SFranco Fichtner p->ps->width -= width;
637070c62a6SFranco Fichtner else
63854ba9607SSascha Wildner p->ps->width = 0;
639070c62a6SFranco Fichtner p->ps->lastwidth = lastwidth;
640070c62a6SFranco Fichtner }
64180387638SSascha Wildner
64280387638SSascha Wildner void
pspdf_free(void * arg)64380387638SSascha Wildner pspdf_free(void *arg)
64480387638SSascha Wildner {
64580387638SSascha Wildner struct termp *p;
64680387638SSascha Wildner
64780387638SSascha Wildner p = (struct termp *)arg;
64880387638SSascha Wildner
649a4c7eb57SSascha Wildner free(p->ps->psmarg);
650a4c7eb57SSascha Wildner free(p->ps->pdfobjs);
65180387638SSascha Wildner
652a4c7eb57SSascha Wildner free(p->ps);
65380387638SSascha Wildner term_free(p);
65480387638SSascha Wildner }
65580387638SSascha Wildner
65680387638SSascha Wildner static void
ps_printf(struct termp * p,const char * fmt,...)65780387638SSascha Wildner ps_printf(struct termp *p, const char *fmt, ...)
65880387638SSascha Wildner {
65980387638SSascha Wildner va_list ap;
66080387638SSascha Wildner int pos, len;
66180387638SSascha Wildner
66280387638SSascha Wildner va_start(ap, fmt);
66380387638SSascha Wildner
66480387638SSascha Wildner /*
66580387638SSascha Wildner * If we're running in regular mode, then pipe directly into
66680387638SSascha Wildner * vprintf(). If we're processing margins, then push the data
66780387638SSascha Wildner * into our growable margin buffer.
66880387638SSascha Wildner */
66980387638SSascha Wildner
670a4c7eb57SSascha Wildner if ( ! (PS_MARGINS & p->ps->flags)) {
67180387638SSascha Wildner len = vprintf(fmt, ap);
67280387638SSascha Wildner va_end(ap);
673070c62a6SFranco Fichtner p->ps->pdfbytes += len < 0 ? 0 : (size_t)len;
67480387638SSascha Wildner return;
67580387638SSascha Wildner }
67680387638SSascha Wildner
67780387638SSascha Wildner /*
67880387638SSascha Wildner * XXX: I assume that the in-margin print won't exceed
67980387638SSascha Wildner * PS_BUFSLOP (128 bytes), which is reasonable but still an
68080387638SSascha Wildner * assumption that will cause pukeage if it's not the case.
68180387638SSascha Wildner */
68280387638SSascha Wildner
68380387638SSascha Wildner ps_growbuf(p, PS_BUFSLOP);
68480387638SSascha Wildner
685a4c7eb57SSascha Wildner pos = (int)p->ps->psmargcur;
68636342e81SSascha Wildner vsnprintf(&p->ps->psmarg[pos], PS_BUFSLOP, fmt, ap);
68780387638SSascha Wildner
68880387638SSascha Wildner va_end(ap);
68980387638SSascha Wildner
690a4c7eb57SSascha Wildner p->ps->psmargcur = strlen(p->ps->psmarg);
69180387638SSascha Wildner }
69280387638SSascha Wildner
69380387638SSascha Wildner static void
ps_putchar(struct termp * p,char c)69480387638SSascha Wildner ps_putchar(struct termp *p, char c)
69580387638SSascha Wildner {
69680387638SSascha Wildner int pos;
69780387638SSascha Wildner
69880387638SSascha Wildner /* See ps_printf(). */
69980387638SSascha Wildner
700a4c7eb57SSascha Wildner if ( ! (PS_MARGINS & p->ps->flags)) {
70180387638SSascha Wildner putchar(c);
702a4c7eb57SSascha Wildner p->ps->pdfbytes++;
70380387638SSascha Wildner return;
70480387638SSascha Wildner }
70580387638SSascha Wildner
70680387638SSascha Wildner ps_growbuf(p, 2);
70780387638SSascha Wildner
708a4c7eb57SSascha Wildner pos = (int)p->ps->psmargcur++;
709a4c7eb57SSascha Wildner p->ps->psmarg[pos++] = c;
710a4c7eb57SSascha Wildner p->ps->psmarg[pos] = '\0';
71180387638SSascha Wildner }
71280387638SSascha Wildner
71380387638SSascha Wildner static void
pdf_obj(struct termp * p,size_t obj)71480387638SSascha Wildner pdf_obj(struct termp *p, size_t obj)
71580387638SSascha Wildner {
71680387638SSascha Wildner
71780387638SSascha Wildner assert(obj > 0);
71880387638SSascha Wildner
719a4c7eb57SSascha Wildner if ((obj - 1) >= p->ps->pdfobjsz) {
720a4c7eb57SSascha Wildner p->ps->pdfobjsz = obj + 128;
721070c62a6SFranco Fichtner p->ps->pdfobjs = mandoc_reallocarray(p->ps->pdfobjs,
722070c62a6SFranco Fichtner p->ps->pdfobjsz, sizeof(size_t));
72380387638SSascha Wildner }
72480387638SSascha Wildner
725a4c7eb57SSascha Wildner p->ps->pdfobjs[(int)obj - 1] = p->ps->pdfbytes;
72680387638SSascha Wildner ps_printf(p, "%zu 0 obj\n", obj);
72780387638SSascha Wildner }
72880387638SSascha Wildner
72980387638SSascha Wildner static void
ps_closepage(struct termp * p)73080387638SSascha Wildner ps_closepage(struct termp *p)
73180387638SSascha Wildner {
73280387638SSascha Wildner int i;
73380387638SSascha Wildner size_t len, base;
73480387638SSascha Wildner
73580387638SSascha Wildner /*
73680387638SSascha Wildner * Close out a page that we've already flushed to output. In
73754ba9607SSascha Wildner * PostScript, we simply note that the page must be shown. In
73880387638SSascha Wildner * PDF, we must now create the Length, Resource, and Page node
73980387638SSascha Wildner * for the page contents.
74080387638SSascha Wildner */
74180387638SSascha Wildner
742a4c7eb57SSascha Wildner assert(p->ps->psmarg && p->ps->psmarg[0]);
743a4c7eb57SSascha Wildner ps_printf(p, "%s", p->ps->psmarg);
74480387638SSascha Wildner
74580387638SSascha Wildner if (TERMTYPE_PS != p->type) {
746a4c7eb57SSascha Wildner len = p->ps->pdfbytes - p->ps->pdflastpg;
747a4c7eb57SSascha Wildner base = p->ps->pages * 4 + p->ps->pdfbody;
74880387638SSascha Wildner
74980387638SSascha Wildner ps_printf(p, "endstream\nendobj\n");
75080387638SSascha Wildner
75180387638SSascha Wildner /* Length of content. */
75280387638SSascha Wildner pdf_obj(p, base + 1);
75380387638SSascha Wildner ps_printf(p, "%zu\nendobj\n", len);
75480387638SSascha Wildner
75580387638SSascha Wildner /* Resource for content. */
75680387638SSascha Wildner pdf_obj(p, base + 2);
75780387638SSascha Wildner ps_printf(p, "<<\n/ProcSet [/PDF /Text]\n");
75880387638SSascha Wildner ps_printf(p, "/Font <<\n");
75980387638SSascha Wildner for (i = 0; i < (int)TERMFONT__MAX; i++)
76080387638SSascha Wildner ps_printf(p, "/F%d %d 0 R\n", i, 3 + i);
76154ba9607SSascha Wildner ps_printf(p, ">>\n>>\nendobj\n");
76280387638SSascha Wildner
76380387638SSascha Wildner /* Page node. */
76480387638SSascha Wildner pdf_obj(p, base + 3);
76580387638SSascha Wildner ps_printf(p, "<<\n");
76680387638SSascha Wildner ps_printf(p, "/Type /Page\n");
76780387638SSascha Wildner ps_printf(p, "/Parent 2 0 R\n");
76880387638SSascha Wildner ps_printf(p, "/Resources %zu 0 R\n", base + 2);
76980387638SSascha Wildner ps_printf(p, "/Contents %zu 0 R\n", base);
77080387638SSascha Wildner ps_printf(p, ">>\nendobj\n");
77180387638SSascha Wildner } else
77280387638SSascha Wildner ps_printf(p, "showpage\n");
77380387638SSascha Wildner
774a4c7eb57SSascha Wildner p->ps->pages++;
775a4c7eb57SSascha Wildner p->ps->psrow = p->ps->top;
776a4c7eb57SSascha Wildner assert( ! (PS_NEWPAGE & p->ps->flags));
777a4c7eb57SSascha Wildner p->ps->flags |= PS_NEWPAGE;
77880387638SSascha Wildner }
77980387638SSascha Wildner
78080387638SSascha Wildner static void
ps_end(struct termp * p)78180387638SSascha Wildner ps_end(struct termp *p)
78280387638SSascha Wildner {
78380387638SSascha Wildner size_t i, xref, base;
78480387638SSascha Wildner
78554ba9607SSascha Wildner ps_plast(p);
78654ba9607SSascha Wildner ps_pclose(p);
78754ba9607SSascha Wildner
78880387638SSascha Wildner /*
78980387638SSascha Wildner * At the end of the file, do one last showpage. This is the
79080387638SSascha Wildner * same behaviour as groff(1) and works for multiple pages as
79180387638SSascha Wildner * well as just one.
79280387638SSascha Wildner */
79380387638SSascha Wildner
794a4c7eb57SSascha Wildner if ( ! (PS_NEWPAGE & p->ps->flags)) {
795a4c7eb57SSascha Wildner assert(0 == p->ps->flags);
796a4c7eb57SSascha Wildner assert('\0' == p->ps->last);
79780387638SSascha Wildner ps_closepage(p);
79880387638SSascha Wildner }
79980387638SSascha Wildner
80080387638SSascha Wildner if (TERMTYPE_PS == p->type) {
80180387638SSascha Wildner ps_printf(p, "%%%%Trailer\n");
802a4c7eb57SSascha Wildner ps_printf(p, "%%%%Pages: %zu\n", p->ps->pages);
80380387638SSascha Wildner ps_printf(p, "%%%%EOF\n");
80480387638SSascha Wildner return;
80580387638SSascha Wildner }
80680387638SSascha Wildner
80780387638SSascha Wildner pdf_obj(p, 2);
80880387638SSascha Wildner ps_printf(p, "<<\n/Type /Pages\n");
80980387638SSascha Wildner ps_printf(p, "/MediaBox [0 0 %zu %zu]\n",
810a4c7eb57SSascha Wildner (size_t)AFM2PNT(p, p->ps->width),
811a4c7eb57SSascha Wildner (size_t)AFM2PNT(p, p->ps->height));
81280387638SSascha Wildner
813a4c7eb57SSascha Wildner ps_printf(p, "/Count %zu\n", p->ps->pages);
81480387638SSascha Wildner ps_printf(p, "/Kids [");
81580387638SSascha Wildner
816a4c7eb57SSascha Wildner for (i = 0; i < p->ps->pages; i++)
817070c62a6SFranco Fichtner ps_printf(p, " %zu 0 R", i * 4 + p->ps->pdfbody + 3);
81880387638SSascha Wildner
819070c62a6SFranco Fichtner base = (p->ps->pages - 1) * 4 + p->ps->pdfbody + 4;
82080387638SSascha Wildner
82180387638SSascha Wildner ps_printf(p, "]\n>>\nendobj\n");
82280387638SSascha Wildner pdf_obj(p, base);
82380387638SSascha Wildner ps_printf(p, "<<\n");
82480387638SSascha Wildner ps_printf(p, "/Type /Catalog\n");
82580387638SSascha Wildner ps_printf(p, "/Pages 2 0 R\n");
82654ba9607SSascha Wildner ps_printf(p, ">>\nendobj\n");
827a4c7eb57SSascha Wildner xref = p->ps->pdfbytes;
82880387638SSascha Wildner ps_printf(p, "xref\n");
82980387638SSascha Wildner ps_printf(p, "0 %zu\n", base + 1);
83080387638SSascha Wildner ps_printf(p, "0000000000 65535 f \n");
83180387638SSascha Wildner
83280387638SSascha Wildner for (i = 0; i < base; i++)
83380387638SSascha Wildner ps_printf(p, "%.10zu 00000 n \n",
834a4c7eb57SSascha Wildner p->ps->pdfobjs[(int)i]);
83580387638SSascha Wildner
83680387638SSascha Wildner ps_printf(p, "trailer\n");
83780387638SSascha Wildner ps_printf(p, "<<\n");
83880387638SSascha Wildner ps_printf(p, "/Size %zu\n", base + 1);
83980387638SSascha Wildner ps_printf(p, "/Root %zu 0 R\n", base);
84080387638SSascha Wildner ps_printf(p, "/Info 1 0 R\n");
84180387638SSascha Wildner ps_printf(p, ">>\n");
84280387638SSascha Wildner ps_printf(p, "startxref\n");
84380387638SSascha Wildner ps_printf(p, "%zu\n", xref);
84480387638SSascha Wildner ps_printf(p, "%%%%EOF\n");
84580387638SSascha Wildner }
84680387638SSascha Wildner
84780387638SSascha Wildner static void
ps_begin(struct termp * p)84880387638SSascha Wildner ps_begin(struct termp *p)
84980387638SSascha Wildner {
85054ba9607SSascha Wildner size_t width, height;
85180387638SSascha Wildner int i;
85280387638SSascha Wildner
85380387638SSascha Wildner /*
85480387638SSascha Wildner * Print margins into margin buffer. Nothing gets output to the
85580387638SSascha Wildner * screen yet, so we don't need to initialise the primary state.
85680387638SSascha Wildner */
85780387638SSascha Wildner
858a4c7eb57SSascha Wildner if (p->ps->psmarg) {
859a4c7eb57SSascha Wildner assert(p->ps->psmargsz);
860a4c7eb57SSascha Wildner p->ps->psmarg[0] = '\0';
86180387638SSascha Wildner }
86280387638SSascha Wildner
863a4c7eb57SSascha Wildner /*p->ps->pdfbytes = 0;*/
864a4c7eb57SSascha Wildner p->ps->psmargcur = 0;
865a4c7eb57SSascha Wildner p->ps->flags = PS_MARGINS;
866a4c7eb57SSascha Wildner p->ps->pscol = p->ps->left;
867a4c7eb57SSascha Wildner p->ps->psrow = p->ps->header;
86854ba9607SSascha Wildner p->ps->lastrow = 0; /* impossible row */
86980387638SSascha Wildner
87080387638SSascha Wildner ps_setfont(p, TERMFONT_NONE);
87180387638SSascha Wildner
87280387638SSascha Wildner (*p->headf)(p, p->argf);
87380387638SSascha Wildner (*p->endline)(p);
87480387638SSascha Wildner
875a4c7eb57SSascha Wildner p->ps->pscol = p->ps->left;
876a4c7eb57SSascha Wildner p->ps->psrow = p->ps->footer;
87780387638SSascha Wildner
87880387638SSascha Wildner (*p->footf)(p, p->argf);
87980387638SSascha Wildner (*p->endline)(p);
88080387638SSascha Wildner
881a4c7eb57SSascha Wildner p->ps->flags &= ~PS_MARGINS;
88280387638SSascha Wildner
883a4c7eb57SSascha Wildner assert(0 == p->ps->flags);
884a4c7eb57SSascha Wildner assert(p->ps->psmarg);
885a4c7eb57SSascha Wildner assert('\0' != p->ps->psmarg[0]);
88680387638SSascha Wildner
88780387638SSascha Wildner /*
88880387638SSascha Wildner * Print header and initialise page state. Following this,
88980387638SSascha Wildner * stuff gets printed to the screen, so make sure we're sane.
89080387638SSascha Wildner */
89180387638SSascha Wildner
89280387638SSascha Wildner if (TERMTYPE_PS == p->type) {
89354ba9607SSascha Wildner width = AFM2PNT(p, p->ps->width);
89454ba9607SSascha Wildner height = AFM2PNT(p, p->ps->height);
89554ba9607SSascha Wildner
89680387638SSascha Wildner ps_printf(p, "%%!PS-Adobe-3.0\n");
89780387638SSascha Wildner ps_printf(p, "%%%%DocumentData: Clean7Bit\n");
89880387638SSascha Wildner ps_printf(p, "%%%%Orientation: Portrait\n");
89980387638SSascha Wildner ps_printf(p, "%%%%Pages: (atend)\n");
90080387638SSascha Wildner ps_printf(p, "%%%%PageOrder: Ascend\n");
90154ba9607SSascha Wildner ps_printf(p, "%%%%DocumentMedia: man-%s %zu %zu 0 () ()\n",
90254ba9607SSascha Wildner p->ps->medianame, width, height);
90380387638SSascha Wildner ps_printf(p, "%%%%DocumentNeededResources: font");
90480387638SSascha Wildner
90580387638SSascha Wildner for (i = 0; i < (int)TERMFONT__MAX; i++)
90680387638SSascha Wildner ps_printf(p, " %s", fonts[i].name);
90780387638SSascha Wildner
90854ba9607SSascha Wildner ps_printf(p, "\n%%%%DocumentSuppliedResources: "
90954ba9607SSascha Wildner "procset MandocProcs 1.0 0\n");
91054ba9607SSascha Wildner ps_printf(p, "%%%%EndComments\n");
91154ba9607SSascha Wildner ps_printf(p, "%%%%BeginProlog\n");
91254ba9607SSascha Wildner ps_printf(p, "%%%%BeginResource: procset MandocProcs "
91354ba9607SSascha Wildner "10170 10170\n");
91454ba9607SSascha Wildner /* The font size is effectively hard-coded for now. */
91554ba9607SSascha Wildner ps_printf(p, "/fs %zu def\n", p->ps->scale);
91654ba9607SSascha Wildner for (i = 0; i < (int)TERMFONT__MAX; i++)
91754ba9607SSascha Wildner ps_printf(p, "/f%d { /%s fs selectfont } def\n",
91854ba9607SSascha Wildner i, fonts[i].name);
91954ba9607SSascha Wildner ps_printf(p, "/s { 3 1 roll moveto show } bind def\n");
92054ba9607SSascha Wildner ps_printf(p, "/c { exch currentpoint exch pop "
92154ba9607SSascha Wildner "moveto show } bind def\n");
92254ba9607SSascha Wildner ps_printf(p, "%%%%EndResource\n");
92354ba9607SSascha Wildner ps_printf(p, "%%%%EndProlog\n");
92454ba9607SSascha Wildner ps_printf(p, "%%%%BeginSetup\n");
92554ba9607SSascha Wildner ps_printf(p, "%%%%BeginFeature: *PageSize %s\n",
92654ba9607SSascha Wildner p->ps->medianame);
92754ba9607SSascha Wildner ps_printf(p, "<</PageSize [%zu %zu]>>setpagedevice\n",
92854ba9607SSascha Wildner width, height);
92954ba9607SSascha Wildner ps_printf(p, "%%%%EndFeature\n");
93054ba9607SSascha Wildner ps_printf(p, "%%%%EndSetup\n");
93180387638SSascha Wildner } else {
93280387638SSascha Wildner ps_printf(p, "%%PDF-1.1\n");
93380387638SSascha Wildner pdf_obj(p, 1);
93480387638SSascha Wildner ps_printf(p, "<<\n");
93580387638SSascha Wildner ps_printf(p, ">>\n");
93680387638SSascha Wildner ps_printf(p, "endobj\n");
93780387638SSascha Wildner
93880387638SSascha Wildner for (i = 0; i < (int)TERMFONT__MAX; i++) {
93980387638SSascha Wildner pdf_obj(p, (size_t)i + 3);
94080387638SSascha Wildner ps_printf(p, "<<\n");
94180387638SSascha Wildner ps_printf(p, "/Type /Font\n");
94280387638SSascha Wildner ps_printf(p, "/Subtype /Type1\n");
943070c62a6SFranco Fichtner ps_printf(p, "/Name /F%d\n", i);
94480387638SSascha Wildner ps_printf(p, "/BaseFont /%s\n", fonts[i].name);
94554ba9607SSascha Wildner ps_printf(p, ">>\nendobj\n");
94680387638SSascha Wildner }
94780387638SSascha Wildner }
94880387638SSascha Wildner
949a4c7eb57SSascha Wildner p->ps->pdfbody = (size_t)TERMFONT__MAX + 3;
950a4c7eb57SSascha Wildner p->ps->pscol = p->ps->left;
951a4c7eb57SSascha Wildner p->ps->psrow = p->ps->top;
952a4c7eb57SSascha Wildner p->ps->flags |= PS_NEWPAGE;
95380387638SSascha Wildner ps_setfont(p, TERMFONT_NONE);
95480387638SSascha Wildner }
95580387638SSascha Wildner
95680387638SSascha Wildner static void
ps_pletter(struct termp * p,int c)95780387638SSascha Wildner ps_pletter(struct termp *p, int c)
95880387638SSascha Wildner {
95980387638SSascha Wildner int f;
96080387638SSascha Wildner
96180387638SSascha Wildner /*
96280387638SSascha Wildner * If we haven't opened a page context, then output that we're
96380387638SSascha Wildner * in a new page and make sure the font is correctly set.
96480387638SSascha Wildner */
96580387638SSascha Wildner
966a4c7eb57SSascha Wildner if (PS_NEWPAGE & p->ps->flags) {
96780387638SSascha Wildner if (TERMTYPE_PS == p->type) {
96880387638SSascha Wildner ps_printf(p, "%%%%Page: %zu %zu\n",
969070c62a6SFranco Fichtner p->ps->pages + 1, p->ps->pages + 1);
97054ba9607SSascha Wildner ps_printf(p, "f%d\n", (int)p->ps->lastf);
97180387638SSascha Wildner } else {
972a4c7eb57SSascha Wildner pdf_obj(p, p->ps->pdfbody +
973a4c7eb57SSascha Wildner p->ps->pages * 4);
97480387638SSascha Wildner ps_printf(p, "<<\n");
97580387638SSascha Wildner ps_printf(p, "/Length %zu 0 R\n",
976070c62a6SFranco Fichtner p->ps->pdfbody + 1 + p->ps->pages * 4);
97780387638SSascha Wildner ps_printf(p, ">>\nstream\n");
97880387638SSascha Wildner }
979a4c7eb57SSascha Wildner p->ps->pdflastpg = p->ps->pdfbytes;
980a4c7eb57SSascha Wildner p->ps->flags &= ~PS_NEWPAGE;
98180387638SSascha Wildner }
98280387638SSascha Wildner
98380387638SSascha Wildner /*
98480387638SSascha Wildner * If we're not in a PostScript "word" context, then open one
98580387638SSascha Wildner * now at the current cursor.
98680387638SSascha Wildner */
98780387638SSascha Wildner
988a4c7eb57SSascha Wildner if ( ! (PS_INLINE & p->ps->flags)) {
98980387638SSascha Wildner if (TERMTYPE_PS != p->type) {
99080387638SSascha Wildner ps_printf(p, "BT\n/F%d %zu Tf\n",
991070c62a6SFranco Fichtner (int)p->ps->lastf, p->ps->scale);
99280387638SSascha Wildner ps_printf(p, "%.3f %.3f Td\n(",
993a4c7eb57SSascha Wildner AFM2PNT(p, p->ps->pscol),
994a4c7eb57SSascha Wildner AFM2PNT(p, p->ps->psrow));
99554ba9607SSascha Wildner } else {
99654ba9607SSascha Wildner ps_printf(p, "%.3f", AFM2PNT(p, p->ps->pscol));
99754ba9607SSascha Wildner if (p->ps->psrow != p->ps->lastrow)
99854ba9607SSascha Wildner ps_printf(p, " %.3f",
999a4c7eb57SSascha Wildner AFM2PNT(p, p->ps->psrow));
100054ba9607SSascha Wildner ps_printf(p, "(");
100154ba9607SSascha Wildner }
1002a4c7eb57SSascha Wildner p->ps->flags |= PS_INLINE;
100380387638SSascha Wildner }
100480387638SSascha Wildner
1005a4c7eb57SSascha Wildner assert( ! (PS_NEWPAGE & p->ps->flags));
100680387638SSascha Wildner
100780387638SSascha Wildner /*
100880387638SSascha Wildner * We need to escape these characters as per the PostScript
100980387638SSascha Wildner * specification. We would also escape non-graphable characters
101080387638SSascha Wildner * (like tabs), but none of them would get to this point and
101180387638SSascha Wildner * it's superfluous to abort() on them.
101280387638SSascha Wildner */
101380387638SSascha Wildner
101480387638SSascha Wildner switch (c) {
1015070c62a6SFranco Fichtner case '(':
1016070c62a6SFranco Fichtner case ')':
1017070c62a6SFranco Fichtner case '\\':
101880387638SSascha Wildner ps_putchar(p, '\\');
101980387638SSascha Wildner break;
102080387638SSascha Wildner default:
102180387638SSascha Wildner break;
102280387638SSascha Wildner }
102380387638SSascha Wildner
102480387638SSascha Wildner /* Write the character and adjust where we are on the page. */
102580387638SSascha Wildner
1026a4c7eb57SSascha Wildner f = (int)p->ps->lastf;
102780387638SSascha Wildner
1028070c62a6SFranco Fichtner if (c <= 32 || c - 32 >= MAXCHAR)
1029070c62a6SFranco Fichtner c = 32;
103080387638SSascha Wildner
103180387638SSascha Wildner ps_putchar(p, (char)c);
103280387638SSascha Wildner c -= 32;
1033a4c7eb57SSascha Wildner p->ps->pscol += (size_t)fonts[f].gly[c].wx;
103480387638SSascha Wildner }
103580387638SSascha Wildner
103680387638SSascha Wildner static void
ps_pclose(struct termp * p)103780387638SSascha Wildner ps_pclose(struct termp *p)
103880387638SSascha Wildner {
103980387638SSascha Wildner
104080387638SSascha Wildner /*
104180387638SSascha Wildner * Spit out that we're exiting a word context (this is a
104280387638SSascha Wildner * "partial close" because we don't check the last-char buffer
104380387638SSascha Wildner * or anything).
104480387638SSascha Wildner */
104580387638SSascha Wildner
1046a4c7eb57SSascha Wildner if ( ! (PS_INLINE & p->ps->flags))
104780387638SSascha Wildner return;
104880387638SSascha Wildner
104954ba9607SSascha Wildner if (TERMTYPE_PS != p->type)
105080387638SSascha Wildner ps_printf(p, ") Tj\nET\n");
105154ba9607SSascha Wildner else if (p->ps->psrow == p->ps->lastrow)
105254ba9607SSascha Wildner ps_printf(p, ")c\n");
105354ba9607SSascha Wildner else {
105454ba9607SSascha Wildner ps_printf(p, ")s\n");
105554ba9607SSascha Wildner p->ps->lastrow = p->ps->psrow;
105654ba9607SSascha Wildner }
105780387638SSascha Wildner
1058a4c7eb57SSascha Wildner p->ps->flags &= ~PS_INLINE;
105980387638SSascha Wildner }
106080387638SSascha Wildner
106154ba9607SSascha Wildner /* If we have a `last' char that wasn't printed yet, print it now. */
106280387638SSascha Wildner static void
ps_plast(struct termp * p)106354ba9607SSascha Wildner ps_plast(struct termp *p)
106480387638SSascha Wildner {
106554ba9607SSascha Wildner size_t wx;
106680387638SSascha Wildner
106754ba9607SSascha Wildner if (p->ps->last == '\0')
106880387638SSascha Wildner return;
106980387638SSascha Wildner
107054ba9607SSascha Wildner /* Check the font mode; open a new scope if it doesn't match. */
107154ba9607SSascha Wildner
107254ba9607SSascha Wildner if (p->ps->nextf != p->ps->lastf) {
107380387638SSascha Wildner ps_pclose(p);
107454ba9607SSascha Wildner ps_setfont(p, p->ps->nextf);
107554ba9607SSascha Wildner }
107654ba9607SSascha Wildner p->ps->nextf = TERMFONT_NONE;
107754ba9607SSascha Wildner
107854ba9607SSascha Wildner /*
107954ba9607SSascha Wildner * For an overstrike, if a previous character
108054ba9607SSascha Wildner * was wider, advance to center the new one.
108154ba9607SSascha Wildner */
108254ba9607SSascha Wildner
108354ba9607SSascha Wildner if (p->ps->pscolnext) {
108454ba9607SSascha Wildner wx = fonts[p->ps->lastf].gly[(int)p->ps->last-32].wx;
108554ba9607SSascha Wildner if (p->ps->pscol + wx < p->ps->pscolnext)
108654ba9607SSascha Wildner p->ps->pscol = (p->ps->pscol +
108754ba9607SSascha Wildner p->ps->pscolnext - wx) / 2;
108854ba9607SSascha Wildner }
108954ba9607SSascha Wildner
109054ba9607SSascha Wildner ps_pletter(p, p->ps->last);
109154ba9607SSascha Wildner p->ps->last = '\0';
109254ba9607SSascha Wildner
109354ba9607SSascha Wildner /*
109454ba9607SSascha Wildner * For an overstrike, if a previous character
109554ba9607SSascha Wildner * was wider, advance to the end of the old one.
109654ba9607SSascha Wildner */
109754ba9607SSascha Wildner
109854ba9607SSascha Wildner if (p->ps->pscol < p->ps->pscolnext) {
109954ba9607SSascha Wildner ps_pclose(p);
110054ba9607SSascha Wildner p->ps->pscol = p->ps->pscolnext;
110154ba9607SSascha Wildner }
110280387638SSascha Wildner }
110380387638SSascha Wildner
110480387638SSascha Wildner static void
ps_letter(struct termp * p,int arg)1105a4c7eb57SSascha Wildner ps_letter(struct termp *p, int arg)
110680387638SSascha Wildner {
110754ba9607SSascha Wildner size_t savecol;
110854ba9607SSascha Wildner char c;
1109a4c7eb57SSascha Wildner
1110a4c7eb57SSascha Wildner c = arg >= 128 || arg <= 0 ? '?' : arg;
111180387638SSascha Wildner
111280387638SSascha Wildner /*
111354ba9607SSascha Wildner * When receiving a backspace, merely flag it.
111454ba9607SSascha Wildner * We don't know yet whether it is
111554ba9607SSascha Wildner * a font instruction or an overstrike.
111680387638SSascha Wildner */
111780387638SSascha Wildner
111854ba9607SSascha Wildner if (c == '\b') {
111954ba9607SSascha Wildner assert(p->ps->last != '\0');
112054ba9607SSascha Wildner assert( ! (p->ps->flags & PS_BACKSP));
112154ba9607SSascha Wildner p->ps->flags |= PS_BACKSP;
112280387638SSascha Wildner return;
112380387638SSascha Wildner }
112480387638SSascha Wildner
112554ba9607SSascha Wildner /*
112654ba9607SSascha Wildner * Decode font instructions.
112754ba9607SSascha Wildner */
112854ba9607SSascha Wildner
112954ba9607SSascha Wildner if (p->ps->flags & PS_BACKSP) {
113054ba9607SSascha Wildner if (p->ps->last == '_') {
113154ba9607SSascha Wildner switch (p->ps->nextf) {
113254ba9607SSascha Wildner case TERMFONT_BI:
113354ba9607SSascha Wildner break;
113454ba9607SSascha Wildner case TERMFONT_BOLD:
113554ba9607SSascha Wildner p->ps->nextf = TERMFONT_BI;
113654ba9607SSascha Wildner break;
113754ba9607SSascha Wildner default:
113854ba9607SSascha Wildner p->ps->nextf = TERMFONT_UNDER;
113954ba9607SSascha Wildner }
114054ba9607SSascha Wildner p->ps->last = c;
114154ba9607SSascha Wildner p->ps->flags &= ~PS_BACKSP;
114254ba9607SSascha Wildner return;
114354ba9607SSascha Wildner }
114454ba9607SSascha Wildner if (p->ps->last == c) {
114554ba9607SSascha Wildner switch (p->ps->nextf) {
114654ba9607SSascha Wildner case TERMFONT_BI:
114754ba9607SSascha Wildner break;
114854ba9607SSascha Wildner case TERMFONT_UNDER:
114954ba9607SSascha Wildner p->ps->nextf = TERMFONT_BI;
115054ba9607SSascha Wildner break;
115154ba9607SSascha Wildner default:
115254ba9607SSascha Wildner p->ps->nextf = TERMFONT_BOLD;
115354ba9607SSascha Wildner }
115454ba9607SSascha Wildner p->ps->flags &= ~PS_BACKSP;
115554ba9607SSascha Wildner return;
115654ba9607SSascha Wildner }
115754ba9607SSascha Wildner
115854ba9607SSascha Wildner /*
115954ba9607SSascha Wildner * This is not a font instruction, but rather
116054ba9607SSascha Wildner * the next character. Prepare for overstrike.
116154ba9607SSascha Wildner */
116254ba9607SSascha Wildner
116354ba9607SSascha Wildner savecol = p->ps->pscol;
116454ba9607SSascha Wildner } else
116554ba9607SSascha Wildner savecol = SIZE_MAX;
116654ba9607SSascha Wildner
116754ba9607SSascha Wildner /*
116854ba9607SSascha Wildner * We found the next character, so the font instructions
116954ba9607SSascha Wildner * for the previous one are complete.
117054ba9607SSascha Wildner * Use them and print it.
117154ba9607SSascha Wildner */
117254ba9607SSascha Wildner
117354ba9607SSascha Wildner ps_plast(p);
117454ba9607SSascha Wildner
117554ba9607SSascha Wildner /*
117654ba9607SSascha Wildner * Do not print the current character yet because font
117754ba9607SSascha Wildner * instructions might follow; only remember the character.
117854ba9607SSascha Wildner * It will get printed later from ps_plast().
117954ba9607SSascha Wildner */
118054ba9607SSascha Wildner
118154ba9607SSascha Wildner p->ps->last = c;
118254ba9607SSascha Wildner
118354ba9607SSascha Wildner /*
118454ba9607SSascha Wildner * For an overstrike, back up to the previous position.
118554ba9607SSascha Wildner * If the previous character is wider than any it overstrikes,
118654ba9607SSascha Wildner * remember the current position, because it might also be
118754ba9607SSascha Wildner * wider than all that will overstrike it.
118854ba9607SSascha Wildner */
118954ba9607SSascha Wildner
119054ba9607SSascha Wildner if (savecol != SIZE_MAX) {
119154ba9607SSascha Wildner if (p->ps->pscolnext < p->ps->pscol)
119254ba9607SSascha Wildner p->ps->pscolnext = p->ps->pscol;
119354ba9607SSascha Wildner ps_pclose(p);
119454ba9607SSascha Wildner p->ps->pscol = savecol;
119554ba9607SSascha Wildner p->ps->flags &= ~PS_BACKSP;
119654ba9607SSascha Wildner } else
119754ba9607SSascha Wildner p->ps->pscolnext = 0;
119880387638SSascha Wildner }
119980387638SSascha Wildner
120080387638SSascha Wildner static void
ps_advance(struct termp * p,size_t len)120180387638SSascha Wildner ps_advance(struct termp *p, size_t len)
120280387638SSascha Wildner {
120380387638SSascha Wildner
120480387638SSascha Wildner /*
120580387638SSascha Wildner * Advance some spaces. This can probably be made smarter,
120680387638SSascha Wildner * i.e., to have multiple space-separated words in the same
120780387638SSascha Wildner * scope, but this is easier: just close out the current scope
120880387638SSascha Wildner * and readjust our column settings.
120980387638SSascha Wildner */
121080387638SSascha Wildner
121154ba9607SSascha Wildner ps_plast(p);
121254ba9607SSascha Wildner ps_pclose(p);
1213a4c7eb57SSascha Wildner p->ps->pscol += len;
121480387638SSascha Wildner }
121580387638SSascha Wildner
121680387638SSascha Wildner static void
ps_endline(struct termp * p)121780387638SSascha Wildner ps_endline(struct termp *p)
121880387638SSascha Wildner {
121980387638SSascha Wildner
122080387638SSascha Wildner /* Close out any scopes we have open: we're at eoln. */
122180387638SSascha Wildner
122254ba9607SSascha Wildner ps_plast(p);
122354ba9607SSascha Wildner ps_pclose(p);
122480387638SSascha Wildner
122580387638SSascha Wildner /*
122680387638SSascha Wildner * If we're in the margin, don't try to recalculate our current
122780387638SSascha Wildner * row. XXX: if the column tries to be fancy with multiple
122880387638SSascha Wildner * lines, we'll do nasty stuff.
122980387638SSascha Wildner */
123080387638SSascha Wildner
1231a4c7eb57SSascha Wildner if (PS_MARGINS & p->ps->flags)
123280387638SSascha Wildner return;
123380387638SSascha Wildner
123480387638SSascha Wildner /* Left-justify. */
123580387638SSascha Wildner
1236a4c7eb57SSascha Wildner p->ps->pscol = p->ps->left;
123780387638SSascha Wildner
123880387638SSascha Wildner /* If we haven't printed anything, return. */
123980387638SSascha Wildner
1240a4c7eb57SSascha Wildner if (PS_NEWPAGE & p->ps->flags)
124180387638SSascha Wildner return;
124280387638SSascha Wildner
124380387638SSascha Wildner /*
124480387638SSascha Wildner * Put us down a line. If we're at the page bottom, spit out a
124580387638SSascha Wildner * showpage and restart our row.
124680387638SSascha Wildner */
124780387638SSascha Wildner
1248070c62a6SFranco Fichtner if (p->ps->psrow >= p->ps->lineheight + p->ps->bottom) {
1249a4c7eb57SSascha Wildner p->ps->psrow -= p->ps->lineheight;
125080387638SSascha Wildner return;
125180387638SSascha Wildner }
125280387638SSascha Wildner
125380387638SSascha Wildner ps_closepage(p);
125454ba9607SSascha Wildner
1255*99db7d0eSSascha Wildner if ((int)p->tcol->offset > p->ti)
125654ba9607SSascha Wildner p->tcol->offset -= p->ti;
1257*99db7d0eSSascha Wildner else
1258*99db7d0eSSascha Wildner p->tcol->offset = 0;
125954ba9607SSascha Wildner p->ti = 0;
126080387638SSascha Wildner }
126180387638SSascha Wildner
126280387638SSascha Wildner static void
ps_setfont(struct termp * p,enum termfont f)126380387638SSascha Wildner ps_setfont(struct termp *p, enum termfont f)
126480387638SSascha Wildner {
126580387638SSascha Wildner
126680387638SSascha Wildner assert(f < TERMFONT__MAX);
1267a4c7eb57SSascha Wildner p->ps->lastf = f;
126880387638SSascha Wildner
126980387638SSascha Wildner /*
127080387638SSascha Wildner * If we're still at the top of the page, let the font-setting
127180387638SSascha Wildner * be delayed until we actually have stuff to print.
127280387638SSascha Wildner */
127380387638SSascha Wildner
1274a4c7eb57SSascha Wildner if (PS_NEWPAGE & p->ps->flags)
127580387638SSascha Wildner return;
127680387638SSascha Wildner
127780387638SSascha Wildner if (TERMTYPE_PS == p->type)
127854ba9607SSascha Wildner ps_printf(p, "f%d\n", (int)f);
127980387638SSascha Wildner else
128080387638SSascha Wildner ps_printf(p, "/F%d %zu Tf\n",
1281070c62a6SFranco Fichtner (int)f, p->ps->scale);
128280387638SSascha Wildner }
128380387638SSascha Wildner
128480387638SSascha Wildner static size_t
ps_width(const struct termp * p,int c)1285a4c7eb57SSascha Wildner ps_width(const struct termp *p, int c)
128680387638SSascha Wildner {
128780387638SSascha Wildner
128880387638SSascha Wildner if (c <= 32 || c - 32 >= MAXCHAR)
1289070c62a6SFranco Fichtner c = 0;
1290070c62a6SFranco Fichtner else
129180387638SSascha Wildner c -= 32;
1292070c62a6SFranco Fichtner
129354ba9607SSascha Wildner return (size_t)fonts[(int)TERMFONT_NONE].gly[c].wx;
129480387638SSascha Wildner }
129580387638SSascha Wildner
129654ba9607SSascha Wildner static int
ps_hspan(const struct termp * p,const struct roffsu * su)129780387638SSascha Wildner ps_hspan(const struct termp *p, const struct roffsu *su)
129880387638SSascha Wildner {
129980387638SSascha Wildner double r;
130080387638SSascha Wildner
130180387638SSascha Wildner /*
130280387638SSascha Wildner * All of these measurements are derived by converting from the
130380387638SSascha Wildner * native measurement to AFM units.
130480387638SSascha Wildner */
130580387638SSascha Wildner switch (su->unit) {
130654ba9607SSascha Wildner case SCALE_BU:
130754ba9607SSascha Wildner /*
130854ba9607SSascha Wildner * Traditionally, the default unit is fixed to the
130954ba9607SSascha Wildner * output media. So this would refer to the point. In
131054ba9607SSascha Wildner * mandoc(1), however, we stick to the default terminal
131154ba9607SSascha Wildner * scaling unit so that output is the same regardless
131254ba9607SSascha Wildner * the media.
131354ba9607SSascha Wildner */
131454ba9607SSascha Wildner r = PNT2AFM(p, su->scale * 72.0 / 240.0);
131554ba9607SSascha Wildner break;
1316070c62a6SFranco Fichtner case SCALE_CM:
131754ba9607SSascha Wildner r = PNT2AFM(p, su->scale * 72.0 / 2.54);
131880387638SSascha Wildner break;
1319070c62a6SFranco Fichtner case SCALE_EM:
132080387638SSascha Wildner r = su->scale *
132180387638SSascha Wildner fonts[(int)TERMFONT_NONE].gly[109 - 32].wx;
132280387638SSascha Wildner break;
1323070c62a6SFranco Fichtner case SCALE_EN:
132480387638SSascha Wildner r = su->scale *
132580387638SSascha Wildner fonts[(int)TERMFONT_NONE].gly[110 - 32].wx;
132680387638SSascha Wildner break;
132754ba9607SSascha Wildner case SCALE_IN:
132854ba9607SSascha Wildner r = PNT2AFM(p, su->scale * 72.0);
132954ba9607SSascha Wildner break;
133054ba9607SSascha Wildner case SCALE_MM:
133154ba9607SSascha Wildner r = su->scale *
133254ba9607SSascha Wildner fonts[(int)TERMFONT_NONE].gly[109 - 32].wx / 100.0;
133354ba9607SSascha Wildner break;
133454ba9607SSascha Wildner case SCALE_PC:
133554ba9607SSascha Wildner r = PNT2AFM(p, su->scale * 12.0);
133654ba9607SSascha Wildner break;
133754ba9607SSascha Wildner case SCALE_PT:
133854ba9607SSascha Wildner r = PNT2AFM(p, su->scale * 1.0);
133954ba9607SSascha Wildner break;
1340070c62a6SFranco Fichtner case SCALE_VS:
1341a4c7eb57SSascha Wildner r = su->scale * p->ps->lineheight;
134280387638SSascha Wildner break;
134380387638SSascha Wildner default:
134480387638SSascha Wildner r = su->scale;
134580387638SSascha Wildner break;
134680387638SSascha Wildner }
134780387638SSascha Wildner
134854ba9607SSascha Wildner return r * 24.0;
134980387638SSascha Wildner }
135080387638SSascha Wildner
1351a4c7eb57SSascha Wildner static void
ps_growbuf(struct termp * p,size_t sz)1352a4c7eb57SSascha Wildner ps_growbuf(struct termp *p, size_t sz)
1353a4c7eb57SSascha Wildner {
1354a4c7eb57SSascha Wildner if (p->ps->psmargcur + sz <= p->ps->psmargsz)
1355a4c7eb57SSascha Wildner return;
1356a4c7eb57SSascha Wildner
1357a4c7eb57SSascha Wildner if (sz < PS_BUFSLOP)
1358a4c7eb57SSascha Wildner sz = PS_BUFSLOP;
1359a4c7eb57SSascha Wildner
1360a4c7eb57SSascha Wildner p->ps->psmargsz += sz;
1361070c62a6SFranco Fichtner p->ps->psmarg = mandoc_realloc(p->ps->psmarg, p->ps->psmargsz);
1362a4c7eb57SSascha Wildner }
1363