1*6640c13bSYuri Pankov /* $Id: term_ps.c,v 1.91 2017/11/10 23:42:52 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 395c635efSGarrett D'Amore * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4c66b8046SYuri Pankov * Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org> 5*6640c13bSYuri Pankov * Copyright (c) 2017 Marc Espie <espie@openbsd.org> 695c635efSGarrett D'Amore * 795c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 895c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 995c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 1095c635efSGarrett D'Amore * 11371584c2SYuri Pankov * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 1295c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13371584c2SYuri Pankov * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 1495c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1595c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1695c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1795c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1895c635efSGarrett D'Amore */ 1995c635efSGarrett D'Amore #include "config.h" 2095c635efSGarrett D'Amore 2195c635efSGarrett D'Amore #include <sys/types.h> 2295c635efSGarrett D'Amore 2395c635efSGarrett D'Amore #include <assert.h> 24371584c2SYuri Pankov #if HAVE_ERR 25371584c2SYuri Pankov #include <err.h> 26371584c2SYuri Pankov #endif 2795c635efSGarrett D'Amore #include <stdarg.h> 2895c635efSGarrett D'Amore #include <stdint.h> 2995c635efSGarrett D'Amore #include <stdio.h> 3095c635efSGarrett D'Amore #include <stdlib.h> 3195c635efSGarrett D'Amore #include <string.h> 3295c635efSGarrett D'Amore #include <unistd.h> 3395c635efSGarrett D'Amore 34260e9a87SYuri Pankov #include "mandoc_aux.h" 3595c635efSGarrett D'Amore #include "out.h" 3695c635efSGarrett D'Amore #include "term.h" 37371584c2SYuri Pankov #include "manconf.h" 38260e9a87SYuri Pankov #include "main.h" 3995c635efSGarrett D'Amore 4095c635efSGarrett D'Amore /* These work the buffer used by the header and footer. */ 4195c635efSGarrett D'Amore #define PS_BUFSLOP 128 4295c635efSGarrett D'Amore 4395c635efSGarrett D'Amore /* Convert PostScript point "x" to an AFM unit. */ 44260e9a87SYuri Pankov #define PNT2AFM(p, x) \ 4595c635efSGarrett D'Amore (size_t)((double)(x) * (1000.0 / (double)(p)->ps->scale)) 4695c635efSGarrett D'Amore 4795c635efSGarrett D'Amore /* Convert an AFM unit "x" to a PostScript points */ 48260e9a87SYuri Pankov #define AFM2PNT(p, x) \ 4995c635efSGarrett D'Amore ((double)(x) / (1000.0 / (double)(p)->ps->scale)) 5095c635efSGarrett D'Amore 5195c635efSGarrett D'Amore struct glyph { 5295c635efSGarrett D'Amore unsigned short wx; /* WX in AFM */ 5395c635efSGarrett D'Amore }; 5495c635efSGarrett D'Amore 5595c635efSGarrett D'Amore struct font { 5695c635efSGarrett D'Amore const char *name; /* FontName in AFM */ 5795c635efSGarrett D'Amore #define MAXCHAR 95 /* total characters we can handle */ 5895c635efSGarrett D'Amore struct glyph gly[MAXCHAR]; /* glyph metrics */ 5995c635efSGarrett D'Amore }; 6095c635efSGarrett D'Amore 6195c635efSGarrett D'Amore struct termp_ps { 6295c635efSGarrett D'Amore int flags; 6395c635efSGarrett D'Amore #define PS_INLINE (1 << 0) /* we're in a word */ 6495c635efSGarrett D'Amore #define PS_MARGINS (1 << 1) /* we're in the margins */ 6595c635efSGarrett D'Amore #define PS_NEWPAGE (1 << 2) /* new page, no words yet */ 66260e9a87SYuri Pankov #define PS_BACKSP (1 << 3) /* last character was backspace */ 6795c635efSGarrett D'Amore size_t pscol; /* visible column (AFM units) */ 68260e9a87SYuri Pankov size_t pscolnext; /* used for overstrike */ 6995c635efSGarrett D'Amore size_t psrow; /* visible row (AFM units) */ 70*6640c13bSYuri Pankov size_t lastrow; /* psrow of the previous word */ 7195c635efSGarrett D'Amore char *psmarg; /* margin buf */ 7295c635efSGarrett D'Amore size_t psmargsz; /* margin buf size */ 7395c635efSGarrett D'Amore size_t psmargcur; /* cur index in margin buf */ 74260e9a87SYuri Pankov char last; /* last non-backspace seen */ 7595c635efSGarrett D'Amore enum termfont lastf; /* last set font */ 76260e9a87SYuri Pankov enum termfont nextf; /* building next font here */ 7795c635efSGarrett D'Amore size_t scale; /* font scaling factor */ 7895c635efSGarrett D'Amore size_t pages; /* number of pages shown */ 7995c635efSGarrett D'Amore size_t lineheight; /* line height (AFM units) */ 8095c635efSGarrett D'Amore size_t top; /* body top (AFM units) */ 8195c635efSGarrett D'Amore size_t bottom; /* body bottom (AFM units) */ 82*6640c13bSYuri Pankov const char *medianame; /* for DocumentMedia and PageSize */ 8395c635efSGarrett D'Amore size_t height; /* page height (AFM units */ 8495c635efSGarrett D'Amore size_t width; /* page width (AFM units) */ 85260e9a87SYuri Pankov size_t lastwidth; /* page width before last ll */ 8695c635efSGarrett D'Amore size_t left; /* body left (AFM units) */ 8795c635efSGarrett D'Amore size_t header; /* header pos (AFM units) */ 8895c635efSGarrett D'Amore size_t footer; /* footer pos (AFM units) */ 8995c635efSGarrett D'Amore size_t pdfbytes; /* current output byte */ 9095c635efSGarrett D'Amore size_t pdflastpg; /* byte of last page mark */ 9195c635efSGarrett D'Amore size_t pdfbody; /* start of body object */ 9295c635efSGarrett D'Amore size_t *pdfobjs; /* table of object offsets */ 9395c635efSGarrett D'Amore size_t pdfobjsz; /* size of pdfobjs */ 9495c635efSGarrett D'Amore }; 9595c635efSGarrett D'Amore 96371584c2SYuri Pankov static int ps_hspan(const struct termp *, 9795c635efSGarrett D'Amore const struct roffsu *); 9895c635efSGarrett D'Amore static size_t ps_width(const struct termp *, int); 9995c635efSGarrett D'Amore static void ps_advance(struct termp *, size_t); 10095c635efSGarrett D'Amore static void ps_begin(struct termp *); 10195c635efSGarrett D'Amore static void ps_closepage(struct termp *); 10295c635efSGarrett D'Amore static void ps_end(struct termp *); 10395c635efSGarrett D'Amore static void ps_endline(struct termp *); 10495c635efSGarrett D'Amore static void ps_growbuf(struct termp *, size_t); 10595c635efSGarrett D'Amore static void ps_letter(struct termp *, int); 10695c635efSGarrett D'Amore static void ps_pclose(struct termp *); 107a40ea1a7SYuri Pankov static void ps_plast(struct termp *); 10895c635efSGarrett D'Amore static void ps_pletter(struct termp *, int); 109a40ea1a7SYuri Pankov static void ps_printf(struct termp *, const char *, ...) 110a40ea1a7SYuri Pankov __attribute__((__format__ (__printf__, 2, 3))); 11195c635efSGarrett D'Amore static void ps_putchar(struct termp *, char); 11295c635efSGarrett D'Amore static void ps_setfont(struct termp *, enum termfont); 113371584c2SYuri Pankov static void ps_setwidth(struct termp *, int, int); 114*6640c13bSYuri Pankov static struct termp *pspdf_alloc(const struct manoutput *, enum termtype); 11595c635efSGarrett D'Amore static void pdf_obj(struct termp *, size_t); 11695c635efSGarrett D'Amore 11795c635efSGarrett D'Amore /* 11895c635efSGarrett D'Amore * We define, for the time being, three fonts: bold, oblique/italic, and 11995c635efSGarrett D'Amore * normal (roman). The following table hard-codes the font metrics for 12095c635efSGarrett D'Amore * ASCII, i.e., 32--127. 12195c635efSGarrett D'Amore */ 12295c635efSGarrett D'Amore 12395c635efSGarrett D'Amore static const struct font fonts[TERMFONT__MAX] = { 12495c635efSGarrett D'Amore { "Times-Roman", { 12595c635efSGarrett D'Amore { 250 }, 12695c635efSGarrett D'Amore { 333 }, 12795c635efSGarrett D'Amore { 408 }, 12895c635efSGarrett D'Amore { 500 }, 12995c635efSGarrett D'Amore { 500 }, 13095c635efSGarrett D'Amore { 833 }, 13195c635efSGarrett D'Amore { 778 }, 13295c635efSGarrett D'Amore { 333 }, 13395c635efSGarrett D'Amore { 333 }, 13495c635efSGarrett D'Amore { 333 }, 13595c635efSGarrett D'Amore { 500 }, 13695c635efSGarrett D'Amore { 564 }, 13795c635efSGarrett D'Amore { 250 }, 13895c635efSGarrett D'Amore { 333 }, 13995c635efSGarrett D'Amore { 250 }, 14095c635efSGarrett D'Amore { 278 }, 14195c635efSGarrett D'Amore { 500 }, 14295c635efSGarrett D'Amore { 500 }, 14395c635efSGarrett D'Amore { 500 }, 14495c635efSGarrett D'Amore { 500 }, 14595c635efSGarrett D'Amore { 500 }, 14695c635efSGarrett D'Amore { 500 }, 14795c635efSGarrett D'Amore { 500 }, 14895c635efSGarrett D'Amore { 500 }, 14995c635efSGarrett D'Amore { 500 }, 15095c635efSGarrett D'Amore { 500 }, 15195c635efSGarrett D'Amore { 278 }, 15295c635efSGarrett D'Amore { 278 }, 15395c635efSGarrett D'Amore { 564 }, 15495c635efSGarrett D'Amore { 564 }, 15595c635efSGarrett D'Amore { 564 }, 15695c635efSGarrett D'Amore { 444 }, 15795c635efSGarrett D'Amore { 921 }, 15895c635efSGarrett D'Amore { 722 }, 15995c635efSGarrett D'Amore { 667 }, 16095c635efSGarrett D'Amore { 667 }, 16195c635efSGarrett D'Amore { 722 }, 16295c635efSGarrett D'Amore { 611 }, 16395c635efSGarrett D'Amore { 556 }, 16495c635efSGarrett D'Amore { 722 }, 16595c635efSGarrett D'Amore { 722 }, 16695c635efSGarrett D'Amore { 333 }, 16795c635efSGarrett D'Amore { 389 }, 16895c635efSGarrett D'Amore { 722 }, 16995c635efSGarrett D'Amore { 611 }, 17095c635efSGarrett D'Amore { 889 }, 17195c635efSGarrett D'Amore { 722 }, 17295c635efSGarrett D'Amore { 722 }, 17395c635efSGarrett D'Amore { 556 }, 17495c635efSGarrett D'Amore { 722 }, 17595c635efSGarrett D'Amore { 667 }, 17695c635efSGarrett D'Amore { 556 }, 17795c635efSGarrett D'Amore { 611 }, 17895c635efSGarrett D'Amore { 722 }, 17995c635efSGarrett D'Amore { 722 }, 18095c635efSGarrett D'Amore { 944 }, 18195c635efSGarrett D'Amore { 722 }, 18295c635efSGarrett D'Amore { 722 }, 18395c635efSGarrett D'Amore { 611 }, 18495c635efSGarrett D'Amore { 333 }, 18595c635efSGarrett D'Amore { 278 }, 18695c635efSGarrett D'Amore { 333 }, 18795c635efSGarrett D'Amore { 469 }, 18895c635efSGarrett D'Amore { 500 }, 18995c635efSGarrett D'Amore { 333 }, 19095c635efSGarrett D'Amore { 444 }, 19195c635efSGarrett D'Amore { 500 }, 19295c635efSGarrett D'Amore { 444 }, 19395c635efSGarrett D'Amore { 500}, 19495c635efSGarrett D'Amore { 444}, 19595c635efSGarrett D'Amore { 333}, 19695c635efSGarrett D'Amore { 500}, 19795c635efSGarrett D'Amore { 500}, 19895c635efSGarrett D'Amore { 278}, 19995c635efSGarrett D'Amore { 278}, 20095c635efSGarrett D'Amore { 500}, 20195c635efSGarrett D'Amore { 278}, 20295c635efSGarrett D'Amore { 778}, 20395c635efSGarrett D'Amore { 500}, 20495c635efSGarrett D'Amore { 500}, 20595c635efSGarrett D'Amore { 500}, 20695c635efSGarrett D'Amore { 500}, 20795c635efSGarrett D'Amore { 333}, 20895c635efSGarrett D'Amore { 389}, 20995c635efSGarrett D'Amore { 278}, 21095c635efSGarrett D'Amore { 500}, 21195c635efSGarrett D'Amore { 500}, 21295c635efSGarrett D'Amore { 722}, 21395c635efSGarrett D'Amore { 500}, 21495c635efSGarrett D'Amore { 500}, 21595c635efSGarrett D'Amore { 444}, 21695c635efSGarrett D'Amore { 480}, 21795c635efSGarrett D'Amore { 200}, 21895c635efSGarrett D'Amore { 480}, 21995c635efSGarrett D'Amore { 541}, 22095c635efSGarrett D'Amore } }, 22195c635efSGarrett D'Amore { "Times-Bold", { 22295c635efSGarrett D'Amore { 250 }, 22395c635efSGarrett D'Amore { 333 }, 22495c635efSGarrett D'Amore { 555 }, 22595c635efSGarrett D'Amore { 500 }, 22695c635efSGarrett D'Amore { 500 }, 22795c635efSGarrett D'Amore { 1000 }, 22895c635efSGarrett D'Amore { 833 }, 22995c635efSGarrett D'Amore { 333 }, 23095c635efSGarrett D'Amore { 333 }, 23195c635efSGarrett D'Amore { 333 }, 23295c635efSGarrett D'Amore { 500 }, 23395c635efSGarrett D'Amore { 570 }, 23495c635efSGarrett D'Amore { 250 }, 23595c635efSGarrett D'Amore { 333 }, 23695c635efSGarrett D'Amore { 250 }, 23795c635efSGarrett D'Amore { 278 }, 23895c635efSGarrett D'Amore { 500 }, 23995c635efSGarrett D'Amore { 500 }, 24095c635efSGarrett D'Amore { 500 }, 24195c635efSGarrett D'Amore { 500 }, 24295c635efSGarrett D'Amore { 500 }, 24395c635efSGarrett D'Amore { 500 }, 24495c635efSGarrett D'Amore { 500 }, 24595c635efSGarrett D'Amore { 500 }, 24695c635efSGarrett D'Amore { 500 }, 24795c635efSGarrett D'Amore { 500 }, 24895c635efSGarrett D'Amore { 333 }, 24995c635efSGarrett D'Amore { 333 }, 25095c635efSGarrett D'Amore { 570 }, 25195c635efSGarrett D'Amore { 570 }, 25295c635efSGarrett D'Amore { 570 }, 25395c635efSGarrett D'Amore { 500 }, 25495c635efSGarrett D'Amore { 930 }, 25595c635efSGarrett D'Amore { 722 }, 25695c635efSGarrett D'Amore { 667 }, 25795c635efSGarrett D'Amore { 722 }, 25895c635efSGarrett D'Amore { 722 }, 25995c635efSGarrett D'Amore { 667 }, 26095c635efSGarrett D'Amore { 611 }, 26195c635efSGarrett D'Amore { 778 }, 26295c635efSGarrett D'Amore { 778 }, 26395c635efSGarrett D'Amore { 389 }, 26495c635efSGarrett D'Amore { 500 }, 26595c635efSGarrett D'Amore { 778 }, 26695c635efSGarrett D'Amore { 667 }, 26795c635efSGarrett D'Amore { 944 }, 26895c635efSGarrett D'Amore { 722 }, 26995c635efSGarrett D'Amore { 778 }, 27095c635efSGarrett D'Amore { 611 }, 27195c635efSGarrett D'Amore { 778 }, 27295c635efSGarrett D'Amore { 722 }, 27395c635efSGarrett D'Amore { 556 }, 27495c635efSGarrett D'Amore { 667 }, 27595c635efSGarrett D'Amore { 722 }, 27695c635efSGarrett D'Amore { 722 }, 27795c635efSGarrett D'Amore { 1000 }, 27895c635efSGarrett D'Amore { 722 }, 27995c635efSGarrett D'Amore { 722 }, 28095c635efSGarrett D'Amore { 667 }, 28195c635efSGarrett D'Amore { 333 }, 28295c635efSGarrett D'Amore { 278 }, 28395c635efSGarrett D'Amore { 333 }, 28495c635efSGarrett D'Amore { 581 }, 28595c635efSGarrett D'Amore { 500 }, 28695c635efSGarrett D'Amore { 333 }, 28795c635efSGarrett D'Amore { 500 }, 28895c635efSGarrett D'Amore { 556 }, 28995c635efSGarrett D'Amore { 444 }, 29095c635efSGarrett D'Amore { 556 }, 29195c635efSGarrett D'Amore { 444 }, 29295c635efSGarrett D'Amore { 333 }, 29395c635efSGarrett D'Amore { 500 }, 29495c635efSGarrett D'Amore { 556 }, 29595c635efSGarrett D'Amore { 278 }, 29695c635efSGarrett D'Amore { 333 }, 29795c635efSGarrett D'Amore { 556 }, 29895c635efSGarrett D'Amore { 278 }, 29995c635efSGarrett D'Amore { 833 }, 30095c635efSGarrett D'Amore { 556 }, 30195c635efSGarrett D'Amore { 500 }, 30295c635efSGarrett D'Amore { 556 }, 30395c635efSGarrett D'Amore { 556 }, 30495c635efSGarrett D'Amore { 444 }, 30595c635efSGarrett D'Amore { 389 }, 30695c635efSGarrett D'Amore { 333 }, 30795c635efSGarrett D'Amore { 556 }, 30895c635efSGarrett D'Amore { 500 }, 30995c635efSGarrett D'Amore { 722 }, 31095c635efSGarrett D'Amore { 500 }, 31195c635efSGarrett D'Amore { 500 }, 31295c635efSGarrett D'Amore { 444 }, 31395c635efSGarrett D'Amore { 394 }, 31495c635efSGarrett D'Amore { 220 }, 31595c635efSGarrett D'Amore { 394 }, 31695c635efSGarrett D'Amore { 520 }, 31795c635efSGarrett D'Amore } }, 31895c635efSGarrett D'Amore { "Times-Italic", { 31995c635efSGarrett D'Amore { 250 }, 32095c635efSGarrett D'Amore { 333 }, 32195c635efSGarrett D'Amore { 420 }, 32295c635efSGarrett D'Amore { 500 }, 32395c635efSGarrett D'Amore { 500 }, 32495c635efSGarrett D'Amore { 833 }, 32595c635efSGarrett D'Amore { 778 }, 32695c635efSGarrett D'Amore { 333 }, 32795c635efSGarrett D'Amore { 333 }, 32895c635efSGarrett D'Amore { 333 }, 32995c635efSGarrett D'Amore { 500 }, 33095c635efSGarrett D'Amore { 675 }, 33195c635efSGarrett D'Amore { 250 }, 33295c635efSGarrett D'Amore { 333 }, 33395c635efSGarrett D'Amore { 250 }, 33495c635efSGarrett D'Amore { 278 }, 33595c635efSGarrett D'Amore { 500 }, 33695c635efSGarrett D'Amore { 500 }, 33795c635efSGarrett D'Amore { 500 }, 33895c635efSGarrett D'Amore { 500 }, 33995c635efSGarrett D'Amore { 500 }, 34095c635efSGarrett D'Amore { 500 }, 34195c635efSGarrett D'Amore { 500 }, 34295c635efSGarrett D'Amore { 500 }, 34395c635efSGarrett D'Amore { 500 }, 34495c635efSGarrett D'Amore { 500 }, 34595c635efSGarrett D'Amore { 333 }, 34695c635efSGarrett D'Amore { 333 }, 34795c635efSGarrett D'Amore { 675 }, 34895c635efSGarrett D'Amore { 675 }, 34995c635efSGarrett D'Amore { 675 }, 35095c635efSGarrett D'Amore { 500 }, 35195c635efSGarrett D'Amore { 920 }, 35295c635efSGarrett D'Amore { 611 }, 35395c635efSGarrett D'Amore { 611 }, 35495c635efSGarrett D'Amore { 667 }, 35595c635efSGarrett D'Amore { 722 }, 35695c635efSGarrett D'Amore { 611 }, 35795c635efSGarrett D'Amore { 611 }, 35895c635efSGarrett D'Amore { 722 }, 35995c635efSGarrett D'Amore { 722 }, 36095c635efSGarrett D'Amore { 333 }, 36195c635efSGarrett D'Amore { 444 }, 36295c635efSGarrett D'Amore { 667 }, 36395c635efSGarrett D'Amore { 556 }, 36495c635efSGarrett D'Amore { 833 }, 36595c635efSGarrett D'Amore { 667 }, 36695c635efSGarrett D'Amore { 722 }, 36795c635efSGarrett D'Amore { 611 }, 36895c635efSGarrett D'Amore { 722 }, 36995c635efSGarrett D'Amore { 611 }, 37095c635efSGarrett D'Amore { 500 }, 37195c635efSGarrett D'Amore { 556 }, 37295c635efSGarrett D'Amore { 722 }, 37395c635efSGarrett D'Amore { 611 }, 37495c635efSGarrett D'Amore { 833 }, 37595c635efSGarrett D'Amore { 611 }, 37695c635efSGarrett D'Amore { 556 }, 37795c635efSGarrett D'Amore { 556 }, 37895c635efSGarrett D'Amore { 389 }, 37995c635efSGarrett D'Amore { 278 }, 38095c635efSGarrett D'Amore { 389 }, 38195c635efSGarrett D'Amore { 422 }, 38295c635efSGarrett D'Amore { 500 }, 38395c635efSGarrett D'Amore { 333 }, 38495c635efSGarrett D'Amore { 500 }, 38595c635efSGarrett D'Amore { 500 }, 38695c635efSGarrett D'Amore { 444 }, 38795c635efSGarrett D'Amore { 500 }, 38895c635efSGarrett D'Amore { 444 }, 38995c635efSGarrett D'Amore { 278 }, 39095c635efSGarrett D'Amore { 500 }, 39195c635efSGarrett D'Amore { 500 }, 39295c635efSGarrett D'Amore { 278 }, 39395c635efSGarrett D'Amore { 278 }, 39495c635efSGarrett D'Amore { 444 }, 39595c635efSGarrett D'Amore { 278 }, 39695c635efSGarrett D'Amore { 722 }, 39795c635efSGarrett D'Amore { 500 }, 39895c635efSGarrett D'Amore { 500 }, 39995c635efSGarrett D'Amore { 500 }, 40095c635efSGarrett D'Amore { 500 }, 40195c635efSGarrett D'Amore { 389 }, 40295c635efSGarrett D'Amore { 389 }, 40395c635efSGarrett D'Amore { 278 }, 40495c635efSGarrett D'Amore { 500 }, 40595c635efSGarrett D'Amore { 444 }, 40695c635efSGarrett D'Amore { 667 }, 40795c635efSGarrett D'Amore { 444 }, 40895c635efSGarrett D'Amore { 444 }, 40995c635efSGarrett D'Amore { 389 }, 41095c635efSGarrett D'Amore { 400 }, 41195c635efSGarrett D'Amore { 275 }, 41295c635efSGarrett D'Amore { 400 }, 41395c635efSGarrett D'Amore { 541 }, 41495c635efSGarrett D'Amore } }, 415260e9a87SYuri Pankov { "Times-BoldItalic", { 416260e9a87SYuri Pankov { 250 }, 417260e9a87SYuri Pankov { 389 }, 418260e9a87SYuri Pankov { 555 }, 419260e9a87SYuri Pankov { 500 }, 420260e9a87SYuri Pankov { 500 }, 421260e9a87SYuri Pankov { 833 }, 422260e9a87SYuri Pankov { 778 }, 423260e9a87SYuri Pankov { 333 }, 424260e9a87SYuri Pankov { 333 }, 425260e9a87SYuri Pankov { 333 }, 426260e9a87SYuri Pankov { 500 }, 427260e9a87SYuri Pankov { 570 }, 428260e9a87SYuri Pankov { 250 }, 429260e9a87SYuri Pankov { 333 }, 430260e9a87SYuri Pankov { 250 }, 431260e9a87SYuri Pankov { 278 }, 432260e9a87SYuri Pankov { 500 }, 433260e9a87SYuri Pankov { 500 }, 434260e9a87SYuri Pankov { 500 }, 435260e9a87SYuri Pankov { 500 }, 436260e9a87SYuri Pankov { 500 }, 437260e9a87SYuri Pankov { 500 }, 438260e9a87SYuri Pankov { 500 }, 439260e9a87SYuri Pankov { 500 }, 440260e9a87SYuri Pankov { 500 }, 441260e9a87SYuri Pankov { 500 }, 442260e9a87SYuri Pankov { 333 }, 443260e9a87SYuri Pankov { 333 }, 444260e9a87SYuri Pankov { 570 }, 445260e9a87SYuri Pankov { 570 }, 446260e9a87SYuri Pankov { 570 }, 447260e9a87SYuri Pankov { 500 }, 448260e9a87SYuri Pankov { 832 }, 449260e9a87SYuri Pankov { 667 }, 450260e9a87SYuri Pankov { 667 }, 451260e9a87SYuri Pankov { 667 }, 452260e9a87SYuri Pankov { 722 }, 453260e9a87SYuri Pankov { 667 }, 454260e9a87SYuri Pankov { 667 }, 455260e9a87SYuri Pankov { 722 }, 456260e9a87SYuri Pankov { 778 }, 457260e9a87SYuri Pankov { 389 }, 458260e9a87SYuri Pankov { 500 }, 459260e9a87SYuri Pankov { 667 }, 460260e9a87SYuri Pankov { 611 }, 461260e9a87SYuri Pankov { 889 }, 462260e9a87SYuri Pankov { 722 }, 463260e9a87SYuri Pankov { 722 }, 464260e9a87SYuri Pankov { 611 }, 465260e9a87SYuri Pankov { 722 }, 466260e9a87SYuri Pankov { 667 }, 467260e9a87SYuri Pankov { 556 }, 468260e9a87SYuri Pankov { 611 }, 469260e9a87SYuri Pankov { 722 }, 470260e9a87SYuri Pankov { 667 }, 471260e9a87SYuri Pankov { 889 }, 472260e9a87SYuri Pankov { 667 }, 473260e9a87SYuri Pankov { 611 }, 474260e9a87SYuri Pankov { 611 }, 475260e9a87SYuri Pankov { 333 }, 476260e9a87SYuri Pankov { 278 }, 477260e9a87SYuri Pankov { 333 }, 478260e9a87SYuri Pankov { 570 }, 479260e9a87SYuri Pankov { 500 }, 480260e9a87SYuri Pankov { 333 }, 481260e9a87SYuri Pankov { 500 }, 482260e9a87SYuri Pankov { 500 }, 483260e9a87SYuri Pankov { 444 }, 484260e9a87SYuri Pankov { 500 }, 485260e9a87SYuri Pankov { 444 }, 486260e9a87SYuri Pankov { 333 }, 487260e9a87SYuri Pankov { 500 }, 488260e9a87SYuri Pankov { 556 }, 489260e9a87SYuri Pankov { 278 }, 490260e9a87SYuri Pankov { 278 }, 491260e9a87SYuri Pankov { 500 }, 492260e9a87SYuri Pankov { 278 }, 493260e9a87SYuri Pankov { 778 }, 494260e9a87SYuri Pankov { 556 }, 495260e9a87SYuri Pankov { 500 }, 496260e9a87SYuri Pankov { 500 }, 497260e9a87SYuri Pankov { 500 }, 498260e9a87SYuri Pankov { 389 }, 499260e9a87SYuri Pankov { 389 }, 500260e9a87SYuri Pankov { 278 }, 501260e9a87SYuri Pankov { 556 }, 502260e9a87SYuri Pankov { 444 }, 503260e9a87SYuri Pankov { 667 }, 504260e9a87SYuri Pankov { 500 }, 505260e9a87SYuri Pankov { 444 }, 506260e9a87SYuri Pankov { 389 }, 507260e9a87SYuri Pankov { 348 }, 508260e9a87SYuri Pankov { 220 }, 509260e9a87SYuri Pankov { 348 }, 510260e9a87SYuri Pankov { 570 }, 511260e9a87SYuri Pankov } }, 51295c635efSGarrett D'Amore }; 51395c635efSGarrett D'Amore 51495c635efSGarrett D'Amore void * 515371584c2SYuri Pankov pdf_alloc(const struct manoutput *outopts) 51695c635efSGarrett D'Amore { 517*6640c13bSYuri Pankov return pspdf_alloc(outopts, TERMTYPE_PDF); 51895c635efSGarrett D'Amore } 51995c635efSGarrett D'Amore 52095c635efSGarrett D'Amore void * 521371584c2SYuri Pankov ps_alloc(const struct manoutput *outopts) 52295c635efSGarrett D'Amore { 523*6640c13bSYuri Pankov return pspdf_alloc(outopts, TERMTYPE_PS); 52495c635efSGarrett D'Amore } 52595c635efSGarrett D'Amore 52695c635efSGarrett D'Amore static struct termp * 527*6640c13bSYuri Pankov pspdf_alloc(const struct manoutput *outopts, enum termtype type) 52895c635efSGarrett D'Amore { 52995c635efSGarrett D'Amore struct termp *p; 53095c635efSGarrett D'Amore unsigned int pagex, pagey; 53195c635efSGarrett D'Amore size_t marginx, marginy, lineheight; 53295c635efSGarrett D'Amore const char *pp; 53395c635efSGarrett D'Amore 534c66b8046SYuri Pankov p = mandoc_calloc(1, sizeof(*p)); 535c66b8046SYuri Pankov p->tcol = p->tcols = mandoc_calloc(1, sizeof(*p->tcol)); 536c66b8046SYuri Pankov p->maxtcol = 1; 537*6640c13bSYuri Pankov p->type = type; 538c66b8046SYuri Pankov 53995c635efSGarrett D'Amore p->enc = TERMENC_ASCII; 540260e9a87SYuri Pankov p->fontq = mandoc_reallocarray(NULL, 541c66b8046SYuri Pankov (p->fontsz = 8), sizeof(*p->fontq)); 542260e9a87SYuri Pankov p->fontq[0] = p->fontl = TERMFONT_NONE; 543c66b8046SYuri Pankov p->ps = mandoc_calloc(1, sizeof(*p->ps)); 54495c635efSGarrett D'Amore 54595c635efSGarrett D'Amore p->advance = ps_advance; 54695c635efSGarrett D'Amore p->begin = ps_begin; 54795c635efSGarrett D'Amore p->end = ps_end; 54895c635efSGarrett D'Amore p->endline = ps_endline; 54995c635efSGarrett D'Amore p->hspan = ps_hspan; 55095c635efSGarrett D'Amore p->letter = ps_letter; 551260e9a87SYuri Pankov p->setwidth = ps_setwidth; 55295c635efSGarrett D'Amore p->width = ps_width; 55395c635efSGarrett D'Amore 55495c635efSGarrett D'Amore /* Default to US letter (millimetres). */ 55595c635efSGarrett D'Amore 556*6640c13bSYuri Pankov p->ps->medianame = "Letter"; 55795c635efSGarrett D'Amore pagex = 216; 55895c635efSGarrett D'Amore pagey = 279; 55995c635efSGarrett D'Amore 56095c635efSGarrett D'Amore /* 56195c635efSGarrett D'Amore * The ISO-269 paper sizes can be calculated automatically, but 56295c635efSGarrett D'Amore * it would require bringing in -lm for pow() and I'd rather not 56395c635efSGarrett D'Amore * do that. So just do it the easy way for now. Since this 56495c635efSGarrett D'Amore * only happens once, I'm not terribly concerned. 56595c635efSGarrett D'Amore */ 56695c635efSGarrett D'Amore 567371584c2SYuri Pankov pp = outopts->paper; 568*6640c13bSYuri Pankov if (pp != NULL && strcasecmp(pp, "letter") != 0) { 569*6640c13bSYuri Pankov if (strcasecmp(pp, "a3") == 0) { 570*6640c13bSYuri Pankov p->ps->medianame = "A3"; 57195c635efSGarrett D'Amore pagex = 297; 57295c635efSGarrett D'Amore pagey = 420; 573*6640c13bSYuri Pankov } else if (strcasecmp(pp, "a4") == 0) { 574*6640c13bSYuri Pankov p->ps->medianame = "A4"; 57595c635efSGarrett D'Amore pagex = 210; 57695c635efSGarrett D'Amore pagey = 297; 577*6640c13bSYuri Pankov } else if (strcasecmp(pp, "a5") == 0) { 578*6640c13bSYuri Pankov p->ps->medianame = "A5"; 57995c635efSGarrett D'Amore pagex = 148; 58095c635efSGarrett D'Amore pagey = 210; 581*6640c13bSYuri Pankov } else if (strcasecmp(pp, "legal") == 0) { 582*6640c13bSYuri Pankov p->ps->medianame = "Legal"; 58395c635efSGarrett D'Amore pagex = 216; 58495c635efSGarrett D'Amore pagey = 356; 585*6640c13bSYuri Pankov } else if (sscanf(pp, "%ux%u", &pagex, &pagey) == 2) 586*6640c13bSYuri Pankov p->ps->medianame = "CustomSize"; 587*6640c13bSYuri Pankov else 588371584c2SYuri Pankov warnx("%s: Unknown paper", pp); 58995c635efSGarrett D'Amore } 59095c635efSGarrett D'Amore 59195c635efSGarrett D'Amore /* 59295c635efSGarrett D'Amore * This MUST be defined before any PNT2AFM or AFM2PNT 59395c635efSGarrett D'Amore * calculations occur. 59495c635efSGarrett D'Amore */ 59595c635efSGarrett D'Amore 59695c635efSGarrett D'Amore p->ps->scale = 11; 59795c635efSGarrett D'Amore 59895c635efSGarrett D'Amore /* Remember millimetres -> AFM units. */ 59995c635efSGarrett D'Amore 600*6640c13bSYuri Pankov pagex = PNT2AFM(p, ((double)pagex * 72.0 / 25.4)); 601*6640c13bSYuri Pankov pagey = PNT2AFM(p, ((double)pagey * 72.0 / 25.4)); 60295c635efSGarrett D'Amore 60395c635efSGarrett D'Amore /* Margins are 1/9 the page x and y. */ 60495c635efSGarrett D'Amore 605260e9a87SYuri Pankov marginx = (size_t)((double)pagex / 9.0); 606260e9a87SYuri Pankov marginy = (size_t)((double)pagey / 9.0); 60795c635efSGarrett D'Amore 60895c635efSGarrett D'Amore /* Line-height is 1.4em. */ 60995c635efSGarrett D'Amore 61095c635efSGarrett D'Amore lineheight = PNT2AFM(p, ((double)p->ps->scale * 1.4)); 61195c635efSGarrett D'Amore 612260e9a87SYuri Pankov p->ps->width = p->ps->lastwidth = (size_t)pagex; 61395c635efSGarrett D'Amore p->ps->height = (size_t)pagey; 61495c635efSGarrett D'Amore p->ps->header = pagey - (marginy / 2) - (lineheight / 2); 61595c635efSGarrett D'Amore p->ps->top = pagey - marginy; 61695c635efSGarrett D'Amore p->ps->footer = (marginy / 2) - (lineheight / 2); 61795c635efSGarrett D'Amore p->ps->bottom = marginy; 61895c635efSGarrett D'Amore p->ps->left = marginx; 61995c635efSGarrett D'Amore p->ps->lineheight = lineheight; 62095c635efSGarrett D'Amore 62195c635efSGarrett D'Amore p->defrmargin = pagex - (marginx * 2); 622371584c2SYuri Pankov return p; 62395c635efSGarrett D'Amore } 62495c635efSGarrett D'Amore 625260e9a87SYuri Pankov static void 626371584c2SYuri Pankov ps_setwidth(struct termp *p, int iop, int width) 627260e9a87SYuri Pankov { 628260e9a87SYuri Pankov size_t lastwidth; 629260e9a87SYuri Pankov 630260e9a87SYuri Pankov lastwidth = p->ps->width; 631260e9a87SYuri Pankov if (iop > 0) 632260e9a87SYuri Pankov p->ps->width += width; 633260e9a87SYuri Pankov else if (iop == 0) 634371584c2SYuri Pankov p->ps->width = width ? (size_t)width : p->ps->lastwidth; 635371584c2SYuri Pankov else if (p->ps->width > (size_t)width) 636260e9a87SYuri Pankov p->ps->width -= width; 637260e9a87SYuri Pankov else 638260e9a87SYuri Pankov p->ps->width = 0; 639260e9a87SYuri Pankov p->ps->lastwidth = lastwidth; 640260e9a87SYuri Pankov } 64195c635efSGarrett D'Amore 64295c635efSGarrett D'Amore void 64395c635efSGarrett D'Amore pspdf_free(void *arg) 64495c635efSGarrett D'Amore { 64595c635efSGarrett D'Amore struct termp *p; 64695c635efSGarrett D'Amore 64795c635efSGarrett D'Amore p = (struct termp *)arg; 64895c635efSGarrett D'Amore 64995c635efSGarrett D'Amore free(p->ps->psmarg); 65095c635efSGarrett D'Amore free(p->ps->pdfobjs); 65195c635efSGarrett D'Amore 65295c635efSGarrett D'Amore free(p->ps); 65395c635efSGarrett D'Amore term_free(p); 65495c635efSGarrett D'Amore } 65595c635efSGarrett D'Amore 65695c635efSGarrett D'Amore static void 65795c635efSGarrett D'Amore ps_printf(struct termp *p, const char *fmt, ...) 65895c635efSGarrett D'Amore { 65995c635efSGarrett D'Amore va_list ap; 66095c635efSGarrett D'Amore int pos, len; 66195c635efSGarrett D'Amore 66295c635efSGarrett D'Amore va_start(ap, fmt); 66395c635efSGarrett D'Amore 66495c635efSGarrett D'Amore /* 66595c635efSGarrett D'Amore * If we're running in regular mode, then pipe directly into 66695c635efSGarrett D'Amore * vprintf(). If we're processing margins, then push the data 66795c635efSGarrett D'Amore * into our growable margin buffer. 66895c635efSGarrett D'Amore */ 66995c635efSGarrett D'Amore 67095c635efSGarrett D'Amore if ( ! (PS_MARGINS & p->ps->flags)) { 67195c635efSGarrett D'Amore len = vprintf(fmt, ap); 67295c635efSGarrett D'Amore va_end(ap); 673260e9a87SYuri Pankov p->ps->pdfbytes += len < 0 ? 0 : (size_t)len; 67495c635efSGarrett D'Amore return; 67595c635efSGarrett D'Amore } 67695c635efSGarrett D'Amore 67795c635efSGarrett D'Amore /* 67895c635efSGarrett D'Amore * XXX: I assume that the in-margin print won't exceed 67995c635efSGarrett D'Amore * PS_BUFSLOP (128 bytes), which is reasonable but still an 68095c635efSGarrett D'Amore * assumption that will cause pukeage if it's not the case. 68195c635efSGarrett D'Amore */ 68295c635efSGarrett D'Amore 68395c635efSGarrett D'Amore ps_growbuf(p, PS_BUFSLOP); 68495c635efSGarrett D'Amore 68595c635efSGarrett D'Amore pos = (int)p->ps->psmargcur; 68695c635efSGarrett D'Amore vsnprintf(&p->ps->psmarg[pos], PS_BUFSLOP, fmt, ap); 68795c635efSGarrett D'Amore 68895c635efSGarrett D'Amore va_end(ap); 68995c635efSGarrett D'Amore 69095c635efSGarrett D'Amore p->ps->psmargcur = strlen(p->ps->psmarg); 69195c635efSGarrett D'Amore } 69295c635efSGarrett D'Amore 69395c635efSGarrett D'Amore static void 69495c635efSGarrett D'Amore ps_putchar(struct termp *p, char c) 69595c635efSGarrett D'Amore { 69695c635efSGarrett D'Amore int pos; 69795c635efSGarrett D'Amore 69895c635efSGarrett D'Amore /* See ps_printf(). */ 69995c635efSGarrett D'Amore 70095c635efSGarrett D'Amore if ( ! (PS_MARGINS & p->ps->flags)) { 70195c635efSGarrett D'Amore putchar(c); 70295c635efSGarrett D'Amore p->ps->pdfbytes++; 70395c635efSGarrett D'Amore return; 70495c635efSGarrett D'Amore } 70595c635efSGarrett D'Amore 70695c635efSGarrett D'Amore ps_growbuf(p, 2); 70795c635efSGarrett D'Amore 70895c635efSGarrett D'Amore pos = (int)p->ps->psmargcur++; 70995c635efSGarrett D'Amore p->ps->psmarg[pos++] = c; 71095c635efSGarrett D'Amore p->ps->psmarg[pos] = '\0'; 71195c635efSGarrett D'Amore } 71295c635efSGarrett D'Amore 71395c635efSGarrett D'Amore static void 71495c635efSGarrett D'Amore pdf_obj(struct termp *p, size_t obj) 71595c635efSGarrett D'Amore { 71695c635efSGarrett D'Amore 71795c635efSGarrett D'Amore assert(obj > 0); 71895c635efSGarrett D'Amore 71995c635efSGarrett D'Amore if ((obj - 1) >= p->ps->pdfobjsz) { 72095c635efSGarrett D'Amore p->ps->pdfobjsz = obj + 128; 721260e9a87SYuri Pankov p->ps->pdfobjs = mandoc_reallocarray(p->ps->pdfobjs, 722260e9a87SYuri Pankov p->ps->pdfobjsz, sizeof(size_t)); 72395c635efSGarrett D'Amore } 72495c635efSGarrett D'Amore 72595c635efSGarrett D'Amore p->ps->pdfobjs[(int)obj - 1] = p->ps->pdfbytes; 72695c635efSGarrett D'Amore ps_printf(p, "%zu 0 obj\n", obj); 72795c635efSGarrett D'Amore } 72895c635efSGarrett D'Amore 72995c635efSGarrett D'Amore static void 73095c635efSGarrett D'Amore ps_closepage(struct termp *p) 73195c635efSGarrett D'Amore { 73295c635efSGarrett D'Amore int i; 73395c635efSGarrett D'Amore size_t len, base; 73495c635efSGarrett D'Amore 73595c635efSGarrett D'Amore /* 73695c635efSGarrett D'Amore * Close out a page that we've already flushed to output. In 737*6640c13bSYuri Pankov * PostScript, we simply note that the page must be shown. In 73895c635efSGarrett D'Amore * PDF, we must now create the Length, Resource, and Page node 73995c635efSGarrett D'Amore * for the page contents. 74095c635efSGarrett D'Amore */ 74195c635efSGarrett D'Amore 74295c635efSGarrett D'Amore assert(p->ps->psmarg && p->ps->psmarg[0]); 74395c635efSGarrett D'Amore ps_printf(p, "%s", p->ps->psmarg); 74495c635efSGarrett D'Amore 74595c635efSGarrett D'Amore if (TERMTYPE_PS != p->type) { 74695c635efSGarrett D'Amore len = p->ps->pdfbytes - p->ps->pdflastpg; 74795c635efSGarrett D'Amore base = p->ps->pages * 4 + p->ps->pdfbody; 74895c635efSGarrett D'Amore 74995c635efSGarrett D'Amore ps_printf(p, "endstream\nendobj\n"); 75095c635efSGarrett D'Amore 75195c635efSGarrett D'Amore /* Length of content. */ 75295c635efSGarrett D'Amore pdf_obj(p, base + 1); 75395c635efSGarrett D'Amore ps_printf(p, "%zu\nendobj\n", len); 75495c635efSGarrett D'Amore 75595c635efSGarrett D'Amore /* Resource for content. */ 75695c635efSGarrett D'Amore pdf_obj(p, base + 2); 75795c635efSGarrett D'Amore ps_printf(p, "<<\n/ProcSet [/PDF /Text]\n"); 75895c635efSGarrett D'Amore ps_printf(p, "/Font <<\n"); 75995c635efSGarrett D'Amore for (i = 0; i < (int)TERMFONT__MAX; i++) 76095c635efSGarrett D'Amore ps_printf(p, "/F%d %d 0 R\n", i, 3 + i); 761*6640c13bSYuri Pankov ps_printf(p, ">>\n>>\nendobj\n"); 76295c635efSGarrett D'Amore 76395c635efSGarrett D'Amore /* Page node. */ 76495c635efSGarrett D'Amore pdf_obj(p, base + 3); 76595c635efSGarrett D'Amore ps_printf(p, "<<\n"); 76695c635efSGarrett D'Amore ps_printf(p, "/Type /Page\n"); 76795c635efSGarrett D'Amore ps_printf(p, "/Parent 2 0 R\n"); 76895c635efSGarrett D'Amore ps_printf(p, "/Resources %zu 0 R\n", base + 2); 76995c635efSGarrett D'Amore ps_printf(p, "/Contents %zu 0 R\n", base); 77095c635efSGarrett D'Amore ps_printf(p, ">>\nendobj\n"); 77195c635efSGarrett D'Amore } else 77295c635efSGarrett D'Amore ps_printf(p, "showpage\n"); 77395c635efSGarrett D'Amore 77495c635efSGarrett D'Amore p->ps->pages++; 77595c635efSGarrett D'Amore p->ps->psrow = p->ps->top; 77695c635efSGarrett D'Amore assert( ! (PS_NEWPAGE & p->ps->flags)); 77795c635efSGarrett D'Amore p->ps->flags |= PS_NEWPAGE; 77895c635efSGarrett D'Amore } 77995c635efSGarrett D'Amore 78095c635efSGarrett D'Amore static void 78195c635efSGarrett D'Amore ps_end(struct termp *p) 78295c635efSGarrett D'Amore { 78395c635efSGarrett D'Amore size_t i, xref, base; 78495c635efSGarrett D'Amore 785a40ea1a7SYuri Pankov ps_plast(p); 786a40ea1a7SYuri Pankov ps_pclose(p); 787a40ea1a7SYuri Pankov 78895c635efSGarrett D'Amore /* 78995c635efSGarrett D'Amore * At the end of the file, do one last showpage. This is the 79095c635efSGarrett D'Amore * same behaviour as groff(1) and works for multiple pages as 79195c635efSGarrett D'Amore * well as just one. 79295c635efSGarrett D'Amore */ 79395c635efSGarrett D'Amore 79495c635efSGarrett D'Amore if ( ! (PS_NEWPAGE & p->ps->flags)) { 79595c635efSGarrett D'Amore assert(0 == p->ps->flags); 79695c635efSGarrett D'Amore assert('\0' == p->ps->last); 79795c635efSGarrett D'Amore ps_closepage(p); 79895c635efSGarrett D'Amore } 79995c635efSGarrett D'Amore 80095c635efSGarrett D'Amore if (TERMTYPE_PS == p->type) { 80195c635efSGarrett D'Amore ps_printf(p, "%%%%Trailer\n"); 80295c635efSGarrett D'Amore ps_printf(p, "%%%%Pages: %zu\n", p->ps->pages); 80395c635efSGarrett D'Amore ps_printf(p, "%%%%EOF\n"); 80495c635efSGarrett D'Amore return; 80595c635efSGarrett D'Amore } 80695c635efSGarrett D'Amore 80795c635efSGarrett D'Amore pdf_obj(p, 2); 80895c635efSGarrett D'Amore ps_printf(p, "<<\n/Type /Pages\n"); 80995c635efSGarrett D'Amore ps_printf(p, "/MediaBox [0 0 %zu %zu]\n", 81095c635efSGarrett D'Amore (size_t)AFM2PNT(p, p->ps->width), 81195c635efSGarrett D'Amore (size_t)AFM2PNT(p, p->ps->height)); 81295c635efSGarrett D'Amore 81395c635efSGarrett D'Amore ps_printf(p, "/Count %zu\n", p->ps->pages); 81495c635efSGarrett D'Amore ps_printf(p, "/Kids ["); 81595c635efSGarrett D'Amore 81695c635efSGarrett D'Amore for (i = 0; i < p->ps->pages; i++) 817260e9a87SYuri Pankov ps_printf(p, " %zu 0 R", i * 4 + p->ps->pdfbody + 3); 81895c635efSGarrett D'Amore 819260e9a87SYuri Pankov base = (p->ps->pages - 1) * 4 + p->ps->pdfbody + 4; 82095c635efSGarrett D'Amore 82195c635efSGarrett D'Amore ps_printf(p, "]\n>>\nendobj\n"); 82295c635efSGarrett D'Amore pdf_obj(p, base); 82395c635efSGarrett D'Amore ps_printf(p, "<<\n"); 82495c635efSGarrett D'Amore ps_printf(p, "/Type /Catalog\n"); 82595c635efSGarrett D'Amore ps_printf(p, "/Pages 2 0 R\n"); 826*6640c13bSYuri Pankov ps_printf(p, ">>\nendobj\n"); 82795c635efSGarrett D'Amore xref = p->ps->pdfbytes; 82895c635efSGarrett D'Amore ps_printf(p, "xref\n"); 82995c635efSGarrett D'Amore ps_printf(p, "0 %zu\n", base + 1); 83095c635efSGarrett D'Amore ps_printf(p, "0000000000 65535 f \n"); 83195c635efSGarrett D'Amore 83295c635efSGarrett D'Amore for (i = 0; i < base; i++) 83395c635efSGarrett D'Amore ps_printf(p, "%.10zu 00000 n \n", 83495c635efSGarrett D'Amore p->ps->pdfobjs[(int)i]); 83595c635efSGarrett D'Amore 83695c635efSGarrett D'Amore ps_printf(p, "trailer\n"); 83795c635efSGarrett D'Amore ps_printf(p, "<<\n"); 83895c635efSGarrett D'Amore ps_printf(p, "/Size %zu\n", base + 1); 83995c635efSGarrett D'Amore ps_printf(p, "/Root %zu 0 R\n", base); 84095c635efSGarrett D'Amore ps_printf(p, "/Info 1 0 R\n"); 84195c635efSGarrett D'Amore ps_printf(p, ">>\n"); 84295c635efSGarrett D'Amore ps_printf(p, "startxref\n"); 84395c635efSGarrett D'Amore ps_printf(p, "%zu\n", xref); 84495c635efSGarrett D'Amore ps_printf(p, "%%%%EOF\n"); 84595c635efSGarrett D'Amore } 84695c635efSGarrett D'Amore 84795c635efSGarrett D'Amore static void 84895c635efSGarrett D'Amore ps_begin(struct termp *p) 84995c635efSGarrett D'Amore { 850*6640c13bSYuri Pankov size_t width, height; 85195c635efSGarrett D'Amore int i; 85295c635efSGarrett D'Amore 85395c635efSGarrett D'Amore /* 85495c635efSGarrett D'Amore * Print margins into margin buffer. Nothing gets output to the 85595c635efSGarrett D'Amore * screen yet, so we don't need to initialise the primary state. 85695c635efSGarrett D'Amore */ 85795c635efSGarrett D'Amore 85895c635efSGarrett D'Amore if (p->ps->psmarg) { 85995c635efSGarrett D'Amore assert(p->ps->psmargsz); 86095c635efSGarrett D'Amore p->ps->psmarg[0] = '\0'; 86195c635efSGarrett D'Amore } 86295c635efSGarrett D'Amore 86395c635efSGarrett D'Amore /*p->ps->pdfbytes = 0;*/ 86495c635efSGarrett D'Amore p->ps->psmargcur = 0; 86595c635efSGarrett D'Amore p->ps->flags = PS_MARGINS; 86695c635efSGarrett D'Amore p->ps->pscol = p->ps->left; 86795c635efSGarrett D'Amore p->ps->psrow = p->ps->header; 868*6640c13bSYuri Pankov p->ps->lastrow = 0; /* impossible row */ 86995c635efSGarrett D'Amore 87095c635efSGarrett D'Amore ps_setfont(p, TERMFONT_NONE); 87195c635efSGarrett D'Amore 87295c635efSGarrett D'Amore (*p->headf)(p, p->argf); 87395c635efSGarrett D'Amore (*p->endline)(p); 87495c635efSGarrett D'Amore 87595c635efSGarrett D'Amore p->ps->pscol = p->ps->left; 87695c635efSGarrett D'Amore p->ps->psrow = p->ps->footer; 87795c635efSGarrett D'Amore 87895c635efSGarrett D'Amore (*p->footf)(p, p->argf); 87995c635efSGarrett D'Amore (*p->endline)(p); 88095c635efSGarrett D'Amore 88195c635efSGarrett D'Amore p->ps->flags &= ~PS_MARGINS; 88295c635efSGarrett D'Amore 88395c635efSGarrett D'Amore assert(0 == p->ps->flags); 88495c635efSGarrett D'Amore assert(p->ps->psmarg); 88595c635efSGarrett D'Amore assert('\0' != p->ps->psmarg[0]); 88695c635efSGarrett D'Amore 88795c635efSGarrett D'Amore /* 88895c635efSGarrett D'Amore * Print header and initialise page state. Following this, 88995c635efSGarrett D'Amore * stuff gets printed to the screen, so make sure we're sane. 89095c635efSGarrett D'Amore */ 89195c635efSGarrett D'Amore 89295c635efSGarrett D'Amore if (TERMTYPE_PS == p->type) { 893*6640c13bSYuri Pankov width = AFM2PNT(p, p->ps->width); 894*6640c13bSYuri Pankov height = AFM2PNT(p, p->ps->height); 895*6640c13bSYuri Pankov 89695c635efSGarrett D'Amore ps_printf(p, "%%!PS-Adobe-3.0\n"); 89795c635efSGarrett D'Amore ps_printf(p, "%%%%DocumentData: Clean7Bit\n"); 89895c635efSGarrett D'Amore ps_printf(p, "%%%%Orientation: Portrait\n"); 89995c635efSGarrett D'Amore ps_printf(p, "%%%%Pages: (atend)\n"); 90095c635efSGarrett D'Amore ps_printf(p, "%%%%PageOrder: Ascend\n"); 901*6640c13bSYuri Pankov ps_printf(p, "%%%%DocumentMedia: man-%s %zu %zu 0 () ()\n", 902*6640c13bSYuri Pankov p->ps->medianame, width, height); 90395c635efSGarrett D'Amore ps_printf(p, "%%%%DocumentNeededResources: font"); 90495c635efSGarrett D'Amore 90595c635efSGarrett D'Amore for (i = 0; i < (int)TERMFONT__MAX; i++) 90695c635efSGarrett D'Amore ps_printf(p, " %s", fonts[i].name); 90795c635efSGarrett D'Amore 908*6640c13bSYuri Pankov ps_printf(p, "\n%%%%DocumentSuppliedResources: " 909*6640c13bSYuri Pankov "procset MandocProcs 1.0 0\n"); 910*6640c13bSYuri Pankov ps_printf(p, "%%%%EndComments\n"); 911*6640c13bSYuri Pankov ps_printf(p, "%%%%BeginProlog\n"); 912*6640c13bSYuri Pankov ps_printf(p, "%%%%BeginResource: procset MandocProcs " 913*6640c13bSYuri Pankov "10170 10170\n"); 914*6640c13bSYuri Pankov /* The font size is effectively hard-coded for now. */ 915*6640c13bSYuri Pankov ps_printf(p, "/fs %zu def\n", p->ps->scale); 916*6640c13bSYuri Pankov for (i = 0; i < (int)TERMFONT__MAX; i++) 917*6640c13bSYuri Pankov ps_printf(p, "/f%d { /%s fs selectfont } def\n", 918*6640c13bSYuri Pankov i, fonts[i].name); 919*6640c13bSYuri Pankov ps_printf(p, "/s { 3 1 roll moveto show } bind def\n"); 920*6640c13bSYuri Pankov ps_printf(p, "/c { exch currentpoint exch pop " 921*6640c13bSYuri Pankov "moveto show } bind def\n"); 922*6640c13bSYuri Pankov ps_printf(p, "%%%%EndResource\n"); 923*6640c13bSYuri Pankov ps_printf(p, "%%%%EndProlog\n"); 924*6640c13bSYuri Pankov ps_printf(p, "%%%%BeginSetup\n"); 925*6640c13bSYuri Pankov ps_printf(p, "%%%%BeginFeature: *PageSize %s\n", 926*6640c13bSYuri Pankov p->ps->medianame); 927*6640c13bSYuri Pankov ps_printf(p, "<</PageSize [%zu %zu]>>setpagedevice\n", 928*6640c13bSYuri Pankov width, height); 929*6640c13bSYuri Pankov ps_printf(p, "%%%%EndFeature\n"); 930*6640c13bSYuri Pankov ps_printf(p, "%%%%EndSetup\n"); 93195c635efSGarrett D'Amore } else { 93295c635efSGarrett D'Amore ps_printf(p, "%%PDF-1.1\n"); 93395c635efSGarrett D'Amore pdf_obj(p, 1); 93495c635efSGarrett D'Amore ps_printf(p, "<<\n"); 93595c635efSGarrett D'Amore ps_printf(p, ">>\n"); 93695c635efSGarrett D'Amore ps_printf(p, "endobj\n"); 93795c635efSGarrett D'Amore 93895c635efSGarrett D'Amore for (i = 0; i < (int)TERMFONT__MAX; i++) { 93995c635efSGarrett D'Amore pdf_obj(p, (size_t)i + 3); 94095c635efSGarrett D'Amore ps_printf(p, "<<\n"); 94195c635efSGarrett D'Amore ps_printf(p, "/Type /Font\n"); 94295c635efSGarrett D'Amore ps_printf(p, "/Subtype /Type1\n"); 943260e9a87SYuri Pankov ps_printf(p, "/Name /F%d\n", i); 94495c635efSGarrett D'Amore ps_printf(p, "/BaseFont /%s\n", fonts[i].name); 945*6640c13bSYuri Pankov ps_printf(p, ">>\nendobj\n"); 94695c635efSGarrett D'Amore } 94795c635efSGarrett D'Amore } 94895c635efSGarrett D'Amore 94995c635efSGarrett D'Amore p->ps->pdfbody = (size_t)TERMFONT__MAX + 3; 95095c635efSGarrett D'Amore p->ps->pscol = p->ps->left; 95195c635efSGarrett D'Amore p->ps->psrow = p->ps->top; 95295c635efSGarrett D'Amore p->ps->flags |= PS_NEWPAGE; 95395c635efSGarrett D'Amore ps_setfont(p, TERMFONT_NONE); 95495c635efSGarrett D'Amore } 95595c635efSGarrett D'Amore 95695c635efSGarrett D'Amore static void 95795c635efSGarrett D'Amore ps_pletter(struct termp *p, int c) 95895c635efSGarrett D'Amore { 95995c635efSGarrett D'Amore int f; 96095c635efSGarrett D'Amore 96195c635efSGarrett D'Amore /* 96295c635efSGarrett D'Amore * If we haven't opened a page context, then output that we're 96395c635efSGarrett D'Amore * in a new page and make sure the font is correctly set. 96495c635efSGarrett D'Amore */ 96595c635efSGarrett D'Amore 96695c635efSGarrett D'Amore if (PS_NEWPAGE & p->ps->flags) { 96795c635efSGarrett D'Amore if (TERMTYPE_PS == p->type) { 96895c635efSGarrett D'Amore ps_printf(p, "%%%%Page: %zu %zu\n", 969260e9a87SYuri Pankov p->ps->pages + 1, p->ps->pages + 1); 970*6640c13bSYuri Pankov ps_printf(p, "f%d\n", (int)p->ps->lastf); 97195c635efSGarrett D'Amore } else { 97295c635efSGarrett D'Amore pdf_obj(p, p->ps->pdfbody + 97395c635efSGarrett D'Amore p->ps->pages * 4); 97495c635efSGarrett D'Amore ps_printf(p, "<<\n"); 97595c635efSGarrett D'Amore ps_printf(p, "/Length %zu 0 R\n", 976260e9a87SYuri Pankov p->ps->pdfbody + 1 + p->ps->pages * 4); 97795c635efSGarrett D'Amore ps_printf(p, ">>\nstream\n"); 97895c635efSGarrett D'Amore } 97995c635efSGarrett D'Amore p->ps->pdflastpg = p->ps->pdfbytes; 98095c635efSGarrett D'Amore p->ps->flags &= ~PS_NEWPAGE; 98195c635efSGarrett D'Amore } 98295c635efSGarrett D'Amore 98395c635efSGarrett D'Amore /* 98495c635efSGarrett D'Amore * If we're not in a PostScript "word" context, then open one 98595c635efSGarrett D'Amore * now at the current cursor. 98695c635efSGarrett D'Amore */ 98795c635efSGarrett D'Amore 98895c635efSGarrett D'Amore if ( ! (PS_INLINE & p->ps->flags)) { 98995c635efSGarrett D'Amore if (TERMTYPE_PS != p->type) { 99095c635efSGarrett D'Amore ps_printf(p, "BT\n/F%d %zu Tf\n", 991260e9a87SYuri Pankov (int)p->ps->lastf, p->ps->scale); 99295c635efSGarrett D'Amore ps_printf(p, "%.3f %.3f Td\n(", 99395c635efSGarrett D'Amore AFM2PNT(p, p->ps->pscol), 99495c635efSGarrett D'Amore AFM2PNT(p, p->ps->psrow)); 995*6640c13bSYuri Pankov } else { 996*6640c13bSYuri Pankov ps_printf(p, "%.3f", AFM2PNT(p, p->ps->pscol)); 997*6640c13bSYuri Pankov if (p->ps->psrow != p->ps->lastrow) 998*6640c13bSYuri Pankov ps_printf(p, " %.3f", 99995c635efSGarrett D'Amore AFM2PNT(p, p->ps->psrow)); 1000*6640c13bSYuri Pankov ps_printf(p, "("); 1001*6640c13bSYuri Pankov } 100295c635efSGarrett D'Amore p->ps->flags |= PS_INLINE; 100395c635efSGarrett D'Amore } 100495c635efSGarrett D'Amore 100595c635efSGarrett D'Amore assert( ! (PS_NEWPAGE & p->ps->flags)); 100695c635efSGarrett D'Amore 100795c635efSGarrett D'Amore /* 100895c635efSGarrett D'Amore * We need to escape these characters as per the PostScript 100995c635efSGarrett D'Amore * specification. We would also escape non-graphable characters 101095c635efSGarrett D'Amore * (like tabs), but none of them would get to this point and 101195c635efSGarrett D'Amore * it's superfluous to abort() on them. 101295c635efSGarrett D'Amore */ 101395c635efSGarrett D'Amore 101495c635efSGarrett D'Amore switch (c) { 1015260e9a87SYuri Pankov case '(': 1016260e9a87SYuri Pankov case ')': 1017260e9a87SYuri Pankov case '\\': 101895c635efSGarrett D'Amore ps_putchar(p, '\\'); 101995c635efSGarrett D'Amore break; 102095c635efSGarrett D'Amore default: 102195c635efSGarrett D'Amore break; 102295c635efSGarrett D'Amore } 102395c635efSGarrett D'Amore 102495c635efSGarrett D'Amore /* Write the character and adjust where we are on the page. */ 102595c635efSGarrett D'Amore 102695c635efSGarrett D'Amore f = (int)p->ps->lastf; 102795c635efSGarrett D'Amore 1028260e9a87SYuri Pankov if (c <= 32 || c - 32 >= MAXCHAR) 1029260e9a87SYuri Pankov c = 32; 103095c635efSGarrett D'Amore 103195c635efSGarrett D'Amore ps_putchar(p, (char)c); 103295c635efSGarrett D'Amore c -= 32; 103395c635efSGarrett D'Amore p->ps->pscol += (size_t)fonts[f].gly[c].wx; 103495c635efSGarrett D'Amore } 103595c635efSGarrett D'Amore 103695c635efSGarrett D'Amore static void 103795c635efSGarrett D'Amore ps_pclose(struct termp *p) 103895c635efSGarrett D'Amore { 103995c635efSGarrett D'Amore 104095c635efSGarrett D'Amore /* 104195c635efSGarrett D'Amore * Spit out that we're exiting a word context (this is a 104295c635efSGarrett D'Amore * "partial close" because we don't check the last-char buffer 104395c635efSGarrett D'Amore * or anything). 104495c635efSGarrett D'Amore */ 104595c635efSGarrett D'Amore 104695c635efSGarrett D'Amore if ( ! (PS_INLINE & p->ps->flags)) 104795c635efSGarrett D'Amore return; 104895c635efSGarrett D'Amore 1049*6640c13bSYuri Pankov if (TERMTYPE_PS != p->type) 105095c635efSGarrett D'Amore ps_printf(p, ") Tj\nET\n"); 1051*6640c13bSYuri Pankov else if (p->ps->psrow == p->ps->lastrow) 1052*6640c13bSYuri Pankov ps_printf(p, ")c\n"); 1053*6640c13bSYuri Pankov else { 1054*6640c13bSYuri Pankov ps_printf(p, ")s\n"); 1055*6640c13bSYuri Pankov p->ps->lastrow = p->ps->psrow; 1056*6640c13bSYuri Pankov } 105795c635efSGarrett D'Amore 105895c635efSGarrett D'Amore p->ps->flags &= ~PS_INLINE; 105995c635efSGarrett D'Amore } 106095c635efSGarrett D'Amore 1061a40ea1a7SYuri Pankov /* If we have a `last' char that wasn't printed yet, print it now. */ 106295c635efSGarrett D'Amore static void 1063a40ea1a7SYuri Pankov ps_plast(struct termp *p) 106495c635efSGarrett D'Amore { 1065a40ea1a7SYuri Pankov size_t wx; 106695c635efSGarrett D'Amore 1067a40ea1a7SYuri Pankov if (p->ps->last == '\0') 1068a40ea1a7SYuri Pankov return; 106995c635efSGarrett D'Amore 1070a40ea1a7SYuri Pankov /* Check the font mode; open a new scope if it doesn't match. */ 1071a40ea1a7SYuri Pankov 1072260e9a87SYuri Pankov if (p->ps->nextf != p->ps->lastf) { 107395c635efSGarrett D'Amore ps_pclose(p); 1074260e9a87SYuri Pankov ps_setfont(p, p->ps->nextf); 107595c635efSGarrett D'Amore } 1076260e9a87SYuri Pankov p->ps->nextf = TERMFONT_NONE; 1077a40ea1a7SYuri Pankov 1078a40ea1a7SYuri Pankov /* 1079a40ea1a7SYuri Pankov * For an overstrike, if a previous character 1080a40ea1a7SYuri Pankov * was wider, advance to center the new one. 1081a40ea1a7SYuri Pankov */ 1082a40ea1a7SYuri Pankov 1083a40ea1a7SYuri Pankov if (p->ps->pscolnext) { 1084a40ea1a7SYuri Pankov wx = fonts[p->ps->lastf].gly[(int)p->ps->last-32].wx; 1085a40ea1a7SYuri Pankov if (p->ps->pscol + wx < p->ps->pscolnext) 1086a40ea1a7SYuri Pankov p->ps->pscol = (p->ps->pscol + 1087a40ea1a7SYuri Pankov p->ps->pscolnext - wx) / 2; 108895c635efSGarrett D'Amore } 108995c635efSGarrett D'Amore 1090a40ea1a7SYuri Pankov ps_pletter(p, p->ps->last); 1091a40ea1a7SYuri Pankov p->ps->last = '\0'; 109295c635efSGarrett D'Amore 1093a40ea1a7SYuri Pankov /* 1094a40ea1a7SYuri Pankov * For an overstrike, if a previous character 1095a40ea1a7SYuri Pankov * was wider, advance to the end of the old one. 1096a40ea1a7SYuri Pankov */ 1097a40ea1a7SYuri Pankov 1098a40ea1a7SYuri Pankov if (p->ps->pscol < p->ps->pscolnext) { 109995c635efSGarrett D'Amore ps_pclose(p); 1100a40ea1a7SYuri Pankov p->ps->pscol = p->ps->pscolnext; 1101a40ea1a7SYuri Pankov } 110295c635efSGarrett D'Amore } 110395c635efSGarrett D'Amore 110495c635efSGarrett D'Amore static void 110595c635efSGarrett D'Amore ps_letter(struct termp *p, int arg) 110695c635efSGarrett D'Amore { 1107a40ea1a7SYuri Pankov size_t savecol; 1108260e9a87SYuri Pankov char c; 110995c635efSGarrett D'Amore 111095c635efSGarrett D'Amore c = arg >= 128 || arg <= 0 ? '?' : arg; 111195c635efSGarrett D'Amore 111295c635efSGarrett D'Amore /* 1113260e9a87SYuri Pankov * When receiving a backspace, merely flag it. 1114260e9a87SYuri Pankov * We don't know yet whether it is 1115260e9a87SYuri Pankov * a font instruction or an overstrike. 111695c635efSGarrett D'Amore */ 111795c635efSGarrett D'Amore 1118260e9a87SYuri Pankov if (c == '\b') { 1119260e9a87SYuri Pankov assert(p->ps->last != '\0'); 1120260e9a87SYuri Pankov assert( ! (p->ps->flags & PS_BACKSP)); 1121260e9a87SYuri Pankov p->ps->flags |= PS_BACKSP; 112295c635efSGarrett D'Amore return; 112395c635efSGarrett D'Amore } 112495c635efSGarrett D'Amore 1125260e9a87SYuri Pankov /* 1126260e9a87SYuri Pankov * Decode font instructions. 1127260e9a87SYuri Pankov */ 1128260e9a87SYuri Pankov 1129260e9a87SYuri Pankov if (p->ps->flags & PS_BACKSP) { 1130260e9a87SYuri Pankov if (p->ps->last == '_') { 1131260e9a87SYuri Pankov switch (p->ps->nextf) { 1132260e9a87SYuri Pankov case TERMFONT_BI: 1133260e9a87SYuri Pankov break; 1134260e9a87SYuri Pankov case TERMFONT_BOLD: 1135260e9a87SYuri Pankov p->ps->nextf = TERMFONT_BI; 1136260e9a87SYuri Pankov break; 1137260e9a87SYuri Pankov default: 1138260e9a87SYuri Pankov p->ps->nextf = TERMFONT_UNDER; 1139260e9a87SYuri Pankov } 1140260e9a87SYuri Pankov p->ps->last = c; 1141260e9a87SYuri Pankov p->ps->flags &= ~PS_BACKSP; 1142260e9a87SYuri Pankov return; 1143260e9a87SYuri Pankov } 1144260e9a87SYuri Pankov if (p->ps->last == c) { 1145260e9a87SYuri Pankov switch (p->ps->nextf) { 1146260e9a87SYuri Pankov case TERMFONT_BI: 1147260e9a87SYuri Pankov break; 1148260e9a87SYuri Pankov case TERMFONT_UNDER: 1149260e9a87SYuri Pankov p->ps->nextf = TERMFONT_BI; 1150260e9a87SYuri Pankov break; 1151260e9a87SYuri Pankov default: 1152260e9a87SYuri Pankov p->ps->nextf = TERMFONT_BOLD; 1153260e9a87SYuri Pankov } 1154260e9a87SYuri Pankov p->ps->flags &= ~PS_BACKSP; 1155260e9a87SYuri Pankov return; 115695c635efSGarrett D'Amore } 115795c635efSGarrett D'Amore 1158260e9a87SYuri Pankov /* 1159260e9a87SYuri Pankov * This is not a font instruction, but rather 1160260e9a87SYuri Pankov * the next character. Prepare for overstrike. 1161260e9a87SYuri Pankov */ 1162260e9a87SYuri Pankov 1163260e9a87SYuri Pankov savecol = p->ps->pscol; 1164260e9a87SYuri Pankov } else 1165260e9a87SYuri Pankov savecol = SIZE_MAX; 1166260e9a87SYuri Pankov 1167260e9a87SYuri Pankov /* 1168260e9a87SYuri Pankov * We found the next character, so the font instructions 1169260e9a87SYuri Pankov * for the previous one are complete. 1170260e9a87SYuri Pankov * Use them and print it. 1171260e9a87SYuri Pankov */ 1172260e9a87SYuri Pankov 1173a40ea1a7SYuri Pankov ps_plast(p); 1174260e9a87SYuri Pankov 1175260e9a87SYuri Pankov /* 1176260e9a87SYuri Pankov * Do not print the current character yet because font 1177a40ea1a7SYuri Pankov * instructions might follow; only remember the character. 1178a40ea1a7SYuri Pankov * It will get printed later from ps_plast(). 1179260e9a87SYuri Pankov */ 1180260e9a87SYuri Pankov 1181260e9a87SYuri Pankov p->ps->last = c; 1182260e9a87SYuri Pankov 1183260e9a87SYuri Pankov /* 1184260e9a87SYuri Pankov * For an overstrike, back up to the previous position. 1185260e9a87SYuri Pankov * If the previous character is wider than any it overstrikes, 1186260e9a87SYuri Pankov * remember the current position, because it might also be 1187260e9a87SYuri Pankov * wider than all that will overstrike it. 1188260e9a87SYuri Pankov */ 1189260e9a87SYuri Pankov 1190260e9a87SYuri Pankov if (savecol != SIZE_MAX) { 1191260e9a87SYuri Pankov if (p->ps->pscolnext < p->ps->pscol) 1192260e9a87SYuri Pankov p->ps->pscolnext = p->ps->pscol; 1193260e9a87SYuri Pankov ps_pclose(p); 1194260e9a87SYuri Pankov p->ps->pscol = savecol; 1195260e9a87SYuri Pankov p->ps->flags &= ~PS_BACKSP; 1196260e9a87SYuri Pankov } else 1197260e9a87SYuri Pankov p->ps->pscolnext = 0; 1198260e9a87SYuri Pankov } 119995c635efSGarrett D'Amore 120095c635efSGarrett D'Amore static void 120195c635efSGarrett D'Amore ps_advance(struct termp *p, size_t len) 120295c635efSGarrett D'Amore { 120395c635efSGarrett D'Amore 120495c635efSGarrett D'Amore /* 120595c635efSGarrett D'Amore * Advance some spaces. This can probably be made smarter, 120695c635efSGarrett D'Amore * i.e., to have multiple space-separated words in the same 120795c635efSGarrett D'Amore * scope, but this is easier: just close out the current scope 120895c635efSGarrett D'Amore * and readjust our column settings. 120995c635efSGarrett D'Amore */ 121095c635efSGarrett D'Amore 1211a40ea1a7SYuri Pankov ps_plast(p); 1212a40ea1a7SYuri Pankov ps_pclose(p); 121395c635efSGarrett D'Amore p->ps->pscol += len; 121495c635efSGarrett D'Amore } 121595c635efSGarrett D'Amore 121695c635efSGarrett D'Amore static void 121795c635efSGarrett D'Amore ps_endline(struct termp *p) 121895c635efSGarrett D'Amore { 121995c635efSGarrett D'Amore 122095c635efSGarrett D'Amore /* Close out any scopes we have open: we're at eoln. */ 122195c635efSGarrett D'Amore 1222a40ea1a7SYuri Pankov ps_plast(p); 1223a40ea1a7SYuri Pankov ps_pclose(p); 122495c635efSGarrett D'Amore 122595c635efSGarrett D'Amore /* 122695c635efSGarrett D'Amore * If we're in the margin, don't try to recalculate our current 122795c635efSGarrett D'Amore * row. XXX: if the column tries to be fancy with multiple 122895c635efSGarrett D'Amore * lines, we'll do nasty stuff. 122995c635efSGarrett D'Amore */ 123095c635efSGarrett D'Amore 123195c635efSGarrett D'Amore if (PS_MARGINS & p->ps->flags) 123295c635efSGarrett D'Amore return; 123395c635efSGarrett D'Amore 123495c635efSGarrett D'Amore /* Left-justify. */ 123595c635efSGarrett D'Amore 123695c635efSGarrett D'Amore p->ps->pscol = p->ps->left; 123795c635efSGarrett D'Amore 123895c635efSGarrett D'Amore /* If we haven't printed anything, return. */ 123995c635efSGarrett D'Amore 124095c635efSGarrett D'Amore if (PS_NEWPAGE & p->ps->flags) 124195c635efSGarrett D'Amore return; 124295c635efSGarrett D'Amore 124395c635efSGarrett D'Amore /* 124495c635efSGarrett D'Amore * Put us down a line. If we're at the page bottom, spit out a 124595c635efSGarrett D'Amore * showpage and restart our row. 124695c635efSGarrett D'Amore */ 124795c635efSGarrett D'Amore 1248260e9a87SYuri Pankov if (p->ps->psrow >= p->ps->lineheight + p->ps->bottom) { 124995c635efSGarrett D'Amore p->ps->psrow -= p->ps->lineheight; 125095c635efSGarrett D'Amore return; 125195c635efSGarrett D'Amore } 125295c635efSGarrett D'Amore 125395c635efSGarrett D'Amore ps_closepage(p); 1254c66b8046SYuri Pankov 1255c66b8046SYuri Pankov p->tcol->offset -= p->ti; 1256c66b8046SYuri Pankov p->ti = 0; 125795c635efSGarrett D'Amore } 125895c635efSGarrett D'Amore 125995c635efSGarrett D'Amore static void 126095c635efSGarrett D'Amore ps_setfont(struct termp *p, enum termfont f) 126195c635efSGarrett D'Amore { 126295c635efSGarrett D'Amore 126395c635efSGarrett D'Amore assert(f < TERMFONT__MAX); 126495c635efSGarrett D'Amore p->ps->lastf = f; 126595c635efSGarrett D'Amore 126695c635efSGarrett D'Amore /* 126795c635efSGarrett D'Amore * If we're still at the top of the page, let the font-setting 126895c635efSGarrett D'Amore * be delayed until we actually have stuff to print. 126995c635efSGarrett D'Amore */ 127095c635efSGarrett D'Amore 127195c635efSGarrett D'Amore if (PS_NEWPAGE & p->ps->flags) 127295c635efSGarrett D'Amore return; 127395c635efSGarrett D'Amore 127495c635efSGarrett D'Amore if (TERMTYPE_PS == p->type) 1275*6640c13bSYuri Pankov ps_printf(p, "f%d\n", (int)f); 127695c635efSGarrett D'Amore else 127795c635efSGarrett D'Amore ps_printf(p, "/F%d %zu Tf\n", 1278260e9a87SYuri Pankov (int)f, p->ps->scale); 127995c635efSGarrett D'Amore } 128095c635efSGarrett D'Amore 128195c635efSGarrett D'Amore static size_t 128295c635efSGarrett D'Amore ps_width(const struct termp *p, int c) 128395c635efSGarrett D'Amore { 128495c635efSGarrett D'Amore 128595c635efSGarrett D'Amore if (c <= 32 || c - 32 >= MAXCHAR) 1286260e9a87SYuri Pankov c = 0; 1287260e9a87SYuri Pankov else 128895c635efSGarrett D'Amore c -= 32; 1289260e9a87SYuri Pankov 1290371584c2SYuri Pankov return (size_t)fonts[(int)TERMFONT_NONE].gly[c].wx; 129195c635efSGarrett D'Amore } 129295c635efSGarrett D'Amore 1293371584c2SYuri Pankov static int 129495c635efSGarrett D'Amore ps_hspan(const struct termp *p, const struct roffsu *su) 129595c635efSGarrett D'Amore { 129695c635efSGarrett D'Amore double r; 129795c635efSGarrett D'Amore 129895c635efSGarrett D'Amore /* 129995c635efSGarrett D'Amore * All of these measurements are derived by converting from the 130095c635efSGarrett D'Amore * native measurement to AFM units. 130195c635efSGarrett D'Amore */ 130295c635efSGarrett D'Amore switch (su->unit) { 1303260e9a87SYuri Pankov case SCALE_BU: 1304260e9a87SYuri Pankov /* 1305260e9a87SYuri Pankov * Traditionally, the default unit is fixed to the 1306260e9a87SYuri Pankov * output media. So this would refer to the point. In 1307260e9a87SYuri Pankov * mandoc(1), however, we stick to the default terminal 1308260e9a87SYuri Pankov * scaling unit so that output is the same regardless 1309260e9a87SYuri Pankov * the media. 1310260e9a87SYuri Pankov */ 1311260e9a87SYuri Pankov r = PNT2AFM(p, su->scale * 72.0 / 240.0); 131295c635efSGarrett D'Amore break; 1313260e9a87SYuri Pankov case SCALE_CM: 1314260e9a87SYuri Pankov r = PNT2AFM(p, su->scale * 72.0 / 2.54); 131595c635efSGarrett D'Amore break; 1316260e9a87SYuri Pankov case SCALE_EM: 131795c635efSGarrett D'Amore r = su->scale * 131895c635efSGarrett D'Amore fonts[(int)TERMFONT_NONE].gly[109 - 32].wx; 131995c635efSGarrett D'Amore break; 1320260e9a87SYuri Pankov case SCALE_EN: 132195c635efSGarrett D'Amore r = su->scale * 132295c635efSGarrett D'Amore fonts[(int)TERMFONT_NONE].gly[110 - 32].wx; 132395c635efSGarrett D'Amore break; 1324260e9a87SYuri Pankov case SCALE_IN: 1325260e9a87SYuri Pankov r = PNT2AFM(p, su->scale * 72.0); 1326260e9a87SYuri Pankov break; 1327260e9a87SYuri Pankov case SCALE_MM: 1328260e9a87SYuri Pankov r = su->scale * 1329260e9a87SYuri Pankov fonts[(int)TERMFONT_NONE].gly[109 - 32].wx / 100.0; 1330260e9a87SYuri Pankov break; 1331260e9a87SYuri Pankov case SCALE_PC: 1332260e9a87SYuri Pankov r = PNT2AFM(p, su->scale * 12.0); 1333260e9a87SYuri Pankov break; 1334260e9a87SYuri Pankov case SCALE_PT: 1335260e9a87SYuri Pankov r = PNT2AFM(p, su->scale * 1.0); 1336260e9a87SYuri Pankov break; 1337260e9a87SYuri Pankov case SCALE_VS: 133895c635efSGarrett D'Amore r = su->scale * p->ps->lineheight; 133995c635efSGarrett D'Amore break; 134095c635efSGarrett D'Amore default: 134195c635efSGarrett D'Amore r = su->scale; 134295c635efSGarrett D'Amore break; 134395c635efSGarrett D'Amore } 134495c635efSGarrett D'Amore 1345371584c2SYuri Pankov return r * 24.0; 134695c635efSGarrett D'Amore } 134795c635efSGarrett D'Amore 134895c635efSGarrett D'Amore static void 134995c635efSGarrett D'Amore ps_growbuf(struct termp *p, size_t sz) 135095c635efSGarrett D'Amore { 135195c635efSGarrett D'Amore if (p->ps->psmargcur + sz <= p->ps->psmargsz) 135295c635efSGarrett D'Amore return; 135395c635efSGarrett D'Amore 135495c635efSGarrett D'Amore if (sz < PS_BUFSLOP) 135595c635efSGarrett D'Amore sz = PS_BUFSLOP; 135695c635efSGarrett D'Amore 135795c635efSGarrett D'Amore p->ps->psmargsz += sz; 1358260e9a87SYuri Pankov p->ps->psmarg = mandoc_realloc(p->ps->psmarg, p->ps->psmargsz); 135995c635efSGarrett D'Amore } 1360