diff options
Diffstat (limited to 'src/devices/grodvi')
-rw-r--r-- | src/devices/grodvi/dvi.cpp | 988 | ||||
-rw-r--r-- | src/devices/grodvi/grodvi.1.man | 633 | ||||
-rw-r--r-- | src/devices/grodvi/grodvi.am | 32 |
3 files changed, 1653 insertions, 0 deletions
diff --git a/src/devices/grodvi/dvi.cpp b/src/devices/grodvi/dvi.cpp new file mode 100644 index 0000000..f9e8a57 --- /dev/null +++ b/src/devices/grodvi/dvi.cpp @@ -0,0 +1,988 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <assert.h> + +#include "driver.h" +#include "nonposix.h" +#include "paper.h" + +extern "C" const char *Version_string; + +#define DEFAULT_LINEWIDTH 40 +static int linewidth = DEFAULT_LINEWIDTH; + +static int draw_flag = 1; + +static int landscape_flag = 0; +static double user_paper_length = 0; +static double user_paper_width = 0; + +/* These values were chosen because: + +(MULTIPLIER*SIZESCALE)/(RES*UNITWIDTH) == 1/(2^20 * 72.27) + +and 57816 is an exact multiple of both 72.27*SIZESCALE and 72. + +The width in the groff font file is the product of MULTIPLIER and the +width in the tfm file. */ + +#define RES 57816 +#define RES_7227 (RES/7227) +#define UNITWIDTH 131072 +#define SIZESCALE 100 +#define MULTIPLIER 1 + +class dvi_font : public font { + dvi_font(const char *); +public: + int checksum; + int design_size; + ~dvi_font(); + void handle_unknown_font_command(const char *command, const char *arg, + const char *filename, int lineno); + static dvi_font *load_dvi_font(const char *); +}; + +dvi_font *dvi_font::load_dvi_font(const char *s) +{ + dvi_font *f = new dvi_font(s); + if (!f->load()) { + delete f; + return 0; + } + return f; +} + +dvi_font::dvi_font(const char *nm) +: font(nm), checksum(0), design_size(0) +{ +} + +dvi_font::~dvi_font() +{ +} + +void dvi_font::handle_unknown_font_command(const char *command, + const char *arg, + const char *filename, int lineno) +{ + char *ptr; + if (strcmp(command, "checksum") == 0) { + if (arg == 0) + fatal_with_file_and_line(filename, lineno, + "'checksum' command requires an argument"); + checksum = int(strtol(arg, &ptr, 10)); + if (checksum == 0 && ptr == arg) { + fatal_with_file_and_line(filename, lineno, "bad checksum"); + } + } + else if (strcmp(command, "designsize") == 0) { + if (arg == 0) + fatal_with_file_and_line(filename, lineno, + "'designsize' command requires an argument"); + design_size = int(strtol(arg, &ptr, 10)); + if (design_size == 0 && ptr == arg) { + fatal_with_file_and_line(filename, lineno, "bad design size"); + } + } +} + +#define FONTS_MAX 256 + +struct output_font { + dvi_font *f; + int point_size; + output_font() : f(0) { } +}; + +class dvi_printer : public printer { + FILE *fp; + int max_drift; + int byte_count; + int last_bop; + int page_count; + int cur_h; + int cur_v; + int end_h; + int max_h; + int max_v; + output_font output_font_table[FONTS_MAX]; + font *cur_font; + int cur_point_size; + color cur_color; + int pushed; + int pushed_h; + int pushed_v; + int have_pushed; + void preamble(); + void postamble(); + void define_font(int); + void set_font(int); + void possibly_begin_line(); + void set_color(color *); +protected: + enum { + id_byte = 2, + set1 = 128, + put1 = 133, + put_rule = 137, + bop = 139, + eop = 140, + push = 141, + pop = 142, + right1 = 143, + down1 = 157, + fnt_num_0 = 171, + fnt1 = 235, + xxx1 = 239, + fnt_def1 = 243, + pre = 247, + post = 248, + post_post = 249, + filler = 223 + }; + int line_thickness; + + void out1(int); + void out2(int); + void out3(int); + void out4(int); + void moveto(int, int); + void out_string(const char *); + void out_signed(unsigned char, int); + void out_unsigned(unsigned char, int); + void do_special(const char *); +public: + dvi_printer(); + ~dvi_printer(); + font *make_font(const char *); + void begin_page(int); + void end_page(int); + void set_char(glyph *, font *, const environment *, int, const char *); + void special(char *, const environment *, char); + void end_of_line(); + void draw(int, int *, int, const environment *); +}; + + +class draw_dvi_printer : public dvi_printer { + int output_pen_size; + void set_line_thickness(const environment *); + void fill_next(const environment *); +public: + draw_dvi_printer(); + ~draw_dvi_printer(); + void draw(int code, int *p, int np, const environment *env); + void end_page(int); +}; + +dvi_printer::dvi_printer() +: fp(stdout), byte_count(0), last_bop(-1), page_count(0), max_h(0), max_v(0), + cur_font(0), cur_point_size(-1), pushed(0), line_thickness(-1) +{ + if (font::res != RES) + fatal("resolution must be %1", RES); + if (font::unitwidth != UNITWIDTH) + fatal("unitwidth must be %1", UNITWIDTH); + if (font::hor != 1) + fatal("hor must be equal to 1"); + if (font::vert != 1) + fatal("vert must be equal to 1"); + if (font::sizescale != SIZESCALE) + fatal("sizescale must be equal to %1", SIZESCALE); + max_drift = font::res/1000; // this is fairly arbitrary + preamble(); +} + +dvi_printer::~dvi_printer() +{ + postamble(); +} + + +draw_dvi_printer::draw_dvi_printer() +: output_pen_size(-1) +{ +} + +draw_dvi_printer::~draw_dvi_printer() +{ +} + + +void dvi_printer::out1(int n) +{ + byte_count += 1; + putc(n & 0xff, fp); +} + +void dvi_printer::out2(int n) +{ + byte_count += 2; + putc((n >> 8) & 0xff, fp); + putc(n & 0xff, fp); +} + +void dvi_printer::out3(int n) +{ + byte_count += 3; + putc((n >> 16) & 0xff, fp); + putc((n >> 8) & 0xff, fp); + putc(n & 0xff, fp); +} + +void dvi_printer::out4(int n) +{ + byte_count += 4; + putc((n >> 24) & 0xff, fp); + putc((n >> 16) & 0xff, fp); + putc((n >> 8) & 0xff, fp); + putc(n & 0xff, fp); +} + +void dvi_printer::out_string(const char *s) +{ + out1(strlen(s)); + while (*s != 0) + out1(*s++); +} + + +void dvi_printer::end_of_line() +{ + if (pushed) { + out1(pop); + pushed = 0; + cur_h = pushed_h; + cur_v = pushed_v; + } +} + +void dvi_printer::possibly_begin_line() +{ + if (!pushed) { + have_pushed = pushed = 1; + pushed_h = cur_h; + pushed_v = cur_v; + out1(push); + } +} + +int scale(int x, int z) +{ + int sw; + int a, b, c, d; + int alpha, beta; + alpha = 16*z; beta = 16; + while (z >= 040000000L) { + z /= 2; beta /= 2; + } + d = x & 255; + c = (x >> 8) & 255; + b = (x >> 16) & 255; + a = (x >> 24) & 255; + sw = (((((d * z) / 0400) + (c * z)) / 0400) + (b * z)) / beta; + if (a == 255) + sw -= alpha; + else + assert(a == 0); + return sw; +} + +void dvi_printer::set_color(color *col) +{ + cur_color = *col; + char buf[256]; + unsigned int components[4]; + color_scheme cs = col->get_components(components); + switch (cs) { + case DEFAULT: + sprintf(buf, "color gray 0"); + break; + case RGB: + sprintf(buf, "color rgb %.3g %.3g %.3g", + double(Red) / double(color::MAX_COLOR_VAL), + double(Green) / double(color::MAX_COLOR_VAL), + double(Blue) / double(color::MAX_COLOR_VAL)); + break; + case CMY: + col->get_cmyk(&Cyan, &Magenta, &Yellow, &Black); + // fall through + case CMYK: + sprintf(buf, "color cmyk %.3g %.3g %.3g %.3g", + double(Cyan) / double(color::MAX_COLOR_VAL), + double(Magenta) / double(color::MAX_COLOR_VAL), + double(Yellow) / double(color::MAX_COLOR_VAL), + double(Black) / double(color::MAX_COLOR_VAL)); + break; + case GRAY: + sprintf(buf, "color gray %.3g", + double(Gray) / double(color::MAX_COLOR_VAL)); + break; + } + do_special(buf); +} + +void dvi_printer::set_char(glyph *g, font *f, const environment *env, + int w, const char *) +{ + if (*env->col != cur_color) + set_color(env->col); + int code = f->get_code(g); + if (env->size != cur_point_size || f != cur_font) { + cur_font = f; + cur_point_size = env->size; + int i; + for (i = 0;; i++) { + if (i >= FONTS_MAX) { + fatal("too many output fonts required"); + } + if (output_font_table[i].f == 0) { + output_font_table[i].f = (dvi_font *)cur_font; + output_font_table[i].point_size = cur_point_size; + define_font(i); + } + if (output_font_table[i].f == cur_font + && output_font_table[i].point_size == cur_point_size) + break; + } + set_font(i); + } + int distance = env->hpos - cur_h; + if (env->hpos != end_h && distance != 0) { + out_signed(right1, distance); + cur_h = env->hpos; + } + else if (distance > max_drift) { + out_signed(right1, distance - max_drift); + cur_h = env->hpos - max_drift; + } + else if (distance < -max_drift) { + out_signed(right1, distance + max_drift); + cur_h = env->hpos + max_drift; + } + if (env->vpos != cur_v) { + out_signed(down1, env->vpos - cur_v); + cur_v = env->vpos; + } + possibly_begin_line(); + end_h = env->hpos + w; + cur_h += scale(f->get_width(g, UNITWIDTH) / MULTIPLIER, + cur_point_size * RES_7227); + if (cur_h > max_h) + max_h = cur_h; + if (cur_v > max_v) + max_v = cur_v; + if (code >= 0 && code <= 127) + out1(code); + else + out_unsigned(set1, code); +} + +void dvi_printer::define_font(int i) +{ + out_unsigned(fnt_def1, i); + dvi_font *f = output_font_table[i].f; + out4(f->checksum); + out4(output_font_table[i].point_size*RES_7227); + out4(int((double(f->design_size)/(1<<20))*RES_7227*100 + .5)); + const char *nm = f->get_internal_name(); + out1(0); + out_string(nm); +} + +void dvi_printer::set_font(int i) +{ + if (i >= 0 && i <= 63) + out1(fnt_num_0 + i); + else + out_unsigned(fnt1, i); +} + +void dvi_printer::out_signed(unsigned char base, int param) +{ + if (-128 <= param && param < 128) { + out1(base); + out1(param); + } + else if (-32768 <= param && param < 32768) { + out1(base+1); + out2(param); + } + else if (-(1 << 23) <= param && param < (1 << 23)) { + out1(base+2); + out3(param); + } + else { + out1(base+3); + out4(param); + } +} + +void dvi_printer::out_unsigned(unsigned char base, int param) +{ + if (param >= 0) { + if (param < 256) { + out1(base); + out1(param); + } + else if (param < 65536) { + out1(base+1); + out2(param); + } + else if (param < (1 << 24)) { + out1(base+2); + out3(param); + } + else { + out1(base+3); + out4(param); + } + } + else { + out1(base+3); + out4(param); + } +} + +void dvi_printer::preamble() +{ + out1(pre); + out1(id_byte); + out4(254000); + out4(font::res); + out4(1000); + out1(0); +} + +void dvi_printer::postamble() +{ + int tem = byte_count; + out1(post); + out4(last_bop); + out4(254000); + out4(font::res); + out4(1000); + out4(max_v); + out4(max_h); + out2(have_pushed); // stack depth + out2(page_count); + int i; + for (i = 0; i < FONTS_MAX && output_font_table[i].f != 0; i++) + define_font(i); + out1(post_post); + out4(tem); + out1(id_byte); + for (i = 0; i < 4 || byte_count % 4 != 0; i++) + out1(filler); +} + +void dvi_printer::begin_page(int i) +{ + page_count++; + int tem = byte_count; + out1(bop); + out4(i); + for (int j = 1; j < 10; j++) + out4(0); + out4(last_bop); + last_bop = tem; + // By convention position (0,0) in a dvi file is placed at (1in, 1in). + cur_h = font::res; + cur_v = font::res; + end_h = 0; + if (page_count == 1) { + char buf[256]; + // at least dvips uses this + double length = user_paper_length ? user_paper_length : + double(font::paperlength) / font::res; + double width = user_paper_width ? user_paper_width : + double(font::paperwidth) / font::res; + if (width > 0 && length > 0) { + sprintf(buf, "papersize=%.3fin,%.3fin", + landscape_flag ? length : width, + landscape_flag ? width : length); + do_special(buf); + } + } + if (cur_color != default_color) + set_color(&cur_color); +} + +void dvi_printer::end_page(int) +{ + set_color(&default_color); + if (pushed) + end_of_line(); + out1(eop); + cur_font = 0; +} + +void draw_dvi_printer::end_page(int len) +{ + dvi_printer::end_page(len); + output_pen_size = -1; +} + +void dvi_printer::do_special(const char *s) +{ + int len = strlen(s); + if (len == 0) + return; + possibly_begin_line(); + out_unsigned(xxx1, len); + while (*s) + out1(*s++); +} + +void dvi_printer::special(char *arg, const environment *env, char type) +{ + if (type != 'p') + return; + moveto(env->hpos, env->vpos); + do_special(arg); +} + +void dvi_printer::moveto(int h, int v) +{ + if (h != cur_h) { + out_signed(right1, h - cur_h); + cur_h = h; + if (cur_h > max_h) + max_h = cur_h; + } + if (v != cur_v) { + out_signed(down1, v - cur_v); + cur_v = v; + if (cur_v > max_v) + max_v = cur_v; + } + end_h = 0; +} + +void dvi_printer::draw(int code, int *p, int np, const environment *env) +{ + if (code == 'l') { + int x = 0, y = 0; + int height = 0, width = 0; + int thickness; + if (line_thickness < 0) + thickness = env->size*RES_7227*linewidth/1000; + else if (line_thickness > 0) + thickness = line_thickness; + else + thickness = 1; + if (np != 2) { + error("2 arguments required for line"); + } + else if (p[0] == 0) { + // vertical rule + if (p[1] > 0) { + x = env->hpos - thickness/2; + y = env->vpos + p[1] + thickness/2; + height = p[1] + thickness; + width = thickness; + } + else if (p[1] < 0) { + x = env->hpos - thickness/2; + y = env->vpos + thickness/2; + height = thickness - p[1]; + width = thickness; + } + } + else if (p[1] == 0) { + if (p[0] > 0) { + x = env->hpos - thickness/2; + y = env->vpos + thickness/2; + height = thickness; + width = p[0] + thickness; + } + else if (p[0] < 0) { + x = env->hpos - p[0] - thickness/2; + y = env->vpos + thickness/2; + height = thickness; + width = thickness - p[0]; + } + } + if (height != 0) { + moveto(x, y); + out1(put_rule); + out4(height); + out4(width); + } + } + else if (code == 't') { + if (np == 0) { + line_thickness = -1; + } + else { + // troff gratuitously adds an extra 0 + if (np != 1 && np != 2) + error("0 or 1 argument required for thickness"); + else + line_thickness = p[0]; + } + } + else if (code == 'R') { + if (np != 2) + error("2 arguments required for rule"); + else if (p[0] != 0 || p[1] != 0) { + int dh = p[0]; + int dv = p[1]; + int oh = env->hpos; + int ov = env->vpos; + if (dv > 0) { + ov += dv; + dv = -dv; + } + if (dh < 0) { + oh += dh; + dh = -dh; + } + moveto(oh, ov); + out1(put_rule); + out4(-dv); + out4(dh); + } + } +} + +// XXX Will this overflow? + +inline int milliinches(int n) +{ + return (n*1000 + font::res/2)/font::res; +} + +void draw_dvi_printer::set_line_thickness(const environment *env) +{ + int desired_pen_size + = milliinches(line_thickness < 0 + // Will this overflow? + ? env->size*RES_7227*linewidth/1000 + : line_thickness); + if (desired_pen_size != output_pen_size) { + char buf[256]; + sprintf(buf, "pn %d", desired_pen_size); + do_special(buf); + output_pen_size = desired_pen_size; + } +} + +void draw_dvi_printer::fill_next(const environment *env) +{ + unsigned int g; + if (env->fill->is_default()) + g = 0; + else { + // currently, only BW support + env->fill->get_gray(&g); + } + char buf[256]; + sprintf(buf, "sh %.3g", 1 - double(g) / double(color::MAX_COLOR_VAL)); + do_special(buf); +} + +void draw_dvi_printer::draw(int code, int *p, int np, const environment *env) +{ + char buf[1024]; + int fill_flag = 0; + switch (code) { + case 'C': + fill_flag = 1; + // fall through + case 'c': + { + // troff adds an extra argument to C + if (np != 1 && !(code == 'C' && np == 2)) { + error("1 argument required for circle"); + break; + } + moveto(env->hpos+p[0]/2, env->vpos); + if (fill_flag) + fill_next(env); + else + set_line_thickness(env); + int rad; + rad = milliinches(p[0]/2); + sprintf(buf, "%s 0 0 %d %d 0 6.28319", + (fill_flag ? "ia" : "ar"), + rad, + rad); + do_special(buf); + break; + } + case 'l': + if (np != 2) { + error("2 arguments required for line"); + break; + } + moveto(env->hpos, env->vpos); + set_line_thickness(env); + do_special("pa 0 0"); + sprintf(buf, "pa %d %d", milliinches(p[0]), milliinches(p[1])); + do_special(buf); + do_special("fp"); + break; + case 'E': + fill_flag = 1; + // fall through + case 'e': + if (np != 2) { + error("2 arguments required for ellipse"); + break; + } + moveto(env->hpos+p[0]/2, env->vpos); + if (fill_flag) + fill_next(env); + else + set_line_thickness(env); + sprintf(buf, "%s 0 0 %d %d 0 6.28319", + (fill_flag ? "ia" : "ar"), + milliinches(p[0]/2), + milliinches(p[1]/2)); + do_special(buf); + break; + case 'P': + fill_flag = 1; + // fall through + case 'p': + { + if (np & 1) { + error("even number of arguments required for polygon"); + break; + } + if (np == 0) { + error("no arguments for polygon"); + break; + } + moveto(env->hpos, env->vpos); + if (fill_flag) + fill_next(env); + else + set_line_thickness(env); + do_special("pa 0 0"); + int h = 0, v = 0; + for (int i = 0; i < np; i += 2) { + h += p[i]; + v += p[i+1]; + sprintf(buf, "pa %d %d", milliinches(h), milliinches(v)); + do_special(buf); + } + do_special("pa 0 0"); + do_special(fill_flag ? "ip" : "fp"); + break; + } + case '~': + { + if (np & 1) { + error("even number of arguments required for spline"); + break; + } + if (np == 0) { + error("no arguments for spline"); + break; + } + moveto(env->hpos, env->vpos); + set_line_thickness(env); + do_special("pa 0 0"); + int h = 0, v = 0; + for (int i = 0; i < np; i += 2) { + h += p[i]; + v += p[i+1]; + sprintf(buf, "pa %d %d", milliinches(h), milliinches(v)); + do_special(buf); + } + do_special("sp"); + break; + } + case 'a': + { + if (np != 4) { + error("4 arguments required for arc"); + break; + } + set_line_thickness(env); + double c[2]; + if (adjust_arc_center(p, c)) { + int rad = milliinches(int(sqrt(c[0]*c[0] + c[1]*c[1]) + .5)); + moveto(env->hpos + int(c[0]), env->vpos + int(c[1])); + double start = atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0]); + double end = atan2(-c[1], -c[0]); + if (end - start < 0) + start -= 2 * 3.14159265358; + sprintf(buf, "ar 0 0 %d %d %f %f", rad, rad, start, end); + do_special(buf); + } + else { + moveto(env->hpos, env->vpos); + do_special("pa 0 0"); + sprintf(buf, + "pa %d %d", + milliinches(p[0] + p[2]), + milliinches(p[1] + p[3])); + do_special(buf); + do_special("fp"); + } + break; + } + case 't': + { + if (np == 0) { + line_thickness = -1; + } + else { + // troff gratuitously adds an extra 0 + if (np != 1 && np != 2) { + error("0 or 1 argument required for thickness"); + break; + } + line_thickness = p[0]; + } + break; + } + case 'R': + { + if (np != 2) { + error("2 arguments required for rule"); + break; + } + int dh = p[0]; + if (dh == 0) + break; + int dv = p[1]; + if (dv == 0) + break; + int oh = env->hpos; + int ov = env->vpos; + if (dv > 0) { + ov += dv; + dv = -dv; + } + if (dh < 0) { + oh += dh; + dh = -dh; + } + moveto(oh, ov); + out1(put_rule); + out4(-dv); + out4(dh); + break; + } + default: + error("unrecognised drawing command '%1'", char(code)); + break; + } +} + +font *dvi_printer::make_font(const char *nm) +{ + return dvi_font::load_dvi_font(nm); +} + +printer *make_printer() +{ + if (draw_flag) + return new draw_dvi_printer; + else + return new dvi_printer; +} + +static void usage(FILE *stream); + +int main(int argc, char **argv) +{ + setlocale(LC_NUMERIC, "C"); + program_name = argv[0]; + static char stderr_buf[BUFSIZ]; + setbuf(stderr, stderr_buf); + int c; + static const struct option long_options[] = { + { "help", no_argument, 0, CHAR_MAX + 1 }, + { "version", no_argument, 0, 'v' }, + { NULL, 0, 0, 0 } + }; + while ((c = getopt_long(argc, argv, "dF:I:lp:vw:", long_options, NULL)) + != EOF) + switch(c) { + case 'd': + draw_flag = 0; + break; + case 'l': + landscape_flag = 1; + break; + case 'F': + font::command_line_font_dir(optarg); + break; + case 'I': + // ignore include search path + break; + case 'p': + if (!font::scan_papersize(optarg, 0, + &user_paper_length, &user_paper_width)) + error("ignoring invalid paper format '%1'", optarg); + break; + case 'v': + { + printf("GNU grodvi (groff) version %s\n", Version_string); + exit(0); + break; + } + case 'w': + if (sscanf(optarg, "%d", &linewidth) != 1 + || linewidth < 0 || linewidth > 1000) { + error("invalid line width '%1' ignored", optarg); + linewidth = DEFAULT_LINEWIDTH; + } + break; + case CHAR_MAX + 1: // --help + usage(stdout); + exit(0); + break; + case '?': + usage(stderr); + exit(1); + break; + default: + assert(0); + } + SET_BINARY(fileno(stdout)); + if (optind >= argc) + do_file("-"); + else { + for (int i = optind; i < argc; i++) + do_file(argv[i]); + } + return 0; +} + +static void usage(FILE *stream) +{ + fprintf(stream, +"usage: %s [-dl] [-F dir] [-p paper-format] [-w n] [file ...]\n" +"usage: %s {-v | --version}\n" +"usage: %s --help\n", + program_name, program_name, program_name); +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/devices/grodvi/grodvi.1.man b/src/devices/grodvi/grodvi.1.man new file mode 100644 index 0000000..05cbe0d --- /dev/null +++ b/src/devices/grodvi/grodvi.1.man @@ -0,0 +1,633 @@ +.TH grodvi @MAN1EXT@ "@MDATE@" "groff @VERSION@" +.SH Name +grodvi \- +.I groff +output driver for TeX DVI format +. +. +.\" ==================================================================== +.\" Legal Terms +.\" ==================================================================== +.\" +.\" Copyright (C) 1989-2020, 2022 Free Software Foundation, Inc. +.\" +.\" Permission is granted to make and distribute verbatim copies of this +.\" manual provided the copyright notice and this permission notice are +.\" preserved on all copies. +.\" +.\" Permission is granted to copy and distribute modified versions of +.\" this manual under the conditions for verbatim copying, provided that +.\" the entire resulting derived work is distributed under the terms of +.\" a permission notice identical to this one. +.\" +.\" Permission is granted to copy and distribute translations of this +.\" manual into another language, under the above conditions for +.\" modified versions, except that this permission notice may be +.\" included in translations approved by the Free Software Foundation +.\" instead of in the original English. +. +. +.\" Save and disable compatibility mode (for, e.g., Solaris 10/11). +.do nr *groff_grodvi_1_man_C \n[.cp] +.cp 0 +. +.\" Define fallback for groff 1.23's MR macro if the system lacks it. +.nr do-fallback 0 +.if !\n(.f .nr do-fallback 1 \" mandoc +.if \n(.g .if !d MR .nr do-fallback 1 \" older groff +.if !\n(.g .nr do-fallback 1 \" non-groff *roff +.if \n[do-fallback] \{\ +. de MR +. ie \\n(.$=1 \ +. I \%\\$1 +. el \ +. IR \%\\$1 (\\$2)\\$3 +. . +.\} +.rr do-fallback +. +. +.ie t .ds tx T\h'-.1667m'\v'.224m'E\v'-.224m'\h'-.125m'X +.el .ds tx TeX +. +.\" This macro definition is poor style from a portability standpoint, +.\" but it's a good test and demonstration of the standard font +.\" repertoire for the devices where it has any effect at all, and so +.\" should be retained. +.de FT +. if '\\*(.T'dvi' .ft \\$1 +.. +. +. +.\" ==================================================================== +.SH Synopsis +.\" ==================================================================== +. +.SY grodvi +.RB [ \-dl ] +.RB [ \-F\~\c +.IR dir ] +.RB [ \-p\~\c +.IR paper-format ] +.RB [ \-w\~\c +.IR n ] +.RI [ file\~ .\|.\|.] +.YS +. +. +.SY grodvi +.B \-\-help +.YS +. +. +.SY grodvi +.B \-v +. +.SY grodvi +.B \-\-version +.YS +. +. +.\" ==================================================================== +.SH Description +.\" ==================================================================== +. +The GNU +.I roff +DVI output driver translates the output of +.MR @g@troff @MAN1EXT@ +into \*[tx] DVI format. +. +Normally, +.I grodvi +is invoked by +.MR groff @MAN1EXT@ +when the latter is given the +.RB \[lq] \-T\~dvi \[rq] +option. +. +(In this installation, +.B @DEVICE@ +is the default output device.) +. +Use +.IR groff 's +.B \-P +option to pass any options shown above to +.IR grodvi . +. +If no +.I file +arguments are given, +or if +.I file +is \[lq]\-\[rq], +.I grodvi +reads the standard input stream. +. +Output is written to the standard output stream. +. +. +.P +The DVI file generated by +.I grodvi +can interpreted by any correctly written DVI driver. +. +.I troff \" generic +drawing primitives are implemented using +.I tpic +version\~2 specials. +. +If the driver does not support these, +.B \[rs]D +escape sequences will not produce any output. +. +. +.P +Encapsulated PostScript (EPS) files can be easily included; +use the +.B PSPIC +macro. +. +.I pspic.tmac +is loaded automatically by +.IR dvi.tmac . +. +See +.MR groff_tmac @MAN5EXT@ . +. +. +.P +The default color used by the +.B \[rs]m +and +.B \[rs]M +escape sequences is black. +. +Currently, +the stroke color for +.B \[rs]D +drawing escape sequences is black; +fill color values are translated to gray. +. +. +.P +In +.IR groff , +as in AT&T +.IR troff , \" AT&T +the +.B \[rs]N +escape sequence can be used to access any glyph in the current font by +its position in the corresponding TFM file. +. +. +.P +By design, +the DVI format doesn't care about the physical dimensions of the output +medium. +. +Instead, +.I grodvi +emits the equivalent to \*[tx]'s +.BI \%\[rs]special{\:\%papersize= width , length } +on the first page; +.I dvips +(or another DVI driver) +then sets the page size accordingly. +. +If either the page width or length is not positive, +no +.B \%papersize +special is output. +. +. +.P +A device control escape sequence +.BI \[rs]X\[aq] anything \[aq] +is translated to the same DVI file instructions as would be produced by +.BI \%\[rs]special{ anything } +in \*[tx]; +.I anything +cannot contain a newline. +. +. +.\" ==================================================================== +.SS Typefaces +.\" ==================================================================== +. +.I grodvi +supports the standard four styles: +.B R +(roman), +.B I +.RI ( italic ), +.B B +.RB ( bold ), +and +.B BI +(\f[BI]bold-italic\f[]). +. +Fonts are grouped into families +.B T +and +.B H +having members in each style. +. +\[lq]CM\[rq] abbreviates \[lq]Computer Modern\[rq]. +. +. +.RS +.TP +.B TR +.FT TR +CM Roman (cmr10) +.FT +. +.TQ +.B TI +.FT TI +CM Text Italic (cmti10) +.FT +. +.TQ +.B TB +.FT TB +CM Bold Extended Roman (cmbx10) +.FT +. +.TQ +.B TBI +.FT TBI +CM Bold Extended Text Italic (cmbxti10) +.FT +. +.TQ +.B HR +.FT HR +CM Sans Serif (cmss10) +.FT +. +.TQ +.B HI +.FT HI +CM Slanted Sans Serif (cmssi10) +.FT +. +.TQ +.B HB +.FT HB +CM Sans Serif Bold Extended (cmssbx10) +.FT +. +.TQ +.B HBI +.FT HBI +CM Slanted Sans Serif Bold Extended (cmssbxo10) +.FT +.RE +. +. +.LP +The following fonts are not members of a family. +. +. +.RS +.TP +.B CW +.FT CW +CM Typewriter Text (cmtt10) +.FT +. +.TQ +.B CWI +.FT CWI +CM Italic Typewriter Text (cmitt10) +.FT +.RE +. +. +.P +Special fonts include +.B MI +(cmmi10), +.B S +(cmsy10), +.B EX +(cmex10), +.B SC +(cmtex10, +only for +.BR CW ), +and, +perhaps surprisingly, +.BR TR , +.BR TI , +and +.BR CW , +.\" See font/devdvi/generate/Makefile for details. +because \*[tx] places some glyphs in text fonts that +.I troff \" generic +generally does not. +. +For italic fonts, +.B CWI +is used instead of +.BR CW . +. +. +.P +Finally, +the symbol fonts of the American Mathematical Society are available as +special fonts +.B SA +(msam10) and +.B SB +(msbm10). +. +They are are not mounted by default. +. +. +.br +.ne 2v +.P +The +.I @g@troff +option +.B \-mec +loads the +.I ec.tmac +macro file, +employing the EC and TC fonts instead of CM. +. +These are designed similarly to the Computer Modern fonts; +further, +they provide Euro +.B \[rs][Eu] +and per mille +.B \[rs][%0] +glyphs. +. +.I ec.tmac +must be loaded before any language-specific macro files because it does +not set up the codes necessary for automatic hyphenation. +. +. +.\" ==================================================================== +.SS "Font description files" +.\" ==================================================================== +. +Use +.MR tfmtodit @MAN1EXT@ +to create +.I groff +font description files from TFM +(\*[tx] font metrics) +files. +. +The font description file should contain the following additional +directives, +which +.I tfmtodit +generates automatically. +. +. +.TP +.BI internalname\~ name +The name of the TFM file +(without the +.I .tfm +extension) is +.IR name . +. +. +.TP +.BI checksum\~ n +The checksum in the TFM file is +.IR n . +. +. +.TP +.BI designsize\~ n +The design size in the TFM file is +.IR n . +. +. +.\" ==================================================================== +.SS "Drawing commands" +.\" ==================================================================== +. +.I grodvi +supports an additional drawing command. +. +. +.TP +.BI \[rs]D\[aq]R\~ "dh dv" \[aq] +Draw a rule +(solid black rectangle) +with one corner at the drawing position, +and the diagonally opposite corner at the drawing position +.RI +( dh , dv ), +which becomes the new drawing position afterward. +. +This command produces a rule in the DVI file and so can be printed even +with a driver that does not support +.I tpic +specials, +unlike the other +.B \[rs]D +commands. +. +. +.\" ==================================================================== +.SH Options +.\" ==================================================================== +. +.B \-\-help +displays a usage message, +while +.B \-v +and +.B \-\-version +show version information; +all exit afterward. +. +. +.TP +.B \-d +Do not use +.I tpic +specials to implement drawing commands. +. +Horizontal and vertical lines are implemented by rules. +. +Other drawing commands are ignored. +. +. +.TP +.BI \-F\~ dir +Prepend directory +.RI dir /dev name +to the search path for font and device description files; +.I name +is the name of the device, +usually +.BR dvi . +. +. +.TP +.B \-l +Use landscape orientation rather than portrait. +. +. +.TP +.BI \-p\~ paper-format +Set physical dimensions of output medium, +overriding the +.BR \%papersize , +.BR \%paperlength , +and +.B \%paperwidth +directives in the +.I DESC +file. +. +.I paper-format +can be any argument accepted by the +.B \%papersize +directive; +see +.MR groff_font @MAN5EXT@ . +. +. +.TP +.BI \-w\~ n +Draw rules (lines) with a thickness of +.IR n \~thousandths +of an em. +. +The default thickness is +.B 40 +(0.04\~em). +. +. +.\" ==================================================================== +.SH Environment +.\" ==================================================================== +. +.TP +.I GROFF_FONT_PATH +lists directories in which to search for +.IR devdvi , +.IR grodvi 's +directory of device and font description files. +. +See +.MR @g@troff @MAN1EXT@ +and +.MR groff_font @MAN5EXT@ . +. +. +.\" ==================================================================== +.SH Files +.\" ==================================================================== +. +.TP +.I @FONTDIR@/\:\%devdvi/\:DESC +describes the +.B dvi +output device. +. +. +.TP +.IR @FONTDIR@/\:\%devdvi/ F +describes the font known +.RI as\~ F +on device +.BR dvi . +. +. +.TP +.I @MACRODIR@/\:dvi\:.tmac +defines font mappings, +special characters, +and colors for use with the +.B dvi +output device. +. +It is automatically loaded by +.I \%troffrc +when the +.B dvi +output device is selected. +. +. +.TP +.I @MACRODIR@/\:ec\:.tmac +configures the +.B dvi +output device to use +the EC and TC font families instead of CM +(Computer Modern). +. +. +.\" ==================================================================== +.SH Bugs +.\" ==================================================================== +. +DVI files produced by +.I grodvi +use a different resolution +(57,816 units per inch) +from those produced by \*[tx]. +. +Incorrectly written drivers which assume the resolution used by \*[tx], +rather than using the resolution specified in the DVI file, +will not work with +.IR grodvi . +. +. +.LP +When using the +.B \-d +option with boxed tables, +vertical and horizontal lines can sometimes protrude by one pixel. +. +This is a consequence of the way \*[tx] requires that the heights +and widths of rules be rounded. +. +. +.\" ==================================================================== +.SH "See also" +.\" ==================================================================== +. +.UR https://\:texfaq\:.org/\:FAQ\-\:ECfonts +\[lq]What are the EC fonts?\[rq] +.UE ; +\*[tx] FAQ: Frequently Asked Question List for \*[tx] +. +. +.P +.MR tfmtodit @MAN1EXT@ , +.MR groff @MAN1EXT@ , +.MR @g@troff @MAN1EXT@ , +.MR groff_out @MAN5EXT@ , +.MR groff_font @MAN5EXT@ , +.MR groff_char @MAN7EXT@ , +.MR groff_tmac @MAN5EXT@ +. +. +.\" Clean up. +.rm FT +.rm tx +. +.\" Restore compatibility mode (for, e.g., Solaris 10/11). +.cp \n[*groff_grodvi_1_man_C] +.do rr *groff_grodvi_1_man_C +. +. +.\" Local Variables: +.\" fill-column: 72 +.\" mode: nroff +.\" End: +.\" vim: set filetype=groff textwidth=72: diff --git a/src/devices/grodvi/grodvi.am b/src/devices/grodvi/grodvi.am new file mode 100644 index 0000000..ce93359 --- /dev/null +++ b/src/devices/grodvi/grodvi.am @@ -0,0 +1,32 @@ +# Copyright (C) 2014-2020 Free Software Foundation, Inc. +# +# This file is part of groff. +# +# groff is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# groff is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +bin_PROGRAMS += grodvi +grodvi_SOURCES = src/devices/grodvi/dvi.cpp +grodvi_LDADD = \ + libdriver.a \ + libgroff.a \ + lib/libgnu.a $(LIBM) +man1_MANS += src/devices/grodvi/grodvi.1 +EXTRA_DIST += src/devices/grodvi/grodvi.1.man + + +# Local Variables: +# fill-column: 72 +# mode: makefile-automake +# End: +# vim: set autoindent filetype=automake textwidth=72: |