152284Sobrien/* $NetBSD$ */ 2169689Skan 352284Sobrien// -*- C++ -*- 490075Sobrien/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004 552284Sobrien Free Software Foundation, Inc. 690075Sobrien Written by James Clark (jjc@jclark.com) 790075Sobrien 890075SobrienThis file is part of groff. 990075Sobrien 1052284Sobriengroff is free software; you can redistribute it and/or modify it under 1190075Sobrienthe terms of the GNU General Public License as published by the Free 1290075SobrienSoftware Foundation; either version 2, or (at your option) any later 1390075Sobrienversion. 1490075Sobrien 1552284Sobriengroff is distributed in the hope that it will be useful, but WITHOUT ANY 1652284SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 1790075SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18169689Skanfor more details. 19169689Skan 2052284SobrienYou should have received a copy of the GNU General Public License along 2152284Sobrienwith groff; see the file COPYING. If not, write to the Free Software 2252284SobrienFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 23132718Skan 24132718Skan#include "driver.h" 2552284Sobrien#include "nonposix.h" 2652284Sobrien#include "paper.h" 2790075Sobrien 28169689Skanextern "C" const char *Version_string; 2952284Sobrien 3052284Sobrien#define DEFAULT_LINEWIDTH 40 3152284Sobrienstatic int linewidth = DEFAULT_LINEWIDTH; 3252284Sobrien 3352284Sobrienstatic int draw_flag = 1; 3452284Sobrien 3552284Sobrienstatic int landscape_flag = 0; 36132718Skanstatic double user_paper_length = 0; 3752284Sobrienstatic double user_paper_width = 0; 3890075Sobrien 3952284Sobrien/* These values were chosen because: 4052284Sobrien 4152284Sobrien(MULTIPLIER*SIZESCALE)/(RES*UNITWIDTH) == 1/(2^20 * 72.27) 4252284Sobrien 4352284Sobrienand 57816 is an exact multiple of both 72.27*SIZESCALE and 72. 4452284Sobrien 45132718SkanThe width in the groff font file is the product of MULTIPLIER and the 4652284Sobrienwidth in the tfm file. */ 4752284Sobrien 4852284Sobrien#define RES 57816 4952284Sobrien#define RES_7227 (RES/7227) 5052284Sobrien#define UNITWIDTH 131072 5152284Sobrien#define SIZESCALE 100 52117395Skan#define MULTIPLIER 1 53117395Skan 54117395Skanclass dvi_font : public font { 55117395Skan dvi_font(const char *); 56117395Skanpublic: 57132718Skan int checksum; 58117395Skan int design_size; 59117395Skan ~dvi_font(); 60117395Skan void handle_unknown_font_command(const char *command, const char *arg, 61117395Skan const char *filename, int lineno); 62117395Skan static dvi_font *load_dvi_font(const char *); 63117395Skan}; 64117395Skan 65117395Skandvi_font *dvi_font::load_dvi_font(const char *s) 66117395Skan{ 67117395Skan dvi_font *f = new dvi_font(s); 68132718Skan if (!f->load()) { 69117395Skan delete f; 70117395Skan return 0; 71117395Skan } 72117395Skan return f; 73117395Skan} 74117395Skan 75132718Skandvi_font::dvi_font(const char *nm) 76117395Skan: font(nm), checksum(0), design_size(0) 77117395Skan{ 78117395Skan} 79117395Skan 80117395Skandvi_font::~dvi_font() 81117395Skan{ 82117395Skan} 83117395Skan 84117395Skanvoid dvi_font::handle_unknown_font_command(const char *command, 85117395Skan const char *arg, 86117395Skan const char *filename, int lineno) 87117395Skan{ 88117395Skan char *ptr; 89117395Skan if (strcmp(command, "checksum") == 0) { 90132718Skan if (arg == 0) 91117395Skan fatal_with_file_and_line(filename, lineno, 92117395Skan "`checksum' command requires an argument"); 93117395Skan checksum = int(strtol(arg, &ptr, 10)); 94132718Skan if (checksum == 0 && ptr == arg) { 95117395Skan fatal_with_file_and_line(filename, lineno, "bad checksum"); 96117395Skan } 97117395Skan } 98117395Skan else if (strcmp(command, "designsize") == 0) { 99117395Skan if (arg == 0) 100117395Skan fatal_with_file_and_line(filename, lineno, 101117395Skan "`designsize' command requires an argument"); 102117395Skan design_size = int(strtol(arg, &ptr, 10)); 103117395Skan if (design_size == 0 && ptr == arg) { 104117395Skan fatal_with_file_and_line(filename, lineno, "bad design size"); 105117395Skan } 106117395Skan } 107169689Skan} 108169689Skan 109169689Skan#define FONTS_MAX 256 110169689Skan 111169689Skanstruct output_font { 112169689Skan dvi_font *f; 113169689Skan int point_size; 114169689Skan output_font() : f(0) { } 115169689Skan}; 116169689Skan 117169689Skanclass dvi_printer : public printer { 118169689Skan FILE *fp; 119169689Skan int max_drift; 120169689Skan int byte_count; 121169689Skan int last_bop; 122169689Skan int page_count; 123169689Skan int cur_h; 124169689Skan int cur_v; 125169689Skan int end_h; 126169689Skan int max_h; 127169689Skan int max_v; 128169689Skan output_font output_font_table[FONTS_MAX]; 129169689Skan font *cur_font; 130169689Skan int cur_point_size; 131169689Skan color cur_color; 132169689Skan int pushed; 13352284Sobrien int pushed_h; 13452284Sobrien int pushed_v; 13552284Sobrien int have_pushed; 136132718Skan void preamble(); 13752284Sobrien void postamble(); 13890075Sobrien void define_font(int); 13952284Sobrien void set_font(int); 14052284Sobrien void possibly_begin_line(); 14152284Sobrien void set_color(color *); 14252284Sobrienprotected: 14352284Sobrien enum { 14452284Sobrien id_byte = 2, 14552284Sobrien set1 = 128, 14652284Sobrien put1 = 133, 14752284Sobrien put_rule = 137, 14852284Sobrien bop = 139, 14952284Sobrien eop = 140, 15052284Sobrien push = 141, 15152284Sobrien pop = 142, 15252284Sobrien right1 = 143, 15352284Sobrien down1 = 157, 15452284Sobrien fnt_num_0 = 171, 15552284Sobrien fnt1 = 235, 15652284Sobrien xxx1 = 239, 15752284Sobrien fnt_def1 = 243, 15852284Sobrien pre = 247, 15952284Sobrien post = 248, 160132718Skan post_post = 249, 16152284Sobrien filler = 223 16290075Sobrien }; 16352284Sobrien int line_thickness; 16452284Sobrien 16590075Sobrien void out1(int); 16652284Sobrien void out2(int); 16752284Sobrien void out3(int); 16852284Sobrien void out4(int); 16952284Sobrien void moveto(int, int); 17052284Sobrien void out_string(const char *); 17152284Sobrien void out_signed(unsigned char, int); 17252284Sobrien void out_unsigned(unsigned char, int); 17352284Sobrien void do_special(const char *); 17452284Sobrienpublic: 17552284Sobrien dvi_printer(); 17652284Sobrien ~dvi_printer(); 17752284Sobrien font *make_font(const char *); 178132718Skan void begin_page(int); 17952284Sobrien void end_page(int); 18090075Sobrien void set_char(int, font *, const environment *, int w, const char *name); 18152284Sobrien void special(char *arg, const environment *env, char type); 18252284Sobrien void end_of_line(); 18390075Sobrien void draw(int code, int *p, int np, const environment *env); 18490075Sobrien}; 185132718Skan 18690075Sobrien 18790075Sobrienclass draw_dvi_printer : public dvi_printer { 18890075Sobrien int output_pen_size; 189117395Skan void set_line_thickness(const environment *); 19052284Sobrien void fill_next(const environment *); 19152284Sobrienpublic: 19252284Sobrien draw_dvi_printer(); 193132718Skan ~draw_dvi_printer(); 19452284Sobrien void draw(int code, int *p, int np, const environment *env); 195132718Skan void end_page(int); 19652284Sobrien}; 19752284Sobrien 19890075Sobriendvi_printer::dvi_printer() 19952284Sobrien: fp(stdout), byte_count(0), last_bop(-1), page_count(0), max_h(0), max_v(0), 20052284Sobrien cur_font(0), cur_point_size(-1), pushed(0), line_thickness(-1) 201132718Skan{ 20252284Sobrien if (font::res != RES) 20390075Sobrien fatal("resolution must be %1", RES); 20490075Sobrien if (font::unitwidth != UNITWIDTH) 205132718Skan fatal("unitwidth must be %1", UNITWIDTH); 20690075Sobrien if (font::hor != 1) 20790075Sobrien fatal("hor must be equal to 1"); 20890075Sobrien if (font::vert != 1) 20990075Sobrien fatal("vert must be equal to 1"); 21090075Sobrien if (font::sizescale != SIZESCALE) 21152284Sobrien fatal("sizescale must be equal to %1", SIZESCALE); 21252284Sobrien max_drift = font::res/1000; // this is fairly arbitrary 21352284Sobrien preamble(); 21452284Sobrien} 21552284Sobrien 216132718Skandvi_printer::~dvi_printer() 21752284Sobrien{ 21890075Sobrien postamble(); 21952284Sobrien} 22052284Sobrien 22152284Sobrien 22252284Sobriendraw_dvi_printer::draw_dvi_printer() 22352284Sobrien: output_pen_size(-1) 22490075Sobrien{ 22552284Sobrien} 22652284Sobrien 227132718Skandraw_dvi_printer::~draw_dvi_printer() 22852284Sobrien{ 22990075Sobrien} 23052284Sobrien 23152284Sobrien 23252284Sobrienvoid dvi_printer::out1(int n) 23352284Sobrien{ 23452284Sobrien byte_count += 1; 23552284Sobrien putc(n & 0xff, fp); 23652284Sobrien} 237117395Skan 23852284Sobrienvoid dvi_printer::out2(int n) 239117395Skan{ 240132718Skan byte_count += 2; 24152284Sobrien putc((n >> 8) & 0xff, fp); 242117395Skan putc(n & 0xff, fp); 243117395Skan} 244117395Skan 245117395Skanvoid dvi_printer::out3(int n) 246117395Skan{ 247117395Skan byte_count += 3; 24852284Sobrien putc((n >> 16) & 0xff, fp); 249117395Skan putc((n >> 8) & 0xff, fp); 25052284Sobrien putc(n & 0xff, fp); 25190075Sobrien} 252117395Skan 253117395Skanvoid dvi_printer::out4(int n) 25452284Sobrien{ 25590075Sobrien byte_count += 4; 256117395Skan putc((n >> 24) & 0xff, fp); 25752284Sobrien putc((n >> 16) & 0xff, fp); 25852284Sobrien putc((n >> 8) & 0xff, fp); 259117395Skan putc(n & 0xff, fp); 260132718Skan} 261117395Skan 262117395Skanvoid dvi_printer::out_string(const char *s) 263117395Skan{ 264117395Skan out1(strlen(s)); 265117395Skan while (*s != 0) 266117395Skan out1(*s++); 267117395Skan} 268117395Skan 269117395Skan 270117395Skanvoid dvi_printer::end_of_line() 271117395Skan{ 27252284Sobrien if (pushed) { 27352284Sobrien out1(pop); 27452284Sobrien pushed = 0; 275132718Skan cur_h = pushed_h; 27652284Sobrien cur_v = pushed_v; 277117395Skan } 278117395Skan} 279117395Skan 280132718Skanvoid dvi_printer::possibly_begin_line() 28152284Sobrien{ 282117395Skan if (!pushed) { 283117395Skan have_pushed = pushed = 1; 284132718Skan pushed_h = cur_h; 285132718Skan pushed_v = cur_v; 286132718Skan out1(push); 287132718Skan } 288132718Skan} 289132718Skan 29052284Sobrienint scale(int x, int z) 29152284Sobrien{ 29252284Sobrien int sw; 29390075Sobrien int a, b, c, d; 29452284Sobrien int alpha, beta; 29552284Sobrien alpha = 16*z; beta = 16; 296132718Skan while (z >= 040000000L) { 29752284Sobrien z /= 2; beta /= 2; 298117395Skan } 299117395Skan d = x & 255; 300117395Skan c = (x >> 8) & 255; 301117395Skan b = (x >> 16) & 255; 302117395Skan a = (x >> 24) & 255; 303132718Skan sw = (((((d * z) / 0400) + (c * z)) / 0400) + (b * z)) / beta; 304117395Skan if (a == 255) 305169689Skan sw -= alpha; 306117395Skan else 307117395Skan assert(a == 0); 308117395Skan return sw; 309117395Skan} 310117395Skan 31152284Sobrienvoid dvi_printer::set_color(color *col) 312117395Skan{ 313117395Skan cur_color = *col; 314117395Skan char buf[256]; 315117395Skan unsigned int components[4]; 316117395Skan color_scheme cs = col->get_components(components); 31752284Sobrien switch (cs) { 31852284Sobrien case DEFAULT: 319169689Skan sprintf(buf, "color gray 0"); 320169689Skan break; 321169689Skan case RGB: 322169689Skan sprintf(buf, "color rgb %.3g %.3g %.3g", 323169689Skan double(Red) / color::MAX_COLOR_VAL, 324169689Skan double(Green) / color::MAX_COLOR_VAL, 325169689Skan double(Blue) / color::MAX_COLOR_VAL); 326169689Skan break; 327169689Skan case CMY: 328169689Skan col->get_cmyk(&Cyan, &Magenta, &Yellow, &Black); 329169689Skan // fall through 330169689Skan case CMYK: 331169689Skan sprintf(buf, "color cmyk %.3g %.3g %.3g %.3g", 332169689Skan double(Cyan) / color::MAX_COLOR_VAL, 333169689Skan double(Magenta) / color::MAX_COLOR_VAL, 334169689Skan double(Yellow) / color::MAX_COLOR_VAL, 335169689Skan double(Black) / color::MAX_COLOR_VAL); 336169689Skan break; 33790075Sobrien case GRAY: 338117395Skan sprintf(buf, "color gray %.3g", 33952284Sobrien double(Gray) / color::MAX_COLOR_VAL); 340117395Skan break; 341132718Skan } 34252284Sobrien do_special(buf); 343117395Skan} 344117395Skan 345117395Skanvoid dvi_printer::set_char(int idx, font *f, const environment *env, 346117395Skan int w, const char *) 347117395Skan{ 34852284Sobrien if (*env->col != cur_color) 349117395Skan set_color(env->col); 35052284Sobrien int code = f->get_code(idx); 35190075Sobrien if (env->size != cur_point_size || f != cur_font) { 352132718Skan cur_font = f; 353117395Skan cur_point_size = env->size; 35452284Sobrien int i; 35590075Sobrien for (i = 0;; i++) { 356117395Skan if (i >= FONTS_MAX) { 35752284Sobrien fatal("too many output fonts required"); 35890075Sobrien } 359117395Skan if (output_font_table[i].f == 0) { 360132718Skan output_font_table[i].f = (dvi_font *)cur_font; 361117395Skan output_font_table[i].point_size = cur_point_size; 362117395Skan define_font(i); 363117395Skan } 364117395Skan if (output_font_table[i].f == cur_font 365117395Skan && output_font_table[i].point_size == cur_point_size) 366117395Skan break; 367117395Skan } 368117395Skan set_font(i); 369117395Skan } 370117395Skan int distance = env->hpos - cur_h; 37190075Sobrien if (env->hpos != end_h && distance != 0) { 372117395Skan out_signed(right1, distance); 37390075Sobrien cur_h = env->hpos; 374117395Skan } 375132718Skan else if (distance > max_drift) { 37690075Sobrien out_signed(right1, distance - max_drift); 377117395Skan cur_h = env->hpos - max_drift; 378117395Skan } 379117395Skan else if (distance < -max_drift) { 380117395Skan out_signed(right1, distance + max_drift); 381117395Skan cur_h = env->hpos + max_drift; 382117395Skan } 383117395Skan if (env->vpos != cur_v) { 38490075Sobrien out_signed(down1, env->vpos - cur_v); 38590075Sobrien cur_v = env->vpos; 386132718Skan } 387117395Skan possibly_begin_line(); 38890075Sobrien end_h = env->hpos + w; 389117395Skan cur_h += scale(f->get_width(idx, UNITWIDTH)/MULTIPLIER, 390117395Skan cur_point_size*RES_7227); 39190075Sobrien if (cur_h > max_h) 39290075Sobrien max_h = cur_h; 393117395Skan if (cur_v > max_v) 394132718Skan max_v = cur_v; 395117395Skan if (code >= 0 && code <= 127) 396117395Skan out1(code); 397117395Skan else 398117395Skan out_unsigned(set1, code); 399117395Skan} 400117395Skan 401117395Skanvoid dvi_printer::define_font(int i) 402117395Skan{ 403117395Skan out_unsigned(fnt_def1, i); 404117395Skan dvi_font *f = output_font_table[i].f; 40552284Sobrien out4(f->checksum); 406117395Skan out4(output_font_table[i].point_size*RES_7227); 40752284Sobrien out4(int((double(f->design_size)/(1<<20))*RES_7227*100 + .5)); 408117395Skan const char *nm = f->get_internal_name(); 409132718Skan out1(0); 41052284Sobrien out_string(nm); 411117395Skan} 412117395Skan 413117395Skanvoid dvi_printer::set_font(int i) 414117395Skan{ 415117395Skan if (i >= 0 && i <= 63) 41652284Sobrien out1(fnt_num_0 + i); 417117395Skan else 41852284Sobrien out_unsigned(fnt1, i); 41990075Sobrien} 420132718Skan 421117395Skanvoid dvi_printer::out_signed(unsigned char base, int param) 42252284Sobrien{ 42390075Sobrien if (-128 <= param && param < 128) { 424117395Skan out1(base); 42552284Sobrien out1(param); 42652284Sobrien } 427117395Skan else if (-32768 <= param && param < 32768) { 428132718Skan out1(base+1); 429117395Skan out2(param); 430117395Skan } 431117395Skan else if (-(1 << 23) <= param && param < (1 << 23)) { 432117395Skan out1(base+2); 433117395Skan out3(param); 43490075Sobrien } 435117395Skan else { 436117395Skan out1(base+3); 437117395Skan out4(param); 438117395Skan } 439117395Skan} 440117395Skan 441117395Skanvoid dvi_printer::out_unsigned(unsigned char base, int param) 442132718Skan{ 44390075Sobrien if (param >= 0) { 444117395Skan if (param < 256) { 44590075Sobrien out1(base); 44690075Sobrien out1(param); 447117395Skan } 44890075Sobrien else if (param < 65536) { 449117395Skan out1(base+1); 45090075Sobrien out2(param); 451117395Skan } 45290075Sobrien else if (param < (1 << 24)) { 45390075Sobrien out1(base+2); 45452284Sobrien out3(param); 455117395Skan } 45652284Sobrien else { 457117395Skan out1(base+3); 458132718Skan out4(param); 45952284Sobrien } 460117395Skan } 461117395Skan else { 462117395Skan out1(base+3); 463117395Skan out4(param); 464117395Skan } 465117395Skan} 46652284Sobrien 467117395Skanvoid dvi_printer::preamble() 46852284Sobrien{ 46990075Sobrien out1(pre); 470117395Skan out1(id_byte); 471117395Skan out4(254000); 47252284Sobrien out4(font::res); 47390075Sobrien out4(1000); 474117395Skan out1(0); 47552284Sobrien} 47652284Sobrien 477117395Skanvoid dvi_printer::postamble() 478132718Skan{ 479117395Skan int tem = byte_count; 480117395Skan out1(post); 481117395Skan out4(last_bop); 482117395Skan out4(254000); 483117395Skan out4(font::res); 484117395Skan out4(1000); 485117395Skan out4(max_v); 486117395Skan out4(max_h); 487117395Skan out2(have_pushed); // stack depth 488117395Skan out2(page_count); 489117395Skan int i; 49090075Sobrien for (i = 0; i < FONTS_MAX && output_font_table[i].f != 0; i++) 491117395Skan define_font(i); 49252284Sobrien out1(post_post); 493117395Skan out4(tem); 494132718Skan out1(id_byte); 49552284Sobrien for (i = 0; i < 4 || byte_count % 4 != 0; i++) 496117395Skan out1(filler); 497117395Skan} 498117395Skan 499117395Skanvoid dvi_printer::begin_page(int i) 500117395Skan{ 501117395Skan page_count++; 50252284Sobrien int tem = byte_count; 503117395Skan out1(bop); 50452284Sobrien out4(i); 50590075Sobrien for (int j = 1; j < 10; j++) 506117395Skan out4(0); 507117395Skan out4(last_bop); 50852284Sobrien last_bop = tem; 50990075Sobrien // By convention position (0,0) in a dvi file is placed at (1in, 1in). 510117395Skan cur_h = font::res; 51152284Sobrien cur_v = font::res; 51252284Sobrien end_h = 0; 513117395Skan if (page_count == 1) { 514132718Skan char buf[256]; 515117395Skan // at least dvips uses this 516117395Skan double length = user_paper_length ? user_paper_length : 517117395Skan double(font::paperlength) / font::res; 518117395Skan double width = user_paper_width ? user_paper_width : 519117395Skan double(font::paperwidth) / font::res; 520117395Skan if (width > 0 && length > 0) { 521117395Skan sprintf(buf, "papersize=%.3fin,%.3fin", 522117395Skan landscape_flag ? length : width, 523117395Skan landscape_flag ? width : length); 524117395Skan do_special(buf); 525117395Skan } 52690075Sobrien } 52790075Sobrien if (cur_color != default_color) 52890075Sobrien set_color(&cur_color); 52952284Sobrien} 53052284Sobrien 531132718Skanvoid dvi_printer::end_page(int) 53252284Sobrien{ 53390075Sobrien set_color(&default_color); 53490075Sobrien if (pushed) 53590075Sobrien end_of_line(); 536169689Skan out1(eop); 53752284Sobrien cur_font = 0; 538169689Skan} 53990075Sobrien 540169689Skanvoid draw_dvi_printer::end_page(int len) 54190075Sobrien{ 542117395Skan dvi_printer::end_page(len); 543169689Skan output_pen_size = -1; 54490075Sobrien} 54590075Sobrien 54652284Sobrienvoid dvi_printer::do_special(const char *s) 54752284Sobrien{ 54890075Sobrien int len = strlen(s); 54990075Sobrien if (len == 0) 55090075Sobrien return; 551169689Skan possibly_begin_line(); 55290075Sobrien out_unsigned(xxx1, len); 55390075Sobrien while (*s) 55490075Sobrien out1(*s++); 55552284Sobrien} 556169689Skan 55790075Sobrienvoid dvi_printer::special(char *arg, const environment *env, char type) 55890075Sobrien{ 55990075Sobrien if (type != 'p') 56090075Sobrien return; 56190075Sobrien moveto(env->hpos, env->vpos); 56290075Sobrien do_special(arg); 56390075Sobrien} 56490075Sobrien 56590075Sobrienvoid dvi_printer::moveto(int h, int v) 56690075Sobrien{ 56790075Sobrien if (h != cur_h) { 56890075Sobrien out_signed(right1, h - cur_h); 56990075Sobrien cur_h = h; 57090075Sobrien if (cur_h > max_h) 571132718Skan max_h = cur_h; 57290075Sobrien } 57390075Sobrien if (v != cur_v) { 57490075Sobrien out_signed(down1, v - cur_v); 57590075Sobrien cur_v = v; 576169689Skan if (cur_v > max_v) 57790075Sobrien max_v = cur_v; 578169689Skan } 57952284Sobrien end_h = 0; 580169689Skan} 58190075Sobrien 582117395Skanvoid dvi_printer::draw(int code, int *p, int np, const environment *env) 58390075Sobrien{ 58490075Sobrien if (code == 'l') { 58552284Sobrien int x = 0, y = 0; 58652284Sobrien int height = 0, width = 0; 58752284Sobrien int thickness; 58890075Sobrien if (line_thickness < 0) 58990075Sobrien thickness = env->size*RES_7227*linewidth/1000; 59090075Sobrien else if (line_thickness > 0) 591169689Skan thickness = line_thickness; 59290075Sobrien else 59390075Sobrien thickness = 1; 59490075Sobrien if (np != 2) { 59552284Sobrien error("2 arguments required for line"); 596169689Skan } 59790075Sobrien else if (p[0] == 0) { 59890075Sobrien // vertical rule 59990075Sobrien if (p[1] > 0) { 60090075Sobrien x = env->hpos - thickness/2; 60190075Sobrien y = env->vpos + p[1] + thickness/2; 60290075Sobrien height = p[1] + thickness; 60390075Sobrien width = thickness; 60490075Sobrien } 60590075Sobrien else if (p[1] < 0) { 60690075Sobrien x = env->hpos - thickness/2; 60790075Sobrien y = env->vpos + thickness/2; 60890075Sobrien height = thickness - p[1]; 60990075Sobrien width = thickness; 61090075Sobrien } 611132718Skan } 61290075Sobrien else if (p[1] == 0) { 61390075Sobrien if (p[0] > 0) { 61490075Sobrien x = env->hpos - thickness/2; 61590075Sobrien y = env->vpos + thickness/2; 616169689Skan height = thickness; 61790075Sobrien width = p[0] + thickness; 618169689Skan } 61952284Sobrien else if (p[0] < 0) { 620169689Skan x = env->hpos - p[0] - thickness/2; 62190075Sobrien y = env->vpos + thickness/2; 622117395Skan height = thickness; 62352284Sobrien width = thickness - p[0]; 62490075Sobrien } 62590075Sobrien } 62690075Sobrien if (height != 0) { 62752284Sobrien moveto(x, y); 628169689Skan out1(put_rule); 62990075Sobrien out4(height); 63090075Sobrien out4(width); 631169689Skan } 63290075Sobrien } 63390075Sobrien else if (code == 't') { 63490075Sobrien if (np == 0) { 63552284Sobrien line_thickness = -1; 636169689Skan } 63790075Sobrien else { 63890075Sobrien // troff gratuitously adds an extra 0 63990075Sobrien if (np != 1 && np != 2) 64090075Sobrien error("0 or 1 argument required for thickness"); 64190075Sobrien else 64290075Sobrien line_thickness = p[0]; 64390075Sobrien } 64490075Sobrien } 64552284Sobrien else if (code == 'R') { 64652284Sobrien if (np != 2) 64790075Sobrien error("2 arguments required for rule"); 64890075Sobrien else if (p[0] != 0 || p[1] != 0) { 64952284Sobrien int dh = p[0]; 65052284Sobrien int dv = p[1]; 651132718Skan int oh = env->hpos; 65252284Sobrien int ov = env->vpos; 65390075Sobrien if (dv > 0) { 65490075Sobrien ov += dv; 65590075Sobrien dv = -dv; 656169689Skan } 65752284Sobrien if (dh < 0) { 658169689Skan oh += dh; 65952284Sobrien dh = -dh; 660169689Skan } 66190075Sobrien moveto(oh, ov); 662117395Skan out1(put_rule); 66352284Sobrien out4(-dv); 66490075Sobrien out4(dh); 66552284Sobrien } 66652284Sobrien } 66752284Sobrien} 668169689Skan 66990075Sobrien// XXX Will this overflow? 67090075Sobrien 671169689Skaninline int milliinches(int n) 67290075Sobrien{ 67390075Sobrien return (n*1000 + font::res/2)/font::res; 67490075Sobrien} 67552284Sobrien 676169689Skanvoid draw_dvi_printer::set_line_thickness(const environment *env) 67790075Sobrien{ 67890075Sobrien int desired_pen_size 679117395Skan = milliinches(line_thickness < 0 68090075Sobrien // Will this overflow? 68190075Sobrien ? env->size*RES_7227*linewidth/1000 68290075Sobrien : line_thickness); 68390075Sobrien if (desired_pen_size != output_pen_size) { 68490075Sobrien char buf[256]; 68590075Sobrien sprintf(buf, "pn %d", desired_pen_size); 68690075Sobrien do_special(buf); 68790075Sobrien output_pen_size = desired_pen_size; 68890075Sobrien } 68990075Sobrien} 69090075Sobrien 691132718Skanvoid draw_dvi_printer::fill_next(const environment *env) 69290075Sobrien{ 693169689Skan unsigned int g; 694169689Skan if (env->fill->is_default()) 69590075Sobrien g = 0; 696169689Skan else { 697169689Skan // currently, only BW support 69890075Sobrien env->fill->get_gray(&g); 69990075Sobrien } 70090075Sobrien char buf[256]; 70190075Sobrien sprintf(buf, "sh %.3g", 1 - double(g)/color::MAX_COLOR_VAL); 70290075Sobrien do_special(buf); 70390075Sobrien} 704132718Skan 70590075Sobrienvoid draw_dvi_printer::draw(int code, int *p, int np, const environment *env) 70690075Sobrien{ 70790075Sobrien char buf[1024]; 70890075Sobrien int fill_flag = 0; 70990075Sobrien switch (code) { 71052284Sobrien case 'C': 71190075Sobrien fill_flag = 1; 71252284Sobrien // fall through 71390075Sobrien case 'c': 71490075Sobrien { 71590075Sobrien // troff adds an extra argument to C 71690075Sobrien if (np != 1 && !(code == 'C' && np == 2)) { 71790075Sobrien error("1 argument required for circle"); 71852284Sobrien break; 71990075Sobrien } 72090075Sobrien moveto(env->hpos+p[0]/2, env->vpos); 72190075Sobrien if (fill_flag) 72290075Sobrien fill_next(env); 72352284Sobrien else 72490075Sobrien set_line_thickness(env); 72590075Sobrien int rad; 72690075Sobrien rad = milliinches(p[0]/2); 72790075Sobrien sprintf(buf, "%s 0 0 %d %d 0 6.28319", 72852284Sobrien (fill_flag ? "ia" : "ar"), 72990075Sobrien rad, 73090075Sobrien rad); 73152284Sobrien do_special(buf); 73252284Sobrien break; 73352284Sobrien } 734132718Skan case 'l': 73552284Sobrien if (np != 2) { 73690075Sobrien error("2 arguments required for line"); 73790075Sobrien break; 73890075Sobrien } 73952284Sobrien moveto(env->hpos, env->vpos); 74052284Sobrien set_line_thickness(env); 74152284Sobrien do_special("pa 0 0"); 74290075Sobrien sprintf(buf, "pa %d %d", milliinches(p[0]), milliinches(p[1])); 74390075Sobrien do_special(buf); 74490075Sobrien do_special("fp"); 74590075Sobrien break; 74690075Sobrien case 'E': 74790075Sobrien fill_flag = 1; 74890075Sobrien // fall through 74990075Sobrien case 'e': 75090075Sobrien if (np != 2) { 75152284Sobrien error("2 arguments required for ellipse"); 75252284Sobrien break; 75352284Sobrien } 75452284Sobrien moveto(env->hpos+p[0]/2, env->vpos); 755132718Skan if (fill_flag) 75690075Sobrien fill_next(env); 75790075Sobrien sprintf(buf, "%s 0 0 %d %d 0 6.28319", 75890075Sobrien (fill_flag ? "ia" : "ar"), 759117395Skan milliinches(p[0]/2), 76090075Sobrien milliinches(p[1]/2)); 76190075Sobrien do_special(buf); 76290075Sobrien break; 76390075Sobrien case 'P': 76490075Sobrien fill_flag = 1; 76590075Sobrien // fall through 766117395Skan case 'p': 76790075Sobrien { 76890075Sobrien if (np & 1) { 76990075Sobrien error("even number of arguments required for polygon"); 770117395Skan break; 771117395Skan } 77290075Sobrien if (np == 0) { 77390075Sobrien error("no arguments for polygon"); 774117395Skan break; 77590075Sobrien } 77690075Sobrien moveto(env->hpos, env->vpos); 77790075Sobrien if (fill_flag) 778132718Skan fill_next(env); 779117395Skan else 780117395Skan set_line_thickness(env); 781117395Skan do_special("pa 0 0"); 782117395Skan int h = 0, v = 0; 783117395Skan for (int i = 0; i < np; i += 2) { 784132718Skan h += p[i]; 785132718Skan v += p[i+1]; 78652284Sobrien sprintf(buf, "pa %d %d", milliinches(h), milliinches(v)); 78752284Sobrien do_special(buf); 78852284Sobrien } 78952284Sobrien do_special("pa 0 0"); 79052284Sobrien do_special(fill_flag ? "ip" : "fp"); 79152284Sobrien break; 79252284Sobrien } 79352284Sobrien case '~': 79452284Sobrien { 79590075Sobrien if (np & 1) { 79652284Sobrien error("even number of arguments required for spline"); 79752284Sobrien break; 798 } 799 if (np == 0) { 800 error("no arguments for spline"); 801 break; 802 } 803 moveto(env->hpos, env->vpos); 804 set_line_thickness(env); 805 do_special("pa 0 0"); 806 int h = 0, v = 0; 807 for (int i = 0; i < np; i += 2) { 808 h += p[i]; 809 v += p[i+1]; 810 sprintf(buf, "pa %d %d", milliinches(h), milliinches(v)); 811 do_special(buf); 812 } 813 do_special("sp"); 814 break; 815 } 816 case 'a': 817 { 818 if (np != 4) { 819 error("4 arguments required for arc"); 820 break; 821 } 822 set_line_thickness(env); 823 double c[2]; 824 if (adjust_arc_center(p, c)) { 825 int rad = milliinches(int(sqrt(c[0]*c[0] + c[1]*c[1]) + .5)); 826 moveto(env->hpos + int(c[0]), env->vpos + int(c[1])); 827 double start = atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0]); 828 double end = atan2(-c[1], -c[0]); 829 if (end - start < 0) 830 start -= 2 * 3.14159265358; 831 sprintf(buf, "ar 0 0 %d %d %f %f", rad, rad, start, end); 832 do_special(buf); 833 } 834 else { 835 moveto(env->hpos, env->vpos); 836 do_special("pa 0 0"); 837 sprintf(buf, 838 "pa %d %d", 839 milliinches(p[0] + p[2]), 840 milliinches(p[1] + p[3])); 841 do_special(buf); 842 do_special("fp"); 843 } 844 break; 845 } 846 case 't': 847 { 848 if (np == 0) { 849 line_thickness = -1; 850 } 851 else { 852 // troff gratuitously adds an extra 0 853 if (np != 1 && np != 2) { 854 error("0 or 1 argument required for thickness"); 855 break; 856 } 857 line_thickness = p[0]; 858 } 859 break; 860 } 861 case 'R': 862 { 863 if (np != 2) { 864 error("2 arguments required for rule"); 865 break; 866 } 867 int dh = p[0]; 868 if (dh == 0) 869 break; 870 int dv = p[1]; 871 if (dv == 0) 872 break; 873 int oh = env->hpos; 874 int ov = env->vpos; 875 if (dv > 0) { 876 ov += dv; 877 dv = -dv; 878 } 879 if (dh < 0) { 880 oh += dh; 881 dh = -dh; 882 } 883 moveto(oh, ov); 884 out1(put_rule); 885 out4(-dv); 886 out4(dh); 887 break; 888 } 889 default: 890 error("unrecognised drawing command `%1'", char(code)); 891 break; 892 } 893} 894 895font *dvi_printer::make_font(const char *nm) 896{ 897 return dvi_font::load_dvi_font(nm); 898} 899 900printer *make_printer() 901{ 902 if (draw_flag) 903 return new draw_dvi_printer; 904 else 905 return new dvi_printer; 906} 907 908static void usage(FILE *stream); 909 910int main(int argc, char **argv) 911{ 912 setlocale(LC_NUMERIC, "C"); 913 program_name = argv[0]; 914 static char stderr_buf[BUFSIZ]; 915 setbuf(stderr, stderr_buf); 916 int c; 917 static const struct option long_options[] = { 918 { "help", no_argument, 0, CHAR_MAX + 1 }, 919 { "version", no_argument, 0, 'v' }, 920 { NULL, 0, 0, 0 } 921 }; 922 while ((c = getopt_long(argc, argv, "dF:I:lp:vw:", long_options, NULL)) 923 != EOF) 924 switch(c) { 925 case 'd': 926 draw_flag = 0; 927 break; 928 case 'l': 929 landscape_flag = 1; 930 break; 931 case 'F': 932 font::command_line_font_dir(optarg); 933 break; 934 case 'I': 935 // ignore include search path 936 break; 937 case 'p': 938 if (!font::scan_papersize(optarg, 0, 939 &user_paper_length, &user_paper_width)) 940 error("invalid custom paper size `%1' ignored", optarg); 941 break; 942 case 'v': 943 { 944 printf("GNU grodvi (groff) version %s\n", Version_string); 945 exit(0); 946 break; 947 } 948 case 'w': 949 if (sscanf(optarg, "%d", &linewidth) != 1 950 || linewidth < 0 || linewidth > 1000) { 951 error("bad line width"); 952 linewidth = DEFAULT_LINEWIDTH; 953 } 954 break; 955 case CHAR_MAX + 1: // --help 956 usage(stdout); 957 exit(0); 958 break; 959 case '?': 960 usage(stderr); 961 exit(1); 962 break; 963 default: 964 assert(0); 965 } 966 SET_BINARY(fileno(stdout)); 967 if (optind >= argc) 968 do_file("-"); 969 else { 970 for (int i = optind; i < argc; i++) 971 do_file(argv[i]); 972 } 973 return 0; 974} 975 976static void usage(FILE *stream) 977{ 978 fprintf(stream, "usage: %s [-dv] [-F dir] [-w n] [files ...]\n", 979 program_name); 980} 981