diff options
Diffstat (limited to 'contrib/groff/src/devices/grops/ps.cc')
-rw-r--r-- | contrib/groff/src/devices/grops/ps.cc | 258 |
1 files changed, 165 insertions, 93 deletions
diff --git a/contrib/groff/src/devices/grops/ps.cc b/contrib/groff/src/devices/grops/ps.cc index a467f04..47d1f65 100644 --- a/contrib/groff/src/devices/grops/ps.cc +++ b/contrib/groff/src/devices/grops/ps.cc @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001 +/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002 Free Software Foundation, Inc. Written by James Clark (jjc@jclark.com) @@ -23,6 +23,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "stringclass.h" #include "cset.h" #include "nonposix.h" +#include "paper.h" #include "ps.h" #include <time.h> @@ -42,6 +43,7 @@ static int linewidth = -1; // Non-zero means generate PostScript code that guesses the paper // length using the imageable area. static int guess_flag = 0; +static double user_paper_length = 0; // Non-zero if -b was specified on the command line. static int bflag = 0; @@ -319,7 +321,7 @@ ps_output &ps_output::put_fix_number(int i) ps_output &ps_output::put_float(double d) { char buf[128]; - sprintf(buf, "%.4f", d); + sprintf(buf, "%.3g", d); int len = strlen(buf); if (col > 0 && col + len + need_space > max_line_length) { putc('\n', fp); @@ -354,6 +356,26 @@ ps_output &ps_output::put_symbol(const char *s) return *this; } +ps_output &ps_output::put_color(unsigned int c) +{ + char buf[128]; + sprintf(buf, "%.3g", double(c) / color::MAX_COLOR_VAL); + int len = strlen(buf); + if (col > 0 && col + len + need_space > max_line_length) { + putc('\n', fp); + col = 0; + need_space = 0; + } + if (need_space) { + putc(' ', fp); + col++; + } + fputs(buf, fp); + col += len; + need_space = 1; + return *this; +} + ps_output &ps_output::put_literal_symbol(const char *s) { int len = strlen(s); @@ -476,13 +498,13 @@ class ps_printer : public printer { int sbuf_space_code; int sbuf_kern; style sbuf_style; + color sbuf_color; // the current PS color style output_style; int output_hpos; int output_vpos; int output_draw_point_size; int line_thickness; int output_line_thickness; - int fill; unsigned char output_space_code; enum { MAX_DEFINED_STYLES = 50 }; style defined_styles[MAX_DEFINED_STYLES]; @@ -504,13 +526,15 @@ class ps_printer : public printer { void do_file(char *, const environment *); void do_invis(char *, const environment *); void do_endinvis(char *, const environment *); - void set_line_thickness(const environment *); - void fill_path(); + void set_line_thickness_and_color(const environment *); + void fill_path(const environment *); void encode_fonts(); void define_encoding(const char *, int); void reencode_font(ps_font *); + void set_color(color *c, int fill = 0); + public: - ps_printer(); + ps_printer(double); ~ps_printer(); void set_char(int i, font *f, const environment *env, int w, const char *name); void draw(int code, int *p, int np, const environment *env); @@ -521,14 +545,14 @@ public: void end_of_line(); }; -ps_printer::ps_printer() +// `pl' is in inches +ps_printer::ps_printer(double pl) : out(0, MAX_LINE_LENGTH), pages_output(0), sbuf_len(0), output_hpos(-1), output_vpos(-1), line_thickness(-1), - fill(FILL_MAX + 1), ndefined_styles(0), next_encoding_index(0), ndefs(0), @@ -553,9 +577,12 @@ ps_printer::ps_printer() res = r; out.set_fixed_point(point); space_char_index = font::name_to_index("space"); - paper_length = font::paperlength; + if (pl == 0) + paper_length = font::paperlength; + else + paper_length = int(pl * font::res + 0.5); if (paper_length == 0) - paper_length = 11*font::res; + paper_length = 11 * font::res; equalise_spaces = font::res >= 72000; } @@ -590,7 +617,8 @@ void ps_printer::set_char(int i, font *f, const environment *env, int w, const c if (sbuf_len > 0) { if (sbuf_len < SBUF_SIZE && sty == sbuf_style - && sbuf_vpos == env->vpos) { + && sbuf_vpos == env->vpos + && sbuf_color == *env->col) { if (sbuf_end_hpos == env->hpos) { sbuf[sbuf_len++] = code; sbuf_end_hpos += w + sbuf_kern; @@ -645,6 +673,8 @@ void ps_printer::set_char(int i, font *f, const environment *env, int w, const c sbuf_space_width = 0; sbuf_space_count = sbuf_space_diff_count = 0; sbuf_kern = 0; + if (sbuf_color != *env->col) + set_color(env->col); } static char *make_encoding_name(int encoding_index) @@ -693,7 +723,8 @@ void ps_printer::define_encoding(const char *encoding, int encoding_index) a_delete vec[i]; } } - out.put_delimiter(']').put_symbol("def"); + out.put_delimiter(']') + .put_symbol("def"); } void ps_printer::reencode_font(ps_font *f) @@ -759,18 +790,60 @@ void ps_printer::set_style(const style &sty) int h = sty.height == 0 ? sty.point_size : sty.height; h *= font::res/(72*font::sizescale); int c = int(h*tan(radians(sty.slant)) + .5); - out.put_fix_number(c).put_fix_number(h).put_literal_symbol(psname) + out.put_fix_number(c) + .put_fix_number(h) + .put_literal_symbol(psname) .put_symbol("MF"); } else { - out.put_literal_symbol(psname).put_symbol("SF"); + out.put_literal_symbol(psname) + .put_symbol("SF"); } defined_styles[ndefined_styles++] = sty; } +void ps_printer::set_color(color *col, int fill) +{ + sbuf_color = *col; + unsigned int components[4]; + char s[3]; + color_scheme cs = col->get_components(components); + s[0] = fill ? 'F' : 'C'; + s[2] = 0; + switch (cs) { + case DEFAULT: // black + out.put_symbol("0"); + s[1] = 'g'; + break; + case RGB: + out.put_color(Red) + .put_color(Green) + .put_color(Blue); + s[1] = 'r'; + break; + case CMY: + col->get_cmyk(&Cyan, &Magenta, &Yellow, &Black); + // fall through + case CMYK: + out.put_color(Cyan) + .put_color(Magenta) + .put_color(Yellow) + .put_color(Black); + s[1] = 'k'; + break; + case GRAY: + out.put_color(Gray); + s[1] = 'g'; + break; + } + out.put_symbol(s); +} + void ps_printer::set_space_code(unsigned char c) { - out.put_literal_symbol("SC").put_number(c).put_symbol("def"); + out.put_literal_symbol("SC") + .put_number(c) + .put_symbol("def"); } void ps_printer::end_of_line() @@ -863,39 +936,43 @@ void ps_printer::flush_sbuf() sbuf_len = 0; } - -void ps_printer::set_line_thickness(const environment *env) +void ps_printer::set_line_thickness_and_color(const environment *env) { if (line_thickness < 0) { if (output_draw_point_size != env->size) { // we ought to check for overflow here int lw = ((font::res/(72*font::sizescale))*linewidth*env->size)/1000; - out.put_fix_number(lw).put_symbol("LW"); + out.put_fix_number(lw) + .put_symbol("LW"); output_draw_point_size = env->size; output_line_thickness = -1; } } else { if (output_line_thickness != line_thickness) { - out.put_fix_number(line_thickness).put_symbol("LW"); + out.put_fix_number(line_thickness) + .put_symbol("LW"); output_line_thickness = line_thickness; output_draw_point_size = -1; } } + if (sbuf_color != *env->col) + set_color(env->col); } -void ps_printer::fill_path() +void ps_printer::fill_path(const environment *env) { - if (fill > FILL_MAX) - out.put_symbol("BL"); + if (sbuf_color == *env->fill) + out.put_symbol("FL"); else - out.put_float(transform_fill(fill)).put_symbol("FL"); + set_color(env->fill, 1); } void ps_printer::draw(int code, int *p, int np, const environment *env) { if (invis_count > 0) return; + flush_sbuf(); int fill_flag = 0; switch (code) { case 'C': @@ -911,11 +988,10 @@ void ps_printer::draw(int code, int *p, int np, const environment *env) .put_fix_number(env->vpos) .put_fix_number(p[0]/2) .put_symbol("DC"); - if (fill_flag) { - fill_path(); - } + if (fill_flag) + fill_path(env); else { - set_line_thickness(env); + set_line_thickness_and_color(env); out.put_symbol("ST"); } break; @@ -924,7 +1000,7 @@ void ps_printer::draw(int code, int *p, int np, const environment *env) error("2 arguments required for line"); break; } - set_line_thickness(env); + set_line_thickness_and_color(env); out.put_fix_number(p[0] + env->hpos) .put_fix_number(p[1] + env->vpos) .put_fix_number(env->hpos) @@ -944,11 +1020,10 @@ void ps_printer::draw(int code, int *p, int np, const environment *env) .put_fix_number(env->hpos + p[0]/2) .put_fix_number(env->vpos) .put_symbol("DE"); - if (fill_flag) { - fill_path(); - } + if (fill_flag) + fill_path(env); else { - set_line_thickness(env); + set_line_thickness_and_color(env); out.put_symbol("ST"); } break; @@ -973,11 +1048,10 @@ void ps_printer::draw(int code, int *p, int np, const environment *env) .put_fix_number(p[i+1]) .put_symbol("RL"); out.put_symbol("CL"); - if (fill_flag) { - fill_path(); - } + if (fill_flag) + fill_path(env); else { - set_line_thickness(env); + set_line_thickness_and_color(env); out.put_symbol("ST"); } break; @@ -1015,7 +1089,7 @@ void ps_printer::draw(int code, int *p, int np, const environment *env) out.put_fix_number(p[np - 2] - p[np - 2]/2) .put_fix_number(p[np - 1] - p[np - 1]/2) .put_symbol("RL"); - set_line_thickness(env); + set_line_thickness_and_color(env); out.put_symbol("ST"); } break; @@ -1025,7 +1099,7 @@ void ps_printer::draw(int code, int *p, int np, const environment *env) error("4 arguments required for arc"); break; } - set_line_thickness(env); + set_line_thickness_and_color(env); double c[2]; if (adjust_arc_center(p, c)) out.put_fix_number(env->hpos + int(c[0])) @@ -1043,60 +1117,47 @@ void ps_printer::draw(int code, int *p, int np, const environment *env) } 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 'f': - { + if (np == 0) + line_thickness = -1; + else { + // troff gratuitously adds an extra 0 if (np != 1 && np != 2) { - error("1 argument required for fill"); + error("0 or 1 argument required for thickness"); break; } - fill = p[0]; - if (fill < 0 || fill > FILL_MAX) { - // This means fill with the current color. - fill = FILL_MAX + 1; - } - break; - } + line_thickness = p[0]; + } + break; default: error("unrecognised drawing command `%1'", char(code)); break; } - output_hpos = output_vpos = -1; } - void ps_printer::begin_page(int n) { - out.begin_comment("Page:").comment_arg(i_to_a(n)); - out.comment_arg(i_to_a(++pages_output)).end_comment(); + out.begin_comment("Page:") + .comment_arg(i_to_a(n)); + out.comment_arg(i_to_a(++pages_output)) + .end_comment(); output_style.f = 0; output_space_code = 32; output_draw_point_size = -1; output_line_thickness = -1; output_hpos = output_vpos = -1; ndefined_styles = 0; - out.simple_comment("BeginPageSetup"); - out.put_symbol("BP"); - out.simple_comment("EndPageSetup"); + out.simple_comment("BeginPageSetup") + .put_symbol("BP") + .simple_comment("EndPageSetup"); + if (sbuf_color != default_color) + set_color(&sbuf_color); } void ps_printer::end_page(int) { flush_sbuf(); + set_color(&default_color); out.put_symbol("EP"); if (invis_count != 0) { error("missing `endinvis' command"); @@ -1111,9 +1172,9 @@ font *ps_printer::make_font(const char *nm) ps_printer::~ps_printer() { - out.simple_comment("Trailer"); - out.put_symbol("end"); - out.simple_comment("EOF"); + out.simple_comment("Trailer") + .put_symbol("end") + .simple_comment("EOF"); if (fseek(tempfp, 0L, 0) < 0) fatal("fseek on temporary file failed"); fputs("%!PS-Adobe-", stdout); @@ -1142,8 +1203,12 @@ ps_printer::~ps_printer() rm.need_font(psf->get_internal_name()); } rm.print_header_comments(out); - out.begin_comment("Pages:").comment_arg(i_to_a(pages_output)).end_comment(); - out.begin_comment("PageOrder:").comment_arg("Ascend").end_comment(); + out.begin_comment("Pages:") + .comment_arg(i_to_a(pages_output)) + .end_comment(); + out.begin_comment("PageOrder:") + .comment_arg("Ascend") + .end_comment(); #if 0 fprintf(out.get_file(), "%%%%DocumentMedia: () %g %g 0 () ()\n", font::paperwidth*72.0/font::res, @@ -1164,7 +1229,8 @@ ps_printer::~ps_printer() out.simple_comment("BeginSetup"); } rm.document_setup(out); - out.put_symbol(dict_name).put_symbol("begin"); + out.put_symbol(dict_name) + .put_symbol("begin"); if (ndefs > 0) ndefs += DEFS_DICT_SPARE; out.put_literal_symbol(defs_dict_name) @@ -1184,8 +1250,12 @@ ps_printer::~ps_printer() out.special(defs.contents()); out.put_symbol("end"); if (ncopies != 1) - out.put_literal_symbol("#copies").put_number(ncopies).put_symbol("def"); - out.put_literal_symbol("RES").put_number(res).put_symbol("def"); + out.put_literal_symbol("#copies") + .put_number(ncopies) + .put_symbol("def"); + out.put_literal_symbol("RES") + .put_number(res) + .put_symbol("def"); out.put_literal_symbol("PL"); if (guess_flag) out.put_symbol("PLG"); @@ -1246,7 +1316,7 @@ void ps_printer::special(char *arg, const environment *env, char type) for (; *p != '\0' && *p != ' ' && *p != '\n'; p++) ; if (*command == '\0') { - error("X command without `ps:' tag ignored"); + error("empty X command ignored"); return; } for (unsigned int i = 0; i < sizeof(proc_table)/sizeof(proc_table[0]); i++) @@ -1474,7 +1544,7 @@ void ps_printer::do_endinvis(char *, const environment *) printer *make_printer() { - return new ps_printer; + return new ps_printer(user_paper_length); } static void usage(FILE *stream); @@ -1491,21 +1561,23 @@ int main(int argc, char **argv) { "version", no_argument, 0, 'v' }, { NULL, 0, 0, 0 } }; - while ((c = getopt_long(argc, argv, "F:P:glmc:w:vb:", long_options, NULL)) + while ((c = getopt_long(argc, argv, "b:c:F:glmp:P:vw:", long_options, NULL)) != EOF) switch(c) { - case 'v': - { - printf("GNU grops (groff) version %s\n", Version_string); - exit(0); - break; - } + case 'b': + // XXX check this + broken_flags = atoi(optarg); + bflag = 1; + break; case 'c': if (sscanf(optarg, "%d", &ncopies) != 1 || ncopies <= 0) { error("bad number of copies `%s'", optarg); ncopies = 1; } break; + case 'F': + font::command_line_font_dir(optarg); + break; case 'g': guess_flag = 1; break; @@ -1515,8 +1587,9 @@ int main(int argc, char **argv) case 'm': manual_feed_flag = 1; break; - case 'F': - font::command_line_font_dir(optarg); + case 'p': + if (!font::scan_papersize(optarg, 0, &user_paper_length, 0)) + error("invalid custom paper size `%1' ignored", optarg); break; case 'P': env = "GROPS_PROLOGUE"; @@ -1526,17 +1599,16 @@ int main(int argc, char **argv) if (putenv(strsave(env.contents()))) fatal("putenv failed"); break; + case 'v': + printf("GNU grops (groff) version %s\n", Version_string); + exit(0); + break; case 'w': if (sscanf(optarg, "%d", &linewidth) != 1 || linewidth < 0) { error("bad linewidth `%1'", optarg); linewidth = -1; } break; - case 'b': - // XXX check this - broken_flags = atoi(optarg); - bflag = 1; - break; case CHAR_MAX + 1: // --help usage(stdout); exit(0); |