1*371584c2SYuri Pankov /* $Id: term_ps.c,v 1.80 2015/12/23 20:50:13 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 395c635efSGarrett D'Amore * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4260e9a87SYuri Pankov * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> 595c635efSGarrett D'Amore * 695c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 795c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 895c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 995c635efSGarrett D'Amore * 10*371584c2SYuri Pankov * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 1195c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*371584c2SYuri Pankov * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 1395c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1495c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1595c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1695c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1795c635efSGarrett D'Amore */ 1895c635efSGarrett D'Amore #include "config.h" 1995c635efSGarrett D'Amore 2095c635efSGarrett D'Amore #include <sys/types.h> 2195c635efSGarrett D'Amore 2295c635efSGarrett D'Amore #include <assert.h> 23*371584c2SYuri Pankov #if HAVE_ERR 24*371584c2SYuri Pankov #include <err.h> 25*371584c2SYuri Pankov #endif 2695c635efSGarrett D'Amore #include <stdarg.h> 2795c635efSGarrett D'Amore #include <stdint.h> 2895c635efSGarrett D'Amore #include <stdio.h> 2995c635efSGarrett D'Amore #include <stdlib.h> 3095c635efSGarrett D'Amore #include <string.h> 3195c635efSGarrett D'Amore #include <unistd.h> 3295c635efSGarrett D'Amore 33260e9a87SYuri Pankov #include "mandoc_aux.h" 3495c635efSGarrett D'Amore #include "out.h" 3595c635efSGarrett D'Amore #include "term.h" 36*371584c2SYuri Pankov #include "manconf.h" 37260e9a87SYuri Pankov #include "main.h" 3895c635efSGarrett D'Amore 3995c635efSGarrett D'Amore /* These work the buffer used by the header and footer. */ 4095c635efSGarrett D'Amore #define PS_BUFSLOP 128 4195c635efSGarrett D'Amore 4295c635efSGarrett D'Amore /* Convert PostScript point "x" to an AFM unit. */ 43260e9a87SYuri Pankov #define PNT2AFM(p, x) \ 4495c635efSGarrett D'Amore (size_t)((double)(x) * (1000.0 / (double)(p)->ps->scale)) 4595c635efSGarrett D'Amore 4695c635efSGarrett D'Amore /* Convert an AFM unit "x" to a PostScript points */ 47260e9a87SYuri Pankov #define AFM2PNT(p, x) \ 4895c635efSGarrett D'Amore ((double)(x) / (1000.0 / (double)(p)->ps->scale)) 4995c635efSGarrett D'Amore 5095c635efSGarrett D'Amore struct glyph { 5195c635efSGarrett D'Amore unsigned short wx; /* WX in AFM */ 5295c635efSGarrett D'Amore }; 5395c635efSGarrett D'Amore 5495c635efSGarrett D'Amore struct font { 5595c635efSGarrett D'Amore const char *name; /* FontName in AFM */ 5695c635efSGarrett D'Amore #define MAXCHAR 95 /* total characters we can handle */ 5795c635efSGarrett D'Amore struct glyph gly[MAXCHAR]; /* glyph metrics */ 5895c635efSGarrett D'Amore }; 5995c635efSGarrett D'Amore 6095c635efSGarrett D'Amore struct termp_ps { 6195c635efSGarrett D'Amore int flags; 6295c635efSGarrett D'Amore #define PS_INLINE (1 << 0) /* we're in a word */ 6395c635efSGarrett D'Amore #define PS_MARGINS (1 << 1) /* we're in the margins */ 6495c635efSGarrett D'Amore #define PS_NEWPAGE (1 << 2) /* new page, no words yet */ 65260e9a87SYuri Pankov #define PS_BACKSP (1 << 3) /* last character was backspace */ 6695c635efSGarrett D'Amore size_t pscol; /* visible column (AFM units) */ 67260e9a87SYuri Pankov size_t pscolnext; /* used for overstrike */ 6895c635efSGarrett D'Amore size_t psrow; /* visible row (AFM units) */ 6995c635efSGarrett D'Amore char *psmarg; /* margin buf */ 7095c635efSGarrett D'Amore size_t psmargsz; /* margin buf size */ 7195c635efSGarrett D'Amore size_t psmargcur; /* cur index in margin buf */ 72260e9a87SYuri Pankov char last; /* last non-backspace seen */ 7395c635efSGarrett D'Amore enum termfont lastf; /* last set font */ 74260e9a87SYuri Pankov enum termfont nextf; /* building next font here */ 7595c635efSGarrett D'Amore size_t scale; /* font scaling factor */ 7695c635efSGarrett D'Amore size_t pages; /* number of pages shown */ 7795c635efSGarrett D'Amore size_t lineheight; /* line height (AFM units) */ 7895c635efSGarrett D'Amore size_t top; /* body top (AFM units) */ 7995c635efSGarrett D'Amore size_t bottom; /* body bottom (AFM units) */ 8095c635efSGarrett D'Amore size_t height; /* page height (AFM units */ 8195c635efSGarrett D'Amore size_t width; /* page width (AFM units) */ 82260e9a87SYuri Pankov size_t lastwidth; /* page width before last ll */ 8395c635efSGarrett D'Amore size_t left; /* body left (AFM units) */ 8495c635efSGarrett D'Amore size_t header; /* header pos (AFM units) */ 8595c635efSGarrett D'Amore size_t footer; /* footer pos (AFM units) */ 8695c635efSGarrett D'Amore size_t pdfbytes; /* current output byte */ 8795c635efSGarrett D'Amore size_t pdflastpg; /* byte of last page mark */ 8895c635efSGarrett D'Amore size_t pdfbody; /* start of body object */ 8995c635efSGarrett D'Amore size_t *pdfobjs; /* table of object offsets */ 9095c635efSGarrett D'Amore size_t pdfobjsz; /* size of pdfobjs */ 9195c635efSGarrett D'Amore }; 9295c635efSGarrett D'Amore 93*371584c2SYuri Pankov static int ps_hspan(const struct termp *, 9495c635efSGarrett D'Amore const struct roffsu *); 9595c635efSGarrett D'Amore static size_t ps_width(const struct termp *, int); 9695c635efSGarrett D'Amore static void ps_advance(struct termp *, size_t); 9795c635efSGarrett D'Amore static void ps_begin(struct termp *); 9895c635efSGarrett D'Amore static void ps_closepage(struct termp *); 9995c635efSGarrett D'Amore static void ps_end(struct termp *); 10095c635efSGarrett D'Amore static void ps_endline(struct termp *); 10195c635efSGarrett D'Amore static void ps_fclose(struct termp *); 10295c635efSGarrett D'Amore static void ps_growbuf(struct termp *, size_t); 10395c635efSGarrett D'Amore static void ps_letter(struct termp *, int); 10495c635efSGarrett D'Amore static void ps_pclose(struct termp *); 10595c635efSGarrett D'Amore static void ps_pletter(struct termp *, int); 106260e9a87SYuri Pankov #if __GNUC__ - 0 >= 4 107260e9a87SYuri Pankov __attribute__((__format__ (__printf__, 2, 3))) 108260e9a87SYuri Pankov #endif 10995c635efSGarrett D'Amore static void ps_printf(struct termp *, const char *, ...); 11095c635efSGarrett D'Amore static void ps_putchar(struct termp *, char); 11195c635efSGarrett D'Amore static void ps_setfont(struct termp *, enum termfont); 112*371584c2SYuri Pankov static void ps_setwidth(struct termp *, int, int); 113*371584c2SYuri Pankov static struct termp *pspdf_alloc(const struct manoutput *); 11495c635efSGarrett D'Amore static void pdf_obj(struct termp *, size_t); 11595c635efSGarrett D'Amore 11695c635efSGarrett D'Amore /* 11795c635efSGarrett D'Amore * We define, for the time being, three fonts: bold, oblique/italic, and 11895c635efSGarrett D'Amore * normal (roman). The following table hard-codes the font metrics for 11995c635efSGarrett D'Amore * ASCII, i.e., 32--127. 12095c635efSGarrett D'Amore */ 12195c635efSGarrett D'Amore 12295c635efSGarrett D'Amore static const struct font fonts[TERMFONT__MAX] = { 12395c635efSGarrett D'Amore { "Times-Roman", { 12495c635efSGarrett D'Amore { 250 }, 12595c635efSGarrett D'Amore { 333 }, 12695c635efSGarrett D'Amore { 408 }, 12795c635efSGarrett D'Amore { 500 }, 12895c635efSGarrett D'Amore { 500 }, 12995c635efSGarrett D'Amore { 833 }, 13095c635efSGarrett D'Amore { 778 }, 13195c635efSGarrett D'Amore { 333 }, 13295c635efSGarrett D'Amore { 333 }, 13395c635efSGarrett D'Amore { 333 }, 13495c635efSGarrett D'Amore { 500 }, 13595c635efSGarrett D'Amore { 564 }, 13695c635efSGarrett D'Amore { 250 }, 13795c635efSGarrett D'Amore { 333 }, 13895c635efSGarrett D'Amore { 250 }, 13995c635efSGarrett D'Amore { 278 }, 14095c635efSGarrett D'Amore { 500 }, 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 { 278 }, 15195c635efSGarrett D'Amore { 278 }, 15295c635efSGarrett D'Amore { 564 }, 15395c635efSGarrett D'Amore { 564 }, 15495c635efSGarrett D'Amore { 564 }, 15595c635efSGarrett D'Amore { 444 }, 15695c635efSGarrett D'Amore { 921 }, 15795c635efSGarrett D'Amore { 722 }, 15895c635efSGarrett D'Amore { 667 }, 15995c635efSGarrett D'Amore { 667 }, 16095c635efSGarrett D'Amore { 722 }, 16195c635efSGarrett D'Amore { 611 }, 16295c635efSGarrett D'Amore { 556 }, 16395c635efSGarrett D'Amore { 722 }, 16495c635efSGarrett D'Amore { 722 }, 16595c635efSGarrett D'Amore { 333 }, 16695c635efSGarrett D'Amore { 389 }, 16795c635efSGarrett D'Amore { 722 }, 16895c635efSGarrett D'Amore { 611 }, 16995c635efSGarrett D'Amore { 889 }, 17095c635efSGarrett D'Amore { 722 }, 17195c635efSGarrett D'Amore { 722 }, 17295c635efSGarrett D'Amore { 556 }, 17395c635efSGarrett D'Amore { 722 }, 17495c635efSGarrett D'Amore { 667 }, 17595c635efSGarrett D'Amore { 556 }, 17695c635efSGarrett D'Amore { 611 }, 17795c635efSGarrett D'Amore { 722 }, 17895c635efSGarrett D'Amore { 722 }, 17995c635efSGarrett D'Amore { 944 }, 18095c635efSGarrett D'Amore { 722 }, 18195c635efSGarrett D'Amore { 722 }, 18295c635efSGarrett D'Amore { 611 }, 18395c635efSGarrett D'Amore { 333 }, 18495c635efSGarrett D'Amore { 278 }, 18595c635efSGarrett D'Amore { 333 }, 18695c635efSGarrett D'Amore { 469 }, 18795c635efSGarrett D'Amore { 500 }, 18895c635efSGarrett D'Amore { 333 }, 18995c635efSGarrett D'Amore { 444 }, 19095c635efSGarrett D'Amore { 500 }, 19195c635efSGarrett D'Amore { 444 }, 19295c635efSGarrett D'Amore { 500}, 19395c635efSGarrett D'Amore { 444}, 19495c635efSGarrett D'Amore { 333}, 19595c635efSGarrett D'Amore { 500}, 19695c635efSGarrett D'Amore { 500}, 19795c635efSGarrett D'Amore { 278}, 19895c635efSGarrett D'Amore { 278}, 19995c635efSGarrett D'Amore { 500}, 20095c635efSGarrett D'Amore { 278}, 20195c635efSGarrett D'Amore { 778}, 20295c635efSGarrett D'Amore { 500}, 20395c635efSGarrett D'Amore { 500}, 20495c635efSGarrett D'Amore { 500}, 20595c635efSGarrett D'Amore { 500}, 20695c635efSGarrett D'Amore { 333}, 20795c635efSGarrett D'Amore { 389}, 20895c635efSGarrett D'Amore { 278}, 20995c635efSGarrett D'Amore { 500}, 21095c635efSGarrett D'Amore { 500}, 21195c635efSGarrett D'Amore { 722}, 21295c635efSGarrett D'Amore { 500}, 21395c635efSGarrett D'Amore { 500}, 21495c635efSGarrett D'Amore { 444}, 21595c635efSGarrett D'Amore { 480}, 21695c635efSGarrett D'Amore { 200}, 21795c635efSGarrett D'Amore { 480}, 21895c635efSGarrett D'Amore { 541}, 21995c635efSGarrett D'Amore } }, 22095c635efSGarrett D'Amore { "Times-Bold", { 22195c635efSGarrett D'Amore { 250 }, 22295c635efSGarrett D'Amore { 333 }, 22395c635efSGarrett D'Amore { 555 }, 22495c635efSGarrett D'Amore { 500 }, 22595c635efSGarrett D'Amore { 500 }, 22695c635efSGarrett D'Amore { 1000 }, 22795c635efSGarrett D'Amore { 833 }, 22895c635efSGarrett D'Amore { 333 }, 22995c635efSGarrett D'Amore { 333 }, 23095c635efSGarrett D'Amore { 333 }, 23195c635efSGarrett D'Amore { 500 }, 23295c635efSGarrett D'Amore { 570 }, 23395c635efSGarrett D'Amore { 250 }, 23495c635efSGarrett D'Amore { 333 }, 23595c635efSGarrett D'Amore { 250 }, 23695c635efSGarrett D'Amore { 278 }, 23795c635efSGarrett D'Amore { 500 }, 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 { 333 }, 24895c635efSGarrett D'Amore { 333 }, 24995c635efSGarrett D'Amore { 570 }, 25095c635efSGarrett D'Amore { 570 }, 25195c635efSGarrett D'Amore { 570 }, 25295c635efSGarrett D'Amore { 500 }, 25395c635efSGarrett D'Amore { 930 }, 25495c635efSGarrett D'Amore { 722 }, 25595c635efSGarrett D'Amore { 667 }, 25695c635efSGarrett D'Amore { 722 }, 25795c635efSGarrett D'Amore { 722 }, 25895c635efSGarrett D'Amore { 667 }, 25995c635efSGarrett D'Amore { 611 }, 26095c635efSGarrett D'Amore { 778 }, 26195c635efSGarrett D'Amore { 778 }, 26295c635efSGarrett D'Amore { 389 }, 26395c635efSGarrett D'Amore { 500 }, 26495c635efSGarrett D'Amore { 778 }, 26595c635efSGarrett D'Amore { 667 }, 26695c635efSGarrett D'Amore { 944 }, 26795c635efSGarrett D'Amore { 722 }, 26895c635efSGarrett D'Amore { 778 }, 26995c635efSGarrett D'Amore { 611 }, 27095c635efSGarrett D'Amore { 778 }, 27195c635efSGarrett D'Amore { 722 }, 27295c635efSGarrett D'Amore { 556 }, 27395c635efSGarrett D'Amore { 667 }, 27495c635efSGarrett D'Amore { 722 }, 27595c635efSGarrett D'Amore { 722 }, 27695c635efSGarrett D'Amore { 1000 }, 27795c635efSGarrett D'Amore { 722 }, 27895c635efSGarrett D'Amore { 722 }, 27995c635efSGarrett D'Amore { 667 }, 28095c635efSGarrett D'Amore { 333 }, 28195c635efSGarrett D'Amore { 278 }, 28295c635efSGarrett D'Amore { 333 }, 28395c635efSGarrett D'Amore { 581 }, 28495c635efSGarrett D'Amore { 500 }, 28595c635efSGarrett D'Amore { 333 }, 28695c635efSGarrett D'Amore { 500 }, 28795c635efSGarrett D'Amore { 556 }, 28895c635efSGarrett D'Amore { 444 }, 28995c635efSGarrett D'Amore { 556 }, 29095c635efSGarrett D'Amore { 444 }, 29195c635efSGarrett D'Amore { 333 }, 29295c635efSGarrett D'Amore { 500 }, 29395c635efSGarrett D'Amore { 556 }, 29495c635efSGarrett D'Amore { 278 }, 29595c635efSGarrett D'Amore { 333 }, 29695c635efSGarrett D'Amore { 556 }, 29795c635efSGarrett D'Amore { 278 }, 29895c635efSGarrett D'Amore { 833 }, 29995c635efSGarrett D'Amore { 556 }, 30095c635efSGarrett D'Amore { 500 }, 30195c635efSGarrett D'Amore { 556 }, 30295c635efSGarrett D'Amore { 556 }, 30395c635efSGarrett D'Amore { 444 }, 30495c635efSGarrett D'Amore { 389 }, 30595c635efSGarrett D'Amore { 333 }, 30695c635efSGarrett D'Amore { 556 }, 30795c635efSGarrett D'Amore { 500 }, 30895c635efSGarrett D'Amore { 722 }, 30995c635efSGarrett D'Amore { 500 }, 31095c635efSGarrett D'Amore { 500 }, 31195c635efSGarrett D'Amore { 444 }, 31295c635efSGarrett D'Amore { 394 }, 31395c635efSGarrett D'Amore { 220 }, 31495c635efSGarrett D'Amore { 394 }, 31595c635efSGarrett D'Amore { 520 }, 31695c635efSGarrett D'Amore } }, 31795c635efSGarrett D'Amore { "Times-Italic", { 31895c635efSGarrett D'Amore { 250 }, 31995c635efSGarrett D'Amore { 333 }, 32095c635efSGarrett D'Amore { 420 }, 32195c635efSGarrett D'Amore { 500 }, 32295c635efSGarrett D'Amore { 500 }, 32395c635efSGarrett D'Amore { 833 }, 32495c635efSGarrett D'Amore { 778 }, 32595c635efSGarrett D'Amore { 333 }, 32695c635efSGarrett D'Amore { 333 }, 32795c635efSGarrett D'Amore { 333 }, 32895c635efSGarrett D'Amore { 500 }, 32995c635efSGarrett D'Amore { 675 }, 33095c635efSGarrett D'Amore { 250 }, 33195c635efSGarrett D'Amore { 333 }, 33295c635efSGarrett D'Amore { 250 }, 33395c635efSGarrett D'Amore { 278 }, 33495c635efSGarrett D'Amore { 500 }, 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 { 333 }, 34595c635efSGarrett D'Amore { 333 }, 34695c635efSGarrett D'Amore { 675 }, 34795c635efSGarrett D'Amore { 675 }, 34895c635efSGarrett D'Amore { 675 }, 34995c635efSGarrett D'Amore { 500 }, 35095c635efSGarrett D'Amore { 920 }, 35195c635efSGarrett D'Amore { 611 }, 35295c635efSGarrett D'Amore { 611 }, 35395c635efSGarrett D'Amore { 667 }, 35495c635efSGarrett D'Amore { 722 }, 35595c635efSGarrett D'Amore { 611 }, 35695c635efSGarrett D'Amore { 611 }, 35795c635efSGarrett D'Amore { 722 }, 35895c635efSGarrett D'Amore { 722 }, 35995c635efSGarrett D'Amore { 333 }, 36095c635efSGarrett D'Amore { 444 }, 36195c635efSGarrett D'Amore { 667 }, 36295c635efSGarrett D'Amore { 556 }, 36395c635efSGarrett D'Amore { 833 }, 36495c635efSGarrett D'Amore { 667 }, 36595c635efSGarrett D'Amore { 722 }, 36695c635efSGarrett D'Amore { 611 }, 36795c635efSGarrett D'Amore { 722 }, 36895c635efSGarrett D'Amore { 611 }, 36995c635efSGarrett D'Amore { 500 }, 37095c635efSGarrett D'Amore { 556 }, 37195c635efSGarrett D'Amore { 722 }, 37295c635efSGarrett D'Amore { 611 }, 37395c635efSGarrett D'Amore { 833 }, 37495c635efSGarrett D'Amore { 611 }, 37595c635efSGarrett D'Amore { 556 }, 37695c635efSGarrett D'Amore { 556 }, 37795c635efSGarrett D'Amore { 389 }, 37895c635efSGarrett D'Amore { 278 }, 37995c635efSGarrett D'Amore { 389 }, 38095c635efSGarrett D'Amore { 422 }, 38195c635efSGarrett D'Amore { 500 }, 38295c635efSGarrett D'Amore { 333 }, 38395c635efSGarrett D'Amore { 500 }, 38495c635efSGarrett D'Amore { 500 }, 38595c635efSGarrett D'Amore { 444 }, 38695c635efSGarrett D'Amore { 500 }, 38795c635efSGarrett D'Amore { 444 }, 38895c635efSGarrett D'Amore { 278 }, 38995c635efSGarrett D'Amore { 500 }, 39095c635efSGarrett D'Amore { 500 }, 39195c635efSGarrett D'Amore { 278 }, 39295c635efSGarrett D'Amore { 278 }, 39395c635efSGarrett D'Amore { 444 }, 39495c635efSGarrett D'Amore { 278 }, 39595c635efSGarrett D'Amore { 722 }, 39695c635efSGarrett D'Amore { 500 }, 39795c635efSGarrett D'Amore { 500 }, 39895c635efSGarrett D'Amore { 500 }, 39995c635efSGarrett D'Amore { 500 }, 40095c635efSGarrett D'Amore { 389 }, 40195c635efSGarrett D'Amore { 389 }, 40295c635efSGarrett D'Amore { 278 }, 40395c635efSGarrett D'Amore { 500 }, 40495c635efSGarrett D'Amore { 444 }, 40595c635efSGarrett D'Amore { 667 }, 40695c635efSGarrett D'Amore { 444 }, 40795c635efSGarrett D'Amore { 444 }, 40895c635efSGarrett D'Amore { 389 }, 40995c635efSGarrett D'Amore { 400 }, 41095c635efSGarrett D'Amore { 275 }, 41195c635efSGarrett D'Amore { 400 }, 41295c635efSGarrett D'Amore { 541 }, 41395c635efSGarrett D'Amore } }, 414260e9a87SYuri Pankov { "Times-BoldItalic", { 415260e9a87SYuri Pankov { 250 }, 416260e9a87SYuri Pankov { 389 }, 417260e9a87SYuri Pankov { 555 }, 418260e9a87SYuri Pankov { 500 }, 419260e9a87SYuri Pankov { 500 }, 420260e9a87SYuri Pankov { 833 }, 421260e9a87SYuri Pankov { 778 }, 422260e9a87SYuri Pankov { 333 }, 423260e9a87SYuri Pankov { 333 }, 424260e9a87SYuri Pankov { 333 }, 425260e9a87SYuri Pankov { 500 }, 426260e9a87SYuri Pankov { 570 }, 427260e9a87SYuri Pankov { 250 }, 428260e9a87SYuri Pankov { 333 }, 429260e9a87SYuri Pankov { 250 }, 430260e9a87SYuri Pankov { 278 }, 431260e9a87SYuri Pankov { 500 }, 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 { 333 }, 442260e9a87SYuri Pankov { 333 }, 443260e9a87SYuri Pankov { 570 }, 444260e9a87SYuri Pankov { 570 }, 445260e9a87SYuri Pankov { 570 }, 446260e9a87SYuri Pankov { 500 }, 447260e9a87SYuri Pankov { 832 }, 448260e9a87SYuri Pankov { 667 }, 449260e9a87SYuri Pankov { 667 }, 450260e9a87SYuri Pankov { 667 }, 451260e9a87SYuri Pankov { 722 }, 452260e9a87SYuri Pankov { 667 }, 453260e9a87SYuri Pankov { 667 }, 454260e9a87SYuri Pankov { 722 }, 455260e9a87SYuri Pankov { 778 }, 456260e9a87SYuri Pankov { 389 }, 457260e9a87SYuri Pankov { 500 }, 458260e9a87SYuri Pankov { 667 }, 459260e9a87SYuri Pankov { 611 }, 460260e9a87SYuri Pankov { 889 }, 461260e9a87SYuri Pankov { 722 }, 462260e9a87SYuri Pankov { 722 }, 463260e9a87SYuri Pankov { 611 }, 464260e9a87SYuri Pankov { 722 }, 465260e9a87SYuri Pankov { 667 }, 466260e9a87SYuri Pankov { 556 }, 467260e9a87SYuri Pankov { 611 }, 468260e9a87SYuri Pankov { 722 }, 469260e9a87SYuri Pankov { 667 }, 470260e9a87SYuri Pankov { 889 }, 471260e9a87SYuri Pankov { 667 }, 472260e9a87SYuri Pankov { 611 }, 473260e9a87SYuri Pankov { 611 }, 474260e9a87SYuri Pankov { 333 }, 475260e9a87SYuri Pankov { 278 }, 476260e9a87SYuri Pankov { 333 }, 477260e9a87SYuri Pankov { 570 }, 478260e9a87SYuri Pankov { 500 }, 479260e9a87SYuri Pankov { 333 }, 480260e9a87SYuri Pankov { 500 }, 481260e9a87SYuri Pankov { 500 }, 482260e9a87SYuri Pankov { 444 }, 483260e9a87SYuri Pankov { 500 }, 484260e9a87SYuri Pankov { 444 }, 485260e9a87SYuri Pankov { 333 }, 486260e9a87SYuri Pankov { 500 }, 487260e9a87SYuri Pankov { 556 }, 488260e9a87SYuri Pankov { 278 }, 489260e9a87SYuri Pankov { 278 }, 490260e9a87SYuri Pankov { 500 }, 491260e9a87SYuri Pankov { 278 }, 492260e9a87SYuri Pankov { 778 }, 493260e9a87SYuri Pankov { 556 }, 494260e9a87SYuri Pankov { 500 }, 495260e9a87SYuri Pankov { 500 }, 496260e9a87SYuri Pankov { 500 }, 497260e9a87SYuri Pankov { 389 }, 498260e9a87SYuri Pankov { 389 }, 499260e9a87SYuri Pankov { 278 }, 500260e9a87SYuri Pankov { 556 }, 501260e9a87SYuri Pankov { 444 }, 502260e9a87SYuri Pankov { 667 }, 503260e9a87SYuri Pankov { 500 }, 504260e9a87SYuri Pankov { 444 }, 505260e9a87SYuri Pankov { 389 }, 506260e9a87SYuri Pankov { 348 }, 507260e9a87SYuri Pankov { 220 }, 508260e9a87SYuri Pankov { 348 }, 509260e9a87SYuri Pankov { 570 }, 510260e9a87SYuri Pankov } }, 51195c635efSGarrett D'Amore }; 51295c635efSGarrett D'Amore 51395c635efSGarrett D'Amore void * 514*371584c2SYuri Pankov pdf_alloc(const struct manoutput *outopts) 51595c635efSGarrett D'Amore { 51695c635efSGarrett D'Amore struct termp *p; 51795c635efSGarrett D'Amore 518*371584c2SYuri Pankov if (NULL != (p = pspdf_alloc(outopts))) 51995c635efSGarrett D'Amore p->type = TERMTYPE_PDF; 52095c635efSGarrett D'Amore 521*371584c2SYuri Pankov return p; 52295c635efSGarrett D'Amore } 52395c635efSGarrett D'Amore 52495c635efSGarrett D'Amore void * 525*371584c2SYuri Pankov ps_alloc(const struct manoutput *outopts) 52695c635efSGarrett D'Amore { 52795c635efSGarrett D'Amore struct termp *p; 52895c635efSGarrett D'Amore 529*371584c2SYuri Pankov if (NULL != (p = pspdf_alloc(outopts))) 53095c635efSGarrett D'Amore p->type = TERMTYPE_PS; 53195c635efSGarrett D'Amore 532*371584c2SYuri Pankov return p; 53395c635efSGarrett D'Amore } 53495c635efSGarrett D'Amore 53595c635efSGarrett D'Amore static struct termp * 536*371584c2SYuri Pankov pspdf_alloc(const struct manoutput *outopts) 53795c635efSGarrett D'Amore { 53895c635efSGarrett D'Amore struct termp *p; 53995c635efSGarrett D'Amore unsigned int pagex, pagey; 54095c635efSGarrett D'Amore size_t marginx, marginy, lineheight; 54195c635efSGarrett D'Amore const char *pp; 54295c635efSGarrett D'Amore 54395c635efSGarrett D'Amore p = mandoc_calloc(1, sizeof(struct termp)); 54495c635efSGarrett D'Amore p->enc = TERMENC_ASCII; 545260e9a87SYuri Pankov p->fontq = mandoc_reallocarray(NULL, 546260e9a87SYuri Pankov (p->fontsz = 8), sizeof(enum termfont)); 547260e9a87SYuri Pankov p->fontq[0] = p->fontl = TERMFONT_NONE; 54895c635efSGarrett D'Amore p->ps = mandoc_calloc(1, sizeof(struct termp_ps)); 54995c635efSGarrett D'Amore 55095c635efSGarrett D'Amore p->advance = ps_advance; 55195c635efSGarrett D'Amore p->begin = ps_begin; 55295c635efSGarrett D'Amore p->end = ps_end; 55395c635efSGarrett D'Amore p->endline = ps_endline; 55495c635efSGarrett D'Amore p->hspan = ps_hspan; 55595c635efSGarrett D'Amore p->letter = ps_letter; 556260e9a87SYuri Pankov p->setwidth = ps_setwidth; 55795c635efSGarrett D'Amore p->width = ps_width; 55895c635efSGarrett D'Amore 55995c635efSGarrett D'Amore /* Default to US letter (millimetres). */ 56095c635efSGarrett D'Amore 56195c635efSGarrett D'Amore pagex = 216; 56295c635efSGarrett D'Amore pagey = 279; 56395c635efSGarrett D'Amore 56495c635efSGarrett D'Amore /* 56595c635efSGarrett D'Amore * The ISO-269 paper sizes can be calculated automatically, but 56695c635efSGarrett D'Amore * it would require bringing in -lm for pow() and I'd rather not 56795c635efSGarrett D'Amore * do that. So just do it the easy way for now. Since this 56895c635efSGarrett D'Amore * only happens once, I'm not terribly concerned. 56995c635efSGarrett D'Amore */ 57095c635efSGarrett D'Amore 571*371584c2SYuri Pankov pp = outopts->paper; 57295c635efSGarrett D'Amore if (pp && strcasecmp(pp, "letter")) { 57395c635efSGarrett D'Amore if (0 == strcasecmp(pp, "a3")) { 57495c635efSGarrett D'Amore pagex = 297; 57595c635efSGarrett D'Amore pagey = 420; 57695c635efSGarrett D'Amore } else if (0 == strcasecmp(pp, "a4")) { 57795c635efSGarrett D'Amore pagex = 210; 57895c635efSGarrett D'Amore pagey = 297; 57995c635efSGarrett D'Amore } else if (0 == strcasecmp(pp, "a5")) { 58095c635efSGarrett D'Amore pagex = 148; 58195c635efSGarrett D'Amore pagey = 210; 58295c635efSGarrett D'Amore } else if (0 == strcasecmp(pp, "legal")) { 58395c635efSGarrett D'Amore pagex = 216; 58495c635efSGarrett D'Amore pagey = 356; 58595c635efSGarrett D'Amore } else if (2 != sscanf(pp, "%ux%u", &pagex, &pagey)) 586*371584c2SYuri Pankov warnx("%s: Unknown paper", pp); 58795c635efSGarrett D'Amore } 58895c635efSGarrett D'Amore 58995c635efSGarrett D'Amore /* 59095c635efSGarrett D'Amore * This MUST be defined before any PNT2AFM or AFM2PNT 59195c635efSGarrett D'Amore * calculations occur. 59295c635efSGarrett D'Amore */ 59395c635efSGarrett D'Amore 59495c635efSGarrett D'Amore p->ps->scale = 11; 59595c635efSGarrett D'Amore 59695c635efSGarrett D'Amore /* Remember millimetres -> AFM units. */ 59795c635efSGarrett D'Amore 59895c635efSGarrett D'Amore pagex = PNT2AFM(p, ((double)pagex * 2.834)); 59995c635efSGarrett D'Amore pagey = PNT2AFM(p, ((double)pagey * 2.834)); 60095c635efSGarrett D'Amore 60195c635efSGarrett D'Amore /* Margins are 1/9 the page x and y. */ 60295c635efSGarrett D'Amore 603260e9a87SYuri Pankov marginx = (size_t)((double)pagex / 9.0); 604260e9a87SYuri Pankov marginy = (size_t)((double)pagey / 9.0); 60595c635efSGarrett D'Amore 60695c635efSGarrett D'Amore /* Line-height is 1.4em. */ 60795c635efSGarrett D'Amore 60895c635efSGarrett D'Amore lineheight = PNT2AFM(p, ((double)p->ps->scale * 1.4)); 60995c635efSGarrett D'Amore 610260e9a87SYuri Pankov p->ps->width = p->ps->lastwidth = (size_t)pagex; 61195c635efSGarrett D'Amore p->ps->height = (size_t)pagey; 61295c635efSGarrett D'Amore p->ps->header = pagey - (marginy / 2) - (lineheight / 2); 61395c635efSGarrett D'Amore p->ps->top = pagey - marginy; 61495c635efSGarrett D'Amore p->ps->footer = (marginy / 2) - (lineheight / 2); 61595c635efSGarrett D'Amore p->ps->bottom = marginy; 61695c635efSGarrett D'Amore p->ps->left = marginx; 61795c635efSGarrett D'Amore p->ps->lineheight = lineheight; 61895c635efSGarrett D'Amore 61995c635efSGarrett D'Amore p->defrmargin = pagex - (marginx * 2); 620*371584c2SYuri Pankov return p; 62195c635efSGarrett D'Amore } 62295c635efSGarrett D'Amore 623260e9a87SYuri Pankov static void 624*371584c2SYuri Pankov ps_setwidth(struct termp *p, int iop, int width) 625260e9a87SYuri Pankov { 626260e9a87SYuri Pankov size_t lastwidth; 627260e9a87SYuri Pankov 628260e9a87SYuri Pankov lastwidth = p->ps->width; 629260e9a87SYuri Pankov if (iop > 0) 630260e9a87SYuri Pankov p->ps->width += width; 631260e9a87SYuri Pankov else if (iop == 0) 632*371584c2SYuri Pankov p->ps->width = width ? (size_t)width : p->ps->lastwidth; 633*371584c2SYuri Pankov else if (p->ps->width > (size_t)width) 634260e9a87SYuri Pankov p->ps->width -= width; 635260e9a87SYuri Pankov else 636260e9a87SYuri Pankov p->ps->width = 0; 637260e9a87SYuri Pankov p->ps->lastwidth = lastwidth; 638260e9a87SYuri Pankov } 63995c635efSGarrett D'Amore 64095c635efSGarrett D'Amore void 64195c635efSGarrett D'Amore pspdf_free(void *arg) 64295c635efSGarrett D'Amore { 64395c635efSGarrett D'Amore struct termp *p; 64495c635efSGarrett D'Amore 64595c635efSGarrett D'Amore p = (struct termp *)arg; 64695c635efSGarrett D'Amore 64795c635efSGarrett D'Amore free(p->ps->psmarg); 64895c635efSGarrett D'Amore free(p->ps->pdfobjs); 64995c635efSGarrett D'Amore 65095c635efSGarrett D'Amore free(p->ps); 65195c635efSGarrett D'Amore term_free(p); 65295c635efSGarrett D'Amore } 65395c635efSGarrett D'Amore 65495c635efSGarrett D'Amore static void 65595c635efSGarrett D'Amore ps_printf(struct termp *p, const char *fmt, ...) 65695c635efSGarrett D'Amore { 65795c635efSGarrett D'Amore va_list ap; 65895c635efSGarrett D'Amore int pos, len; 65995c635efSGarrett D'Amore 66095c635efSGarrett D'Amore va_start(ap, fmt); 66195c635efSGarrett D'Amore 66295c635efSGarrett D'Amore /* 66395c635efSGarrett D'Amore * If we're running in regular mode, then pipe directly into 66495c635efSGarrett D'Amore * vprintf(). If we're processing margins, then push the data 66595c635efSGarrett D'Amore * into our growable margin buffer. 66695c635efSGarrett D'Amore */ 66795c635efSGarrett D'Amore 66895c635efSGarrett D'Amore if ( ! (PS_MARGINS & p->ps->flags)) { 66995c635efSGarrett D'Amore len = vprintf(fmt, ap); 67095c635efSGarrett D'Amore va_end(ap); 671260e9a87SYuri Pankov p->ps->pdfbytes += len < 0 ? 0 : (size_t)len; 67295c635efSGarrett D'Amore return; 67395c635efSGarrett D'Amore } 67495c635efSGarrett D'Amore 67595c635efSGarrett D'Amore /* 67695c635efSGarrett D'Amore * XXX: I assume that the in-margin print won't exceed 67795c635efSGarrett D'Amore * PS_BUFSLOP (128 bytes), which is reasonable but still an 67895c635efSGarrett D'Amore * assumption that will cause pukeage if it's not the case. 67995c635efSGarrett D'Amore */ 68095c635efSGarrett D'Amore 68195c635efSGarrett D'Amore ps_growbuf(p, PS_BUFSLOP); 68295c635efSGarrett D'Amore 68395c635efSGarrett D'Amore pos = (int)p->ps->psmargcur; 68495c635efSGarrett D'Amore vsnprintf(&p->ps->psmarg[pos], PS_BUFSLOP, fmt, ap); 68595c635efSGarrett D'Amore 68695c635efSGarrett D'Amore va_end(ap); 68795c635efSGarrett D'Amore 68895c635efSGarrett D'Amore p->ps->psmargcur = strlen(p->ps->psmarg); 68995c635efSGarrett D'Amore } 69095c635efSGarrett D'Amore 69195c635efSGarrett D'Amore static void 69295c635efSGarrett D'Amore ps_putchar(struct termp *p, char c) 69395c635efSGarrett D'Amore { 69495c635efSGarrett D'Amore int pos; 69595c635efSGarrett D'Amore 69695c635efSGarrett D'Amore /* See ps_printf(). */ 69795c635efSGarrett D'Amore 69895c635efSGarrett D'Amore if ( ! (PS_MARGINS & p->ps->flags)) { 69995c635efSGarrett D'Amore putchar(c); 70095c635efSGarrett D'Amore p->ps->pdfbytes++; 70195c635efSGarrett D'Amore return; 70295c635efSGarrett D'Amore } 70395c635efSGarrett D'Amore 70495c635efSGarrett D'Amore ps_growbuf(p, 2); 70595c635efSGarrett D'Amore 70695c635efSGarrett D'Amore pos = (int)p->ps->psmargcur++; 70795c635efSGarrett D'Amore p->ps->psmarg[pos++] = c; 70895c635efSGarrett D'Amore p->ps->psmarg[pos] = '\0'; 70995c635efSGarrett D'Amore } 71095c635efSGarrett D'Amore 71195c635efSGarrett D'Amore static void 71295c635efSGarrett D'Amore pdf_obj(struct termp *p, size_t obj) 71395c635efSGarrett D'Amore { 71495c635efSGarrett D'Amore 71595c635efSGarrett D'Amore assert(obj > 0); 71695c635efSGarrett D'Amore 71795c635efSGarrett D'Amore if ((obj - 1) >= p->ps->pdfobjsz) { 71895c635efSGarrett D'Amore p->ps->pdfobjsz = obj + 128; 719260e9a87SYuri Pankov p->ps->pdfobjs = mandoc_reallocarray(p->ps->pdfobjs, 720260e9a87SYuri Pankov p->ps->pdfobjsz, sizeof(size_t)); 72195c635efSGarrett D'Amore } 72295c635efSGarrett D'Amore 72395c635efSGarrett D'Amore p->ps->pdfobjs[(int)obj - 1] = p->ps->pdfbytes; 72495c635efSGarrett D'Amore ps_printf(p, "%zu 0 obj\n", obj); 72595c635efSGarrett D'Amore } 72695c635efSGarrett D'Amore 72795c635efSGarrett D'Amore static void 72895c635efSGarrett D'Amore ps_closepage(struct termp *p) 72995c635efSGarrett D'Amore { 73095c635efSGarrett D'Amore int i; 73195c635efSGarrett D'Amore size_t len, base; 73295c635efSGarrett D'Amore 73395c635efSGarrett D'Amore /* 73495c635efSGarrett D'Amore * Close out a page that we've already flushed to output. In 73595c635efSGarrett D'Amore * PostScript, we simply note that the page must be showed. In 73695c635efSGarrett D'Amore * PDF, we must now create the Length, Resource, and Page node 73795c635efSGarrett D'Amore * for the page contents. 73895c635efSGarrett D'Amore */ 73995c635efSGarrett D'Amore 74095c635efSGarrett D'Amore assert(p->ps->psmarg && p->ps->psmarg[0]); 74195c635efSGarrett D'Amore ps_printf(p, "%s", p->ps->psmarg); 74295c635efSGarrett D'Amore 74395c635efSGarrett D'Amore if (TERMTYPE_PS != p->type) { 74495c635efSGarrett D'Amore ps_printf(p, "ET\n"); 74595c635efSGarrett D'Amore 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); 76195c635efSGarrett D'Amore ps_printf(p, ">>\n>>\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 78595c635efSGarrett D'Amore /* 78695c635efSGarrett D'Amore * At the end of the file, do one last showpage. This is the 78795c635efSGarrett D'Amore * same behaviour as groff(1) and works for multiple pages as 78895c635efSGarrett D'Amore * well as just one. 78995c635efSGarrett D'Amore */ 79095c635efSGarrett D'Amore 79195c635efSGarrett D'Amore if ( ! (PS_NEWPAGE & p->ps->flags)) { 79295c635efSGarrett D'Amore assert(0 == p->ps->flags); 79395c635efSGarrett D'Amore assert('\0' == p->ps->last); 79495c635efSGarrett D'Amore ps_closepage(p); 79595c635efSGarrett D'Amore } 79695c635efSGarrett D'Amore 79795c635efSGarrett D'Amore if (TERMTYPE_PS == p->type) { 79895c635efSGarrett D'Amore ps_printf(p, "%%%%Trailer\n"); 79995c635efSGarrett D'Amore ps_printf(p, "%%%%Pages: %zu\n", p->ps->pages); 80095c635efSGarrett D'Amore ps_printf(p, "%%%%EOF\n"); 80195c635efSGarrett D'Amore return; 80295c635efSGarrett D'Amore } 80395c635efSGarrett D'Amore 80495c635efSGarrett D'Amore pdf_obj(p, 2); 80595c635efSGarrett D'Amore ps_printf(p, "<<\n/Type /Pages\n"); 80695c635efSGarrett D'Amore ps_printf(p, "/MediaBox [0 0 %zu %zu]\n", 80795c635efSGarrett D'Amore (size_t)AFM2PNT(p, p->ps->width), 80895c635efSGarrett D'Amore (size_t)AFM2PNT(p, p->ps->height)); 80995c635efSGarrett D'Amore 81095c635efSGarrett D'Amore ps_printf(p, "/Count %zu\n", p->ps->pages); 81195c635efSGarrett D'Amore ps_printf(p, "/Kids ["); 81295c635efSGarrett D'Amore 81395c635efSGarrett D'Amore for (i = 0; i < p->ps->pages; i++) 814260e9a87SYuri Pankov ps_printf(p, " %zu 0 R", i * 4 + p->ps->pdfbody + 3); 81595c635efSGarrett D'Amore 816260e9a87SYuri Pankov base = (p->ps->pages - 1) * 4 + p->ps->pdfbody + 4; 81795c635efSGarrett D'Amore 81895c635efSGarrett D'Amore ps_printf(p, "]\n>>\nendobj\n"); 81995c635efSGarrett D'Amore pdf_obj(p, base); 82095c635efSGarrett D'Amore ps_printf(p, "<<\n"); 82195c635efSGarrett D'Amore ps_printf(p, "/Type /Catalog\n"); 82295c635efSGarrett D'Amore ps_printf(p, "/Pages 2 0 R\n"); 82395c635efSGarrett D'Amore ps_printf(p, ">>\n"); 82495c635efSGarrett D'Amore xref = p->ps->pdfbytes; 82595c635efSGarrett D'Amore ps_printf(p, "xref\n"); 82695c635efSGarrett D'Amore ps_printf(p, "0 %zu\n", base + 1); 82795c635efSGarrett D'Amore ps_printf(p, "0000000000 65535 f \n"); 82895c635efSGarrett D'Amore 82995c635efSGarrett D'Amore for (i = 0; i < base; i++) 83095c635efSGarrett D'Amore ps_printf(p, "%.10zu 00000 n \n", 83195c635efSGarrett D'Amore p->ps->pdfobjs[(int)i]); 83295c635efSGarrett D'Amore 83395c635efSGarrett D'Amore ps_printf(p, "trailer\n"); 83495c635efSGarrett D'Amore ps_printf(p, "<<\n"); 83595c635efSGarrett D'Amore ps_printf(p, "/Size %zu\n", base + 1); 83695c635efSGarrett D'Amore ps_printf(p, "/Root %zu 0 R\n", base); 83795c635efSGarrett D'Amore ps_printf(p, "/Info 1 0 R\n"); 83895c635efSGarrett D'Amore ps_printf(p, ">>\n"); 83995c635efSGarrett D'Amore ps_printf(p, "startxref\n"); 84095c635efSGarrett D'Amore ps_printf(p, "%zu\n", xref); 84195c635efSGarrett D'Amore ps_printf(p, "%%%%EOF\n"); 84295c635efSGarrett D'Amore } 84395c635efSGarrett D'Amore 84495c635efSGarrett D'Amore static void 84595c635efSGarrett D'Amore ps_begin(struct termp *p) 84695c635efSGarrett D'Amore { 84795c635efSGarrett D'Amore int i; 84895c635efSGarrett D'Amore 84995c635efSGarrett D'Amore /* 85095c635efSGarrett D'Amore * Print margins into margin buffer. Nothing gets output to the 85195c635efSGarrett D'Amore * screen yet, so we don't need to initialise the primary state. 85295c635efSGarrett D'Amore */ 85395c635efSGarrett D'Amore 85495c635efSGarrett D'Amore if (p->ps->psmarg) { 85595c635efSGarrett D'Amore assert(p->ps->psmargsz); 85695c635efSGarrett D'Amore p->ps->psmarg[0] = '\0'; 85795c635efSGarrett D'Amore } 85895c635efSGarrett D'Amore 85995c635efSGarrett D'Amore /*p->ps->pdfbytes = 0;*/ 86095c635efSGarrett D'Amore p->ps->psmargcur = 0; 86195c635efSGarrett D'Amore p->ps->flags = PS_MARGINS; 86295c635efSGarrett D'Amore p->ps->pscol = p->ps->left; 86395c635efSGarrett D'Amore p->ps->psrow = p->ps->header; 86495c635efSGarrett D'Amore 86595c635efSGarrett D'Amore ps_setfont(p, TERMFONT_NONE); 86695c635efSGarrett D'Amore 86795c635efSGarrett D'Amore (*p->headf)(p, p->argf); 86895c635efSGarrett D'Amore (*p->endline)(p); 86995c635efSGarrett D'Amore 87095c635efSGarrett D'Amore p->ps->pscol = p->ps->left; 87195c635efSGarrett D'Amore p->ps->psrow = p->ps->footer; 87295c635efSGarrett D'Amore 87395c635efSGarrett D'Amore (*p->footf)(p, p->argf); 87495c635efSGarrett D'Amore (*p->endline)(p); 87595c635efSGarrett D'Amore 87695c635efSGarrett D'Amore p->ps->flags &= ~PS_MARGINS; 87795c635efSGarrett D'Amore 87895c635efSGarrett D'Amore assert(0 == p->ps->flags); 87995c635efSGarrett D'Amore assert(p->ps->psmarg); 88095c635efSGarrett D'Amore assert('\0' != p->ps->psmarg[0]); 88195c635efSGarrett D'Amore 88295c635efSGarrett D'Amore /* 88395c635efSGarrett D'Amore * Print header and initialise page state. Following this, 88495c635efSGarrett D'Amore * stuff gets printed to the screen, so make sure we're sane. 88595c635efSGarrett D'Amore */ 88695c635efSGarrett D'Amore 88795c635efSGarrett D'Amore if (TERMTYPE_PS == p->type) { 88895c635efSGarrett D'Amore ps_printf(p, "%%!PS-Adobe-3.0\n"); 88995c635efSGarrett D'Amore ps_printf(p, "%%%%DocumentData: Clean7Bit\n"); 89095c635efSGarrett D'Amore ps_printf(p, "%%%%Orientation: Portrait\n"); 89195c635efSGarrett D'Amore ps_printf(p, "%%%%Pages: (atend)\n"); 89295c635efSGarrett D'Amore ps_printf(p, "%%%%PageOrder: Ascend\n"); 89395c635efSGarrett D'Amore ps_printf(p, "%%%%DocumentMedia: " 89495c635efSGarrett D'Amore "Default %zu %zu 0 () ()\n", 89595c635efSGarrett D'Amore (size_t)AFM2PNT(p, p->ps->width), 89695c635efSGarrett D'Amore (size_t)AFM2PNT(p, p->ps->height)); 89795c635efSGarrett D'Amore ps_printf(p, "%%%%DocumentNeededResources: font"); 89895c635efSGarrett D'Amore 89995c635efSGarrett D'Amore for (i = 0; i < (int)TERMFONT__MAX; i++) 90095c635efSGarrett D'Amore ps_printf(p, " %s", fonts[i].name); 90195c635efSGarrett D'Amore 90295c635efSGarrett D'Amore ps_printf(p, "\n%%%%EndComments\n"); 90395c635efSGarrett D'Amore } else { 90495c635efSGarrett D'Amore ps_printf(p, "%%PDF-1.1\n"); 90595c635efSGarrett D'Amore pdf_obj(p, 1); 90695c635efSGarrett D'Amore ps_printf(p, "<<\n"); 90795c635efSGarrett D'Amore ps_printf(p, ">>\n"); 90895c635efSGarrett D'Amore ps_printf(p, "endobj\n"); 90995c635efSGarrett D'Amore 91095c635efSGarrett D'Amore for (i = 0; i < (int)TERMFONT__MAX; i++) { 91195c635efSGarrett D'Amore pdf_obj(p, (size_t)i + 3); 91295c635efSGarrett D'Amore ps_printf(p, "<<\n"); 91395c635efSGarrett D'Amore ps_printf(p, "/Type /Font\n"); 91495c635efSGarrett D'Amore ps_printf(p, "/Subtype /Type1\n"); 915260e9a87SYuri Pankov ps_printf(p, "/Name /F%d\n", i); 91695c635efSGarrett D'Amore ps_printf(p, "/BaseFont /%s\n", fonts[i].name); 91795c635efSGarrett D'Amore ps_printf(p, ">>\n"); 91895c635efSGarrett D'Amore } 91995c635efSGarrett D'Amore } 92095c635efSGarrett D'Amore 92195c635efSGarrett D'Amore p->ps->pdfbody = (size_t)TERMFONT__MAX + 3; 92295c635efSGarrett D'Amore p->ps->pscol = p->ps->left; 92395c635efSGarrett D'Amore p->ps->psrow = p->ps->top; 92495c635efSGarrett D'Amore p->ps->flags |= PS_NEWPAGE; 92595c635efSGarrett D'Amore ps_setfont(p, TERMFONT_NONE); 92695c635efSGarrett D'Amore } 92795c635efSGarrett D'Amore 92895c635efSGarrett D'Amore static void 92995c635efSGarrett D'Amore ps_pletter(struct termp *p, int c) 93095c635efSGarrett D'Amore { 93195c635efSGarrett D'Amore int f; 93295c635efSGarrett D'Amore 93395c635efSGarrett D'Amore /* 93495c635efSGarrett D'Amore * If we haven't opened a page context, then output that we're 93595c635efSGarrett D'Amore * in a new page and make sure the font is correctly set. 93695c635efSGarrett D'Amore */ 93795c635efSGarrett D'Amore 93895c635efSGarrett D'Amore if (PS_NEWPAGE & p->ps->flags) { 93995c635efSGarrett D'Amore if (TERMTYPE_PS == p->type) { 94095c635efSGarrett D'Amore ps_printf(p, "%%%%Page: %zu %zu\n", 941260e9a87SYuri Pankov p->ps->pages + 1, p->ps->pages + 1); 94295c635efSGarrett D'Amore ps_printf(p, "/%s %zu selectfont\n", 94395c635efSGarrett D'Amore fonts[(int)p->ps->lastf].name, 94495c635efSGarrett D'Amore p->ps->scale); 94595c635efSGarrett D'Amore } else { 94695c635efSGarrett D'Amore pdf_obj(p, p->ps->pdfbody + 94795c635efSGarrett D'Amore p->ps->pages * 4); 94895c635efSGarrett D'Amore ps_printf(p, "<<\n"); 94995c635efSGarrett D'Amore ps_printf(p, "/Length %zu 0 R\n", 950260e9a87SYuri Pankov p->ps->pdfbody + 1 + p->ps->pages * 4); 95195c635efSGarrett D'Amore ps_printf(p, ">>\nstream\n"); 95295c635efSGarrett D'Amore } 95395c635efSGarrett D'Amore p->ps->pdflastpg = p->ps->pdfbytes; 95495c635efSGarrett D'Amore p->ps->flags &= ~PS_NEWPAGE; 95595c635efSGarrett D'Amore } 95695c635efSGarrett D'Amore 95795c635efSGarrett D'Amore /* 95895c635efSGarrett D'Amore * If we're not in a PostScript "word" context, then open one 95995c635efSGarrett D'Amore * now at the current cursor. 96095c635efSGarrett D'Amore */ 96195c635efSGarrett D'Amore 96295c635efSGarrett D'Amore if ( ! (PS_INLINE & p->ps->flags)) { 96395c635efSGarrett D'Amore if (TERMTYPE_PS != p->type) { 96495c635efSGarrett D'Amore ps_printf(p, "BT\n/F%d %zu Tf\n", 965260e9a87SYuri Pankov (int)p->ps->lastf, p->ps->scale); 96695c635efSGarrett D'Amore ps_printf(p, "%.3f %.3f Td\n(", 96795c635efSGarrett D'Amore AFM2PNT(p, p->ps->pscol), 96895c635efSGarrett D'Amore AFM2PNT(p, p->ps->psrow)); 96995c635efSGarrett D'Amore } else 97095c635efSGarrett D'Amore ps_printf(p, "%.3f %.3f moveto\n(", 97195c635efSGarrett D'Amore AFM2PNT(p, p->ps->pscol), 97295c635efSGarrett D'Amore AFM2PNT(p, p->ps->psrow)); 97395c635efSGarrett D'Amore p->ps->flags |= PS_INLINE; 97495c635efSGarrett D'Amore } 97595c635efSGarrett D'Amore 97695c635efSGarrett D'Amore assert( ! (PS_NEWPAGE & p->ps->flags)); 97795c635efSGarrett D'Amore 97895c635efSGarrett D'Amore /* 97995c635efSGarrett D'Amore * We need to escape these characters as per the PostScript 98095c635efSGarrett D'Amore * specification. We would also escape non-graphable characters 98195c635efSGarrett D'Amore * (like tabs), but none of them would get to this point and 98295c635efSGarrett D'Amore * it's superfluous to abort() on them. 98395c635efSGarrett D'Amore */ 98495c635efSGarrett D'Amore 98595c635efSGarrett D'Amore switch (c) { 986260e9a87SYuri Pankov case '(': 987260e9a87SYuri Pankov case ')': 988260e9a87SYuri Pankov case '\\': 98995c635efSGarrett D'Amore ps_putchar(p, '\\'); 99095c635efSGarrett D'Amore break; 99195c635efSGarrett D'Amore default: 99295c635efSGarrett D'Amore break; 99395c635efSGarrett D'Amore } 99495c635efSGarrett D'Amore 99595c635efSGarrett D'Amore /* Write the character and adjust where we are on the page. */ 99695c635efSGarrett D'Amore 99795c635efSGarrett D'Amore f = (int)p->ps->lastf; 99895c635efSGarrett D'Amore 999260e9a87SYuri Pankov if (c <= 32 || c - 32 >= MAXCHAR) 1000260e9a87SYuri Pankov c = 32; 100195c635efSGarrett D'Amore 100295c635efSGarrett D'Amore ps_putchar(p, (char)c); 100395c635efSGarrett D'Amore c -= 32; 100495c635efSGarrett D'Amore p->ps->pscol += (size_t)fonts[f].gly[c].wx; 100595c635efSGarrett D'Amore } 100695c635efSGarrett D'Amore 100795c635efSGarrett D'Amore static void 100895c635efSGarrett D'Amore ps_pclose(struct termp *p) 100995c635efSGarrett D'Amore { 101095c635efSGarrett D'Amore 101195c635efSGarrett D'Amore /* 101295c635efSGarrett D'Amore * Spit out that we're exiting a word context (this is a 101395c635efSGarrett D'Amore * "partial close" because we don't check the last-char buffer 101495c635efSGarrett D'Amore * or anything). 101595c635efSGarrett D'Amore */ 101695c635efSGarrett D'Amore 101795c635efSGarrett D'Amore if ( ! (PS_INLINE & p->ps->flags)) 101895c635efSGarrett D'Amore return; 101995c635efSGarrett D'Amore 102095c635efSGarrett D'Amore if (TERMTYPE_PS != p->type) { 102195c635efSGarrett D'Amore ps_printf(p, ") Tj\nET\n"); 102295c635efSGarrett D'Amore } else 102395c635efSGarrett D'Amore ps_printf(p, ") show\n"); 102495c635efSGarrett D'Amore 102595c635efSGarrett D'Amore p->ps->flags &= ~PS_INLINE; 102695c635efSGarrett D'Amore } 102795c635efSGarrett D'Amore 102895c635efSGarrett D'Amore static void 102995c635efSGarrett D'Amore ps_fclose(struct termp *p) 103095c635efSGarrett D'Amore { 103195c635efSGarrett D'Amore 103295c635efSGarrett D'Amore /* 103395c635efSGarrett D'Amore * Strong closure: if we have a last-char, spit it out after 103495c635efSGarrett D'Amore * checking that we're in the right font mode. This will of 103595c635efSGarrett D'Amore * course open a new scope, if applicable. 103695c635efSGarrett D'Amore * 103795c635efSGarrett D'Amore * Following this, close out any scope that's open. 103895c635efSGarrett D'Amore */ 103995c635efSGarrett D'Amore 1040260e9a87SYuri Pankov if (p->ps->last != '\0') { 1041260e9a87SYuri Pankov assert( ! (p->ps->flags & PS_BACKSP)); 1042260e9a87SYuri Pankov if (p->ps->nextf != p->ps->lastf) { 104395c635efSGarrett D'Amore ps_pclose(p); 1044260e9a87SYuri Pankov ps_setfont(p, p->ps->nextf); 104595c635efSGarrett D'Amore } 1046260e9a87SYuri Pankov p->ps->nextf = TERMFONT_NONE; 104795c635efSGarrett D'Amore ps_pletter(p, p->ps->last); 104895c635efSGarrett D'Amore p->ps->last = '\0'; 104995c635efSGarrett D'Amore } 105095c635efSGarrett D'Amore 105195c635efSGarrett D'Amore if ( ! (PS_INLINE & p->ps->flags)) 105295c635efSGarrett D'Amore return; 105395c635efSGarrett D'Amore 105495c635efSGarrett D'Amore ps_pclose(p); 105595c635efSGarrett D'Amore } 105695c635efSGarrett D'Amore 105795c635efSGarrett D'Amore static void 105895c635efSGarrett D'Amore ps_letter(struct termp *p, int arg) 105995c635efSGarrett D'Amore { 1060260e9a87SYuri Pankov size_t savecol, wx; 1061260e9a87SYuri Pankov char c; 106295c635efSGarrett D'Amore 106395c635efSGarrett D'Amore c = arg >= 128 || arg <= 0 ? '?' : arg; 106495c635efSGarrett D'Amore 106595c635efSGarrett D'Amore /* 1066260e9a87SYuri Pankov * When receiving a backspace, merely flag it. 1067260e9a87SYuri Pankov * We don't know yet whether it is 1068260e9a87SYuri Pankov * a font instruction or an overstrike. 106995c635efSGarrett D'Amore */ 107095c635efSGarrett D'Amore 1071260e9a87SYuri Pankov if (c == '\b') { 1072260e9a87SYuri Pankov assert(p->ps->last != '\0'); 1073260e9a87SYuri Pankov assert( ! (p->ps->flags & PS_BACKSP)); 1074260e9a87SYuri Pankov p->ps->flags |= PS_BACKSP; 107595c635efSGarrett D'Amore return; 107695c635efSGarrett D'Amore } 107795c635efSGarrett D'Amore 1078260e9a87SYuri Pankov /* 1079260e9a87SYuri Pankov * Decode font instructions. 1080260e9a87SYuri Pankov */ 1081260e9a87SYuri Pankov 1082260e9a87SYuri Pankov if (p->ps->flags & PS_BACKSP) { 1083260e9a87SYuri Pankov if (p->ps->last == '_') { 1084260e9a87SYuri Pankov switch (p->ps->nextf) { 1085260e9a87SYuri Pankov case TERMFONT_BI: 1086260e9a87SYuri Pankov break; 1087260e9a87SYuri Pankov case TERMFONT_BOLD: 1088260e9a87SYuri Pankov p->ps->nextf = TERMFONT_BI; 1089260e9a87SYuri Pankov break; 1090260e9a87SYuri Pankov default: 1091260e9a87SYuri Pankov p->ps->nextf = TERMFONT_UNDER; 1092260e9a87SYuri Pankov } 1093260e9a87SYuri Pankov p->ps->last = c; 1094260e9a87SYuri Pankov p->ps->flags &= ~PS_BACKSP; 1095260e9a87SYuri Pankov return; 1096260e9a87SYuri Pankov } 1097260e9a87SYuri Pankov if (p->ps->last == c) { 1098260e9a87SYuri Pankov switch (p->ps->nextf) { 1099260e9a87SYuri Pankov case TERMFONT_BI: 1100260e9a87SYuri Pankov break; 1101260e9a87SYuri Pankov case TERMFONT_UNDER: 1102260e9a87SYuri Pankov p->ps->nextf = TERMFONT_BI; 1103260e9a87SYuri Pankov break; 1104260e9a87SYuri Pankov default: 1105260e9a87SYuri Pankov p->ps->nextf = TERMFONT_BOLD; 1106260e9a87SYuri Pankov } 1107260e9a87SYuri Pankov p->ps->flags &= ~PS_BACKSP; 1108260e9a87SYuri Pankov return; 110995c635efSGarrett D'Amore } 111095c635efSGarrett D'Amore 1111260e9a87SYuri Pankov /* 1112260e9a87SYuri Pankov * This is not a font instruction, but rather 1113260e9a87SYuri Pankov * the next character. Prepare for overstrike. 1114260e9a87SYuri Pankov */ 1115260e9a87SYuri Pankov 1116260e9a87SYuri Pankov savecol = p->ps->pscol; 1117260e9a87SYuri Pankov } else 1118260e9a87SYuri Pankov savecol = SIZE_MAX; 1119260e9a87SYuri Pankov 1120260e9a87SYuri Pankov /* 1121260e9a87SYuri Pankov * We found the next character, so the font instructions 1122260e9a87SYuri Pankov * for the previous one are complete. 1123260e9a87SYuri Pankov * Use them and print it. 1124260e9a87SYuri Pankov */ 1125260e9a87SYuri Pankov 1126260e9a87SYuri Pankov if (p->ps->last != '\0') { 1127260e9a87SYuri Pankov if (p->ps->nextf != p->ps->lastf) { 1128260e9a87SYuri Pankov ps_pclose(p); 1129260e9a87SYuri Pankov ps_setfont(p, p->ps->nextf); 1130260e9a87SYuri Pankov } 1131260e9a87SYuri Pankov p->ps->nextf = TERMFONT_NONE; 1132260e9a87SYuri Pankov 1133260e9a87SYuri Pankov /* 1134260e9a87SYuri Pankov * For an overstrike, if a previous character 1135260e9a87SYuri Pankov * was wider, advance to center the new one. 1136260e9a87SYuri Pankov */ 1137260e9a87SYuri Pankov 1138260e9a87SYuri Pankov if (p->ps->pscolnext) { 1139260e9a87SYuri Pankov wx = fonts[p->ps->lastf].gly[(int)p->ps->last-32].wx; 1140260e9a87SYuri Pankov if (p->ps->pscol + wx < p->ps->pscolnext) 1141260e9a87SYuri Pankov p->ps->pscol = (p->ps->pscol + 1142260e9a87SYuri Pankov p->ps->pscolnext - wx) / 2; 1143260e9a87SYuri Pankov } 1144260e9a87SYuri Pankov 1145260e9a87SYuri Pankov ps_pletter(p, p->ps->last); 1146260e9a87SYuri Pankov 1147260e9a87SYuri Pankov /* 1148260e9a87SYuri Pankov * For an overstrike, if a previous character 1149260e9a87SYuri Pankov * was wider, advance to the end of the old one. 1150260e9a87SYuri Pankov */ 1151260e9a87SYuri Pankov 1152260e9a87SYuri Pankov if (p->ps->pscol < p->ps->pscolnext) { 1153260e9a87SYuri Pankov ps_pclose(p); 1154260e9a87SYuri Pankov p->ps->pscol = p->ps->pscolnext; 1155260e9a87SYuri Pankov } 1156260e9a87SYuri Pankov } 1157260e9a87SYuri Pankov 1158260e9a87SYuri Pankov /* 1159260e9a87SYuri Pankov * Do not print the current character yet because font 1160260e9a87SYuri Pankov * instructions might follow; only remember it. 1161260e9a87SYuri Pankov * For the first character, nothing else is done. 1162260e9a87SYuri Pankov * The final character will get printed from ps_fclose(). 1163260e9a87SYuri Pankov */ 1164260e9a87SYuri Pankov 1165260e9a87SYuri Pankov p->ps->last = c; 1166260e9a87SYuri Pankov 1167260e9a87SYuri Pankov /* 1168260e9a87SYuri Pankov * For an overstrike, back up to the previous position. 1169260e9a87SYuri Pankov * If the previous character is wider than any it overstrikes, 1170260e9a87SYuri Pankov * remember the current position, because it might also be 1171260e9a87SYuri Pankov * wider than all that will overstrike it. 1172260e9a87SYuri Pankov */ 1173260e9a87SYuri Pankov 1174260e9a87SYuri Pankov if (savecol != SIZE_MAX) { 1175260e9a87SYuri Pankov if (p->ps->pscolnext < p->ps->pscol) 1176260e9a87SYuri Pankov p->ps->pscolnext = p->ps->pscol; 1177260e9a87SYuri Pankov ps_pclose(p); 1178260e9a87SYuri Pankov p->ps->pscol = savecol; 1179260e9a87SYuri Pankov p->ps->flags &= ~PS_BACKSP; 1180260e9a87SYuri Pankov } else 1181260e9a87SYuri Pankov p->ps->pscolnext = 0; 1182260e9a87SYuri Pankov } 118395c635efSGarrett D'Amore 118495c635efSGarrett D'Amore static void 118595c635efSGarrett D'Amore ps_advance(struct termp *p, size_t len) 118695c635efSGarrett D'Amore { 118795c635efSGarrett D'Amore 118895c635efSGarrett D'Amore /* 118995c635efSGarrett D'Amore * Advance some spaces. This can probably be made smarter, 119095c635efSGarrett D'Amore * i.e., to have multiple space-separated words in the same 119195c635efSGarrett D'Amore * scope, but this is easier: just close out the current scope 119295c635efSGarrett D'Amore * and readjust our column settings. 119395c635efSGarrett D'Amore */ 119495c635efSGarrett D'Amore 119595c635efSGarrett D'Amore ps_fclose(p); 119695c635efSGarrett D'Amore p->ps->pscol += len; 119795c635efSGarrett D'Amore } 119895c635efSGarrett D'Amore 119995c635efSGarrett D'Amore static void 120095c635efSGarrett D'Amore ps_endline(struct termp *p) 120195c635efSGarrett D'Amore { 120295c635efSGarrett D'Amore 120395c635efSGarrett D'Amore /* Close out any scopes we have open: we're at eoln. */ 120495c635efSGarrett D'Amore 120595c635efSGarrett D'Amore ps_fclose(p); 120695c635efSGarrett D'Amore 120795c635efSGarrett D'Amore /* 120895c635efSGarrett D'Amore * If we're in the margin, don't try to recalculate our current 120995c635efSGarrett D'Amore * row. XXX: if the column tries to be fancy with multiple 121095c635efSGarrett D'Amore * lines, we'll do nasty stuff. 121195c635efSGarrett D'Amore */ 121295c635efSGarrett D'Amore 121395c635efSGarrett D'Amore if (PS_MARGINS & p->ps->flags) 121495c635efSGarrett D'Amore return; 121595c635efSGarrett D'Amore 121695c635efSGarrett D'Amore /* Left-justify. */ 121795c635efSGarrett D'Amore 121895c635efSGarrett D'Amore p->ps->pscol = p->ps->left; 121995c635efSGarrett D'Amore 122095c635efSGarrett D'Amore /* If we haven't printed anything, return. */ 122195c635efSGarrett D'Amore 122295c635efSGarrett D'Amore if (PS_NEWPAGE & p->ps->flags) 122395c635efSGarrett D'Amore return; 122495c635efSGarrett D'Amore 122595c635efSGarrett D'Amore /* 122695c635efSGarrett D'Amore * Put us down a line. If we're at the page bottom, spit out a 122795c635efSGarrett D'Amore * showpage and restart our row. 122895c635efSGarrett D'Amore */ 122995c635efSGarrett D'Amore 1230260e9a87SYuri Pankov if (p->ps->psrow >= p->ps->lineheight + p->ps->bottom) { 123195c635efSGarrett D'Amore p->ps->psrow -= p->ps->lineheight; 123295c635efSGarrett D'Amore return; 123395c635efSGarrett D'Amore } 123495c635efSGarrett D'Amore 123595c635efSGarrett D'Amore ps_closepage(p); 123695c635efSGarrett D'Amore } 123795c635efSGarrett D'Amore 123895c635efSGarrett D'Amore static void 123995c635efSGarrett D'Amore ps_setfont(struct termp *p, enum termfont f) 124095c635efSGarrett D'Amore { 124195c635efSGarrett D'Amore 124295c635efSGarrett D'Amore assert(f < TERMFONT__MAX); 124395c635efSGarrett D'Amore p->ps->lastf = f; 124495c635efSGarrett D'Amore 124595c635efSGarrett D'Amore /* 124695c635efSGarrett D'Amore * If we're still at the top of the page, let the font-setting 124795c635efSGarrett D'Amore * be delayed until we actually have stuff to print. 124895c635efSGarrett D'Amore */ 124995c635efSGarrett D'Amore 125095c635efSGarrett D'Amore if (PS_NEWPAGE & p->ps->flags) 125195c635efSGarrett D'Amore return; 125295c635efSGarrett D'Amore 125395c635efSGarrett D'Amore if (TERMTYPE_PS == p->type) 125495c635efSGarrett D'Amore ps_printf(p, "/%s %zu selectfont\n", 1255260e9a87SYuri Pankov fonts[(int)f].name, p->ps->scale); 125695c635efSGarrett D'Amore else 125795c635efSGarrett D'Amore ps_printf(p, "/F%d %zu Tf\n", 1258260e9a87SYuri Pankov (int)f, p->ps->scale); 125995c635efSGarrett D'Amore } 126095c635efSGarrett D'Amore 126195c635efSGarrett D'Amore static size_t 126295c635efSGarrett D'Amore ps_width(const struct termp *p, int c) 126395c635efSGarrett D'Amore { 126495c635efSGarrett D'Amore 126595c635efSGarrett D'Amore if (c <= 32 || c - 32 >= MAXCHAR) 1266260e9a87SYuri Pankov c = 0; 1267260e9a87SYuri Pankov else 126895c635efSGarrett D'Amore c -= 32; 1269260e9a87SYuri Pankov 1270*371584c2SYuri Pankov return (size_t)fonts[(int)TERMFONT_NONE].gly[c].wx; 127195c635efSGarrett D'Amore } 127295c635efSGarrett D'Amore 1273*371584c2SYuri Pankov static int 127495c635efSGarrett D'Amore ps_hspan(const struct termp *p, const struct roffsu *su) 127595c635efSGarrett D'Amore { 127695c635efSGarrett D'Amore double r; 127795c635efSGarrett D'Amore 127895c635efSGarrett D'Amore /* 127995c635efSGarrett D'Amore * All of these measurements are derived by converting from the 128095c635efSGarrett D'Amore * native measurement to AFM units. 128195c635efSGarrett D'Amore */ 128295c635efSGarrett D'Amore switch (su->unit) { 1283260e9a87SYuri Pankov case SCALE_BU: 1284260e9a87SYuri Pankov /* 1285260e9a87SYuri Pankov * Traditionally, the default unit is fixed to the 1286260e9a87SYuri Pankov * output media. So this would refer to the point. In 1287260e9a87SYuri Pankov * mandoc(1), however, we stick to the default terminal 1288260e9a87SYuri Pankov * scaling unit so that output is the same regardless 1289260e9a87SYuri Pankov * the media. 1290260e9a87SYuri Pankov */ 1291260e9a87SYuri Pankov r = PNT2AFM(p, su->scale * 72.0 / 240.0); 129295c635efSGarrett D'Amore break; 1293260e9a87SYuri Pankov case SCALE_CM: 1294260e9a87SYuri Pankov r = PNT2AFM(p, su->scale * 72.0 / 2.54); 129595c635efSGarrett D'Amore break; 1296260e9a87SYuri Pankov case SCALE_EM: 129795c635efSGarrett D'Amore r = su->scale * 129895c635efSGarrett D'Amore fonts[(int)TERMFONT_NONE].gly[109 - 32].wx; 129995c635efSGarrett D'Amore break; 1300260e9a87SYuri Pankov case SCALE_EN: 130195c635efSGarrett D'Amore r = su->scale * 130295c635efSGarrett D'Amore fonts[(int)TERMFONT_NONE].gly[110 - 32].wx; 130395c635efSGarrett D'Amore break; 1304260e9a87SYuri Pankov case SCALE_IN: 1305260e9a87SYuri Pankov r = PNT2AFM(p, su->scale * 72.0); 1306260e9a87SYuri Pankov break; 1307260e9a87SYuri Pankov case SCALE_MM: 1308260e9a87SYuri Pankov r = su->scale * 1309260e9a87SYuri Pankov fonts[(int)TERMFONT_NONE].gly[109 - 32].wx / 100.0; 1310260e9a87SYuri Pankov break; 1311260e9a87SYuri Pankov case SCALE_PC: 1312260e9a87SYuri Pankov r = PNT2AFM(p, su->scale * 12.0); 1313260e9a87SYuri Pankov break; 1314260e9a87SYuri Pankov case SCALE_PT: 1315260e9a87SYuri Pankov r = PNT2AFM(p, su->scale * 1.0); 1316260e9a87SYuri Pankov break; 1317260e9a87SYuri Pankov case SCALE_VS: 131895c635efSGarrett D'Amore r = su->scale * p->ps->lineheight; 131995c635efSGarrett D'Amore break; 132095c635efSGarrett D'Amore default: 132195c635efSGarrett D'Amore r = su->scale; 132295c635efSGarrett D'Amore break; 132395c635efSGarrett D'Amore } 132495c635efSGarrett D'Amore 1325*371584c2SYuri Pankov return r * 24.0; 132695c635efSGarrett D'Amore } 132795c635efSGarrett D'Amore 132895c635efSGarrett D'Amore static void 132995c635efSGarrett D'Amore ps_growbuf(struct termp *p, size_t sz) 133095c635efSGarrett D'Amore { 133195c635efSGarrett D'Amore if (p->ps->psmargcur + sz <= p->ps->psmargsz) 133295c635efSGarrett D'Amore return; 133395c635efSGarrett D'Amore 133495c635efSGarrett D'Amore if (sz < PS_BUFSLOP) 133595c635efSGarrett D'Amore sz = PS_BUFSLOP; 133695c635efSGarrett D'Amore 133795c635efSGarrett D'Amore p->ps->psmargsz += sz; 1338260e9a87SYuri Pankov p->ps->psmarg = mandoc_realloc(p->ps->psmarg, p->ps->psmargsz); 133995c635efSGarrett D'Amore } 1340