diff options
author | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2010-06-29 14:41:29 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2010-06-29 14:41:29 +0000 |
commit | 4c125d4843c8bded68b7b31900797d1f080a0af0 (patch) | |
tree | af9cfc372ed16e6dd8f372aa738e92d9bac7959a | |
parent | a2dcc33cf8bf19857bd5a12a68cb8e19b34f2fae (diff) |
framework for glyph width encoding; from kristaps@
-rw-r--r-- | usr.bin/mandoc/mandoc.1 | 24 | ||||
-rw-r--r-- | usr.bin/mandoc/term.c | 61 | ||||
-rw-r--r-- | usr.bin/mandoc/term.h | 21 | ||||
-rw-r--r-- | usr.bin/mandoc/term_ps.c | 431 |
4 files changed, 460 insertions, 77 deletions
diff --git a/usr.bin/mandoc/mandoc.1 b/usr.bin/mandoc/mandoc.1 index 4d9398f9e19..610960feae9 100644 --- a/usr.bin/mandoc/mandoc.1 +++ b/usr.bin/mandoc/mandoc.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: mandoc.1,v 1.32 2010/06/26 17:56:43 schwarze Exp $ +.\" $OpenBSD: mandoc.1,v 1.33 2010/06/29 14:41:28 schwarze Exp $ .\" .\" Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv> .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: June 26 2010 $ +.Dd $Mdocdate: June 29 2010 $ .Dt MANDOC 1 .Os .Sh NAME @@ -211,9 +211,11 @@ The .Fl T Ns Ar html and .Fl T Ns Ar xhtml -modes accept the following output options: +modes accept the following +.Fl O +arguments: .Bl -tag -width Ds -.It Fl O Ns Cm includes Ns = Ns Ar fmt +.It Cm includes Ns = Ns Ar fmt The string .Ar fmt , for example, @@ -226,7 +228,7 @@ Instances of are replaced with the include filename. The default is not to present a hyperlink. -.It Fl O Ns Cm man Ns = Ns Ar fmt +.It Cm man Ns = Ns Ar fmt The string .Ar fmt , for example, @@ -242,7 +244,7 @@ are replaced with the linked manual's name and section, respectively. If no section is included, section 1 is assumed. The default is not to present a hyperlink. -.It Fl O Ns Cm style Ns = Ns Ar style.css +.It Cm style Ns = Ns Ar style.css The file .Ar style.css is used for an external style-sheet. @@ -252,9 +254,11 @@ relative URI. .Pp The .Fl T Ns Ar ascii -mode accepts the following output option: +mode accepts the following +.Fl O +argument: .Bl -tag -width Ds -.It Fl O Ns Cm width Ns = Ns Ar width +.It Cm width Ns = Ns Ar width The output width is set to .Ar width , which will normalise to \(>=60. @@ -348,7 +352,9 @@ cause rendered documents to appear as they do in .Pp Special characters are rendered in decimal-encoded UTF-8. .Ss PostScript Output -PostScript Level 2 pages may be generated by +PostScript +.Qq Adobe-3.0 +Level-2 pages may be generated by .Fl T Ns Cm ps . Output pages are US-letter sized (215.9 x 279.4 mm) and rendered in fixed, 10-point Courier font. diff --git a/usr.bin/mandoc/term.c b/usr.bin/mandoc/term.c index 408d9916505..df88fa918dc 100644 --- a/usr.bin/mandoc/term.c +++ b/usr.bin/mandoc/term.c @@ -1,4 +1,4 @@ -/* $Id: term.c,v 1.41 2010/06/27 21:54:42 schwarze Exp $ */ +/* $Id: term.c,v 1.42 2010/06/29 14:41:28 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -129,9 +129,10 @@ term_flushln(struct termp *p) size_t vbl; /* number of blanks to prepend to output */ size_t vend; /* end of word visual position on output */ size_t bp; /* visual right border position */ - int j; /* temporary loop index */ - int jhy; /* last hyphen before line overflow */ - size_t maxvis, mmax; + int j; /* temporary loop index for p->buf */ + int jhy; /* last hyph before overflow w/r/t j */ + size_t maxvis; /* output position of visible boundary */ + size_t mmax; /* used in calculating bp */ /* * First, establish the maximum columns of "visible" content. @@ -156,21 +157,17 @@ term_flushln(struct termp *p) */ vbl = p->flags & TERMP_NOLPAD ? 0 : p->offset; - /* - * FIXME: if bp is zero, we still output the first word before - * breaking the line. - */ - vis = vend = i = 0; - while (i < (int)p->col) { + while (i < (int)p->col) { /* - * Handle literal tab characters. + * Handle literal tab characters: collapse all + * subsequent tabs into a single huge set of spaces. */ for (j = i; j < (int)p->col; j++) { if ('\t' != p->buf[j]) break; - vend = (vis/p->tabwidth+1)*p->tabwidth; + vend = (vis / p->tabwidth + 1) * p->tabwidth; vbl += vend - vis; vis = vend; } @@ -186,13 +183,21 @@ term_flushln(struct termp *p) for (jhy = 0; j < (int)p->col; j++) { if ((j && ' ' == p->buf[j]) || '\t' == p->buf[j]) break; - if (8 != p->buf[j]) { - if (vend > vis && vend < bp && - ASCII_HYPH == p->buf[j]) - jhy = j; - vend++; - } else - vend--; + + /* Back over the the last printed character. */ + if (8 == p->buf[j]) { + assert(j); + vend -= (*p->width)(p, p->buf[j - 1]); + continue; + } + + /* Regular word. */ + /* Break at the hyphen point if we overrun. */ + if (vend > vis && vend < bp && + ASCII_HYPH == p->buf[j]) + jhy = j; + + vend += (*p->width)(p, p->buf[j]); } /* @@ -232,13 +237,13 @@ term_flushln(struct termp *p) break; if (' ' == p->buf[i]) { while (' ' == p->buf[i]) { - vbl++; + vbl += (*p->width)(p, p->buf[i]); i++; } break; } if (ASCII_NBRSP == p->buf[i]) { - vbl++; + vbl += (*p->width)(p, ' '); continue; } @@ -253,12 +258,13 @@ term_flushln(struct termp *p) vbl = 0; } - if (ASCII_HYPH == p->buf[i]) + if (ASCII_HYPH == p->buf[i]) { (*p->letter)(p, '-'); - else + p->viscol += (*p->width)(p, '-'); + } else { (*p->letter)(p, p->buf[i]); - - p->viscol += 1; + p->viscol += (*p->width)(p, p->buf[i]); + } } vend += vbl; vis = vend; @@ -276,7 +282,7 @@ term_flushln(struct termp *p) if (TERMP_HANG & p->flags) { /* We need one blank after the tag. */ p->overstep = /* LINTED */ - vis - maxvis + 1; + vis - maxvis + (*p->width)(p, ' '); /* * Behave exactly the same way as groff: @@ -300,7 +306,8 @@ term_flushln(struct termp *p) /* Right-pad. */ if (maxvis > vis + /* LINTED */ - ((TERMP_TWOSPACE & p->flags) ? 1 : 0)) { + ((TERMP_TWOSPACE & p->flags) ? + (*p->width)(p, ' ') : 0)) { p->viscol += maxvis - vis; (*p->advance)(p, maxvis - vis); vis += (maxvis - vis); diff --git a/usr.bin/mandoc/term.h b/usr.bin/mandoc/term.h index 7273a39ef59..726915f3ec4 100644 --- a/usr.bin/mandoc/term.h +++ b/usr.bin/mandoc/term.h @@ -1,4 +1,4 @@ -/* $Id: term.h,v 1.23 2010/06/27 01:24:02 schwarze Exp $ */ +/* $Id: term.h,v 1.24 2010/06/29 14:41:28 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -33,7 +33,8 @@ enum termtype { enum termfont { TERMFONT_NONE = 0, TERMFONT_BOLD, - TERMFONT_UNDER + TERMFONT_UNDER, + TERMFONT__MAX }; #define TERM_MAXMARGIN 100000 /* FIXME */ @@ -44,14 +45,22 @@ struct termp_ps { int psstate; /* state of ps output */ #define PS_INLINE (1 << 0) /* we're in a word */ #define PS_MARGINS (1 << 1) /* we're in the margins */ - size_t pscol; /* visible column */ - size_t psrow; /* visible row */ + size_t pscol; /* visible column (points) */ + size_t psrow; /* visible row (points) */ char *psmarg; /* margin buf */ size_t psmargsz; /* margin buf size */ - size_t psmargcur; /* current pos in margin buf */ - size_t pspage; /* current page */ + size_t psmargcur; /* cur index in margin buf */ char last; /* character buffer */ enum termfont lastf; /* last set font */ + size_t pages; /* number of pages shown */ + size_t lineheight; /* each line's height (points) */ + size_t top; /* body top (points) */ + size_t bottom; /* body bottom (points) */ + size_t height; /* total height (points) */ + size_t width; /* total width (points) */ + size_t left; /* body left (points) */ + size_t header; /* header position (points) */ + size_t footer; /* footer position (points) */ }; struct termp { diff --git a/usr.bin/mandoc/term_ps.c b/usr.bin/mandoc/term_ps.c index 0ac3753b239..3f134a46151 100644 --- a/usr.bin/mandoc/term_ps.c +++ b/usr.bin/mandoc/term_ps.c @@ -1,4 +1,4 @@ -/* $Id: term_ps.c,v 1.3 2010/06/26 19:08:00 schwarze Exp $ */ +/* $Id: term_ps.c,v 1.4 2010/06/29 14:41:28 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -25,19 +25,323 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include "out.h" #include "main.h" #include "term.h" -#define PS_CHAR_WIDTH 6 -#define PS_CHAR_HEIGHT 12 -#define PS_CHAR_TOPMARG (792 - 24) -#define PS_CHAR_TOP (PS_CHAR_TOPMARG - 36) -#define PS_CHAR_LEFT 36 -#define PS_CHAR_BOTMARG 24 -#define PS_CHAR_BOT (PS_CHAR_BOTMARG + 36) +struct glyph { + int wx; /* WX in AFM */ +}; +struct font { + const char *name; /* FontName in AFM */ +#define MAXCHAR 95 /* total characters we can handle */ + struct glyph gly[MAXCHAR]; /* glyph metrics */ +}; + +/* + * We define, for the time being, three fonts: bold, oblique/italic, and + * normal (roman). The following table hard-codes the font metrics for + * ASCII, i.e., 32--127. + */ + +static const struct font fonts[TERMFONT__MAX] = { + { "Courier", { + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + } }, + { "Courier-Bold", { + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + } }, + { "Courier-Oblique", { + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + { 600 }, + } }, +}; + +/* These work the buffer used by the header and footer. */ #define PS_BUFSLOP 128 #define PS_GROWBUF(p, sz) \ do if ((p)->engine.ps.psmargcur + (sz) > \ @@ -62,7 +366,7 @@ static void ps_endline(struct termp *); static void ps_fclose(struct termp *); static size_t ps_width(const struct termp *, char); static void ps_pclose(struct termp *); -static void ps_pletter(struct termp *, char); +static void ps_pletter(struct termp *, int); static void ps_printf(struct termp *, const char *, ...); static void ps_putchar(struct termp *, char); static void ps_setfont(struct termp *, enum termfont); @@ -72,12 +376,14 @@ void * ps_alloc(void) { struct termp *p; + size_t pagex, pagey, margin; if (NULL == (p = term_alloc(TERMENC_ASCII))) return(NULL); - p->defrmargin = 78; - p->tabwidth = 5; + pagex = 612; + pagey = 792; + margin = 72; p->type = TERMTYPE_PS; p->letter = ps_letter; @@ -86,6 +392,20 @@ ps_alloc(void) p->advance = ps_advance; p->endline = ps_endline; p->width = ps_width; + + assert(margin * 2 < pagex); + assert(margin * 2 < pagey); + + p->engine.ps.width = pagex; + p->engine.ps.height = pagey; + p->engine.ps.header = pagey - (margin / 2); + p->engine.ps.top = pagey - margin; + p->engine.ps.footer = (margin / 2); + p->engine.ps.bottom = margin; + p->engine.ps.left = margin; + p->engine.ps.lineheight = 12; + + p->defrmargin = pagex - (margin * 2); return(p); } @@ -175,14 +495,20 @@ ps_end(struct termp *p) assert('\0' == p->engine.ps.last); assert(p->engine.ps.psmarg && p->engine.ps.psmarg[0]); printf("%s", p->engine.ps.psmarg); + p->engine.ps.pages++; printf("showpage\n"); - printf("%s\n", "%%EOF"); + + printf("%%%%Trailer\n"); + printf("%%%%Pages: %zu\n", p->engine.ps.pages); + printf("%%%%EOF\n"); } static void ps_begin(struct termp *p) { + time_t t; + int i; /* * Print margins into margin buffer. Nothing gets output to the @@ -196,16 +522,16 @@ ps_begin(struct termp *p) p->engine.ps.psmargcur = 0; p->engine.ps.psstate = PS_MARGINS; - p->engine.ps.pscol = PS_CHAR_LEFT; - p->engine.ps.psrow = PS_CHAR_TOPMARG; + p->engine.ps.pscol = p->engine.ps.left; + p->engine.ps.psrow = p->engine.ps.header; ps_setfont(p, TERMFONT_NONE); (*p->headf)(p, p->argf); (*p->endline)(p); - p->engine.ps.pscol = PS_CHAR_LEFT; - p->engine.ps.psrow = PS_CHAR_BOTMARG; + p->engine.ps.pscol = p->engine.ps.left; + p->engine.ps.psrow = p->engine.ps.footer; (*p->footf)(p, p->argf); (*p->endline)(p); @@ -221,16 +547,38 @@ ps_begin(struct termp *p) * stuff gets printed to the screen, so make sure we're sane. */ - printf("%s\n", "%!PS"); + t = time(NULL); + + printf("%%!PS-Adobe-3.0\n"); + printf("%%%%Creator: mandoc-%s\n", VERSION); + printf("%%%%CreationDate: %s", ctime(&t)); + printf("%%%%DocumentData: Clean7Bit\n"); + printf("%%%%Orientation: Portrait\n"); + printf("%%%%Pages: (atend)\n"); + printf("%%%%PageOrder: Ascend\n"); + printf("%%%%Orientation: Portrait\n"); + printf("%%%%DocumentMedia: Default %zu %zu 0 () ()\n", + p->engine.ps.width, + p->engine.ps.height); + printf("%%%%DocumentNeededResources: font"); + for (i = 0; i < (int)TERMFONT__MAX; i++) + printf(" %s", fonts[i].name); + printf("\n%%%%EndComments\n"); + + printf("%%%%Page: %zu %zu\n", + p->engine.ps.pages + 1, + p->engine.ps.pages + 1); + ps_setfont(p, TERMFONT_NONE); - p->engine.ps.pscol = PS_CHAR_LEFT; - p->engine.ps.psrow = PS_CHAR_TOP; + p->engine.ps.pscol = p->engine.ps.left; + p->engine.ps.psrow = p->engine.ps.top; } static void -ps_pletter(struct termp *p, char c) +ps_pletter(struct termp *p, int c) { + int f; /* * If we're not in a PostScript "word" context, then open one @@ -265,8 +613,17 @@ ps_pletter(struct termp *p, char c) /* Write the character and adjust where we are on the page. */ + f = (int)p->engine.ps.lastf; + + if (c <= 32 || (c - 32 > MAXCHAR)) { + ps_putchar(p, ' '); + p->engine.ps.pscol += (fonts[f].gly[0].wx / 100); + return; + } + ps_putchar(p, c); - p->engine.ps.pscol += PS_CHAR_WIDTH; + c -= 32; + p->engine.ps.pscol += (fonts[f].gly[c].wx / 100); } @@ -376,7 +733,7 @@ ps_advance(struct termp *p, size_t len) */ ps_fclose(p); - p->engine.ps.pscol += len ? len * PS_CHAR_WIDTH : 0; + p->engine.ps.pscol += len; } @@ -402,16 +759,21 @@ ps_endline(struct termp *p) * showpage and restart our row. */ - p->engine.ps.pscol = PS_CHAR_LEFT; - if (p->engine.ps.psrow >= PS_CHAR_HEIGHT + PS_CHAR_BOT) { - p->engine.ps.psrow -= PS_CHAR_HEIGHT; + p->engine.ps.pscol = p->engine.ps.left; + if (p->engine.ps.psrow >= p->engine.ps.lineheight + + p->engine.ps.bottom) { + p->engine.ps.psrow -= p->engine.ps.lineheight; return; } assert(p->engine.ps.psmarg && p->engine.ps.psmarg[0]); printf("%s", p->engine.ps.psmarg); + printf("%%%%Page: %zu %zu\n", + p->engine.ps.pages + 1, + p->engine.ps.pages + 1); printf("showpage\n"); - p->engine.ps.psrow = PS_CHAR_TOP; + p->engine.ps.pages++; + p->engine.ps.psrow = p->engine.ps.top; } @@ -419,21 +781,20 @@ static void ps_setfont(struct termp *p, enum termfont f) { - if (TERMFONT_BOLD == f) - ps_printf(p, "/Courier-Bold\n"); - else if (TERMFONT_UNDER == f) - ps_printf(p, "/Courier-Oblique\n"); - else - ps_printf(p, "/Courier\n"); - - ps_printf(p, "10 selectfont\n"); + assert(f < TERMFONT__MAX); + ps_printf(p, "/%s 10 selectfont\n", fonts[(int)f].name); p->engine.ps.lastf = f; } +/* ARGSUSED */ static size_t ps_width(const struct termp *p, char c) { - return(1); + if (c <= 32 || c - 32 >= MAXCHAR) + return(fonts[(int)TERMFONT_NONE].gly[0].wx / 100); + + c -= 32; + return(fonts[(int)TERMFONT_NONE].gly[(int)c].wx / 100); } |