📄 ps.cc
字号:
output_hpos(-1), output_vpos(-1), out(0, 79), ndefined_styles(0), next_encoding_index(0), line_thickness(-1), fill(FILL_MAX + 1), ndefs(0), invis_count(0){ tempfp = xtmpfile(); out.set_file(tempfp); if (linewidth < 0) linewidth = DEFAULT_LINEWIDTH; if (font::hor != 1) fatal("horizontal resolution must be 1"); if (font::vert != 1) fatal("vertical resolution must be 1"); if (font::res % (font::sizescale*72) != 0) fatal("res must be a multiple of 72*sizescale"); int r = font::res; int point = 0; while (r % 10 == 0) { r /= 10; point++; } res = r; out.set_fixed_point(point); space_char_index = font::name_to_index("space"); paper_length = font::paperlength; if (paper_length == 0) paper_length = 11*font::res; equalise_spaces = font::res >= 72000;}int ps_printer::set_encoding_index(ps_font *f){ if (f->encoding_index >= 0) return f->encoding_index; for (font_pointer_list *p = font_list; p; p = p->next) if (p->p != f) { char *encoding = ((ps_font *)p->p)->encoding; int encoding_index = ((ps_font *)p->p)->encoding_index; if (encoding != 0 && encoding_index >= 0 && strcmp(f->encoding, encoding) == 0) { return f->encoding_index = encoding_index; } } return f->encoding_index = next_encoding_index++;}void ps_printer::set_char(int i, font *f, const environment *env, int w){ if (i == space_char_index || invis_count > 0) return; unsigned char code = f->get_code(i); style sty(f, env->size, env->height, env->slant); if (sty.slant != 0) { if (sty.slant > 80 || sty.slant < -80) { error("silly slant `%1' degrees", sty.slant); sty.slant = 0; } } if (sbuf_len > 0) { if (sbuf_len < SBUF_SIZE && sty == sbuf_style && sbuf_vpos == env->vpos) { if (sbuf_end_hpos == env->hpos) { sbuf[sbuf_len++] = code; sbuf_end_hpos += w + sbuf_kern; return; } if (sbuf_len == 1 && sbuf_kern == 0) { sbuf_kern = env->hpos - sbuf_end_hpos; sbuf_end_hpos = env->hpos + sbuf_kern + w; sbuf[sbuf_len++] = code; return; } /* If sbuf_end_hpos - sbuf_kern == env->hpos, we are better off starting a new string. */ if (sbuf_len < SBUF_SIZE - 1 && env->hpos >= sbuf_end_hpos && (sbuf_kern == 0 || sbuf_end_hpos - sbuf_kern != env->hpos)) { if (sbuf_space_code < 0) { if (f->contains(space_char_index)) { sbuf_space_code = f->get_code(space_char_index); sbuf_space_width = env->hpos - sbuf_end_hpos; sbuf_end_hpos = env->hpos + w + sbuf_kern; sbuf[sbuf_len++] = sbuf_space_code; sbuf[sbuf_len++] = code; sbuf_space_count++; return; } } else { int diff = env->hpos - sbuf_end_hpos - sbuf_space_width; if (diff == 0 || (equalise_spaces && (diff == 1 || diff == -1))) { sbuf_end_hpos = env->hpos + w + sbuf_kern; sbuf[sbuf_len++] = sbuf_space_code; sbuf[sbuf_len++] = code; sbuf_space_count++; if (diff == 1) sbuf_space_diff_count++; else if (diff == -1) sbuf_space_diff_count--; return; } } } } flush_sbuf(); } sbuf_len = 1; sbuf[0] = code; sbuf_end_hpos = env->hpos + w; sbuf_start_hpos = env->hpos; sbuf_vpos = env->vpos; sbuf_style = sty; sbuf_space_code = -1; sbuf_space_width = 0; sbuf_space_count = sbuf_space_diff_count = 0; sbuf_kern = 0;}int is_small_h(int n){ return n < (font::res*2)/72 && n > -(font::res*10)/72;}int is_small_v(int n){ return n < (font::res*4)/72 && n > -(font::res*4)/72;}static char *make_encoding_name(int encoding_index){ static char buf[3 + INT_DIGITS + 1]; sprintf(buf, "ENC%d", encoding_index); return buf;}const char *const WS = " \t\n\r";void ps_printer::define_encoding(const char *encoding, int encoding_index){ char *vec[256]; for (int i = 0; i < 256; i++) vec[i] = 0; char *path; FILE *fp = font::open_file(encoding, &path); if (fp == 0) fatal("can't open encoding file `%1'", encoding); int lineno = 1; char buf[256]; while (fgets(buf, 512, fp) != 0) { char *p = buf; while (isascii(*p) && isspace(*p)) p++; if (*p != '#' && *p != '\0' && (p = strtok(buf, WS)) != 0) { char *q = strtok(0, WS); int n; if (q == 0 || sscanf(q, "%d", &n) != 1 || n < 0 || n >= 256) fatal_with_file_and_line(path, lineno, "bad second field"); vec[n] = new char[strlen(p) + 1]; strcpy(vec[n], p); } lineno++; } a_delete path; out.put_literal_symbol(make_encoding_name(encoding_index)); out.put_delimiter('['); for (i = 0; i < 256; i++) { if (vec[i] == 0) out.put_literal_symbol(".notdef"); else { out.put_literal_symbol(vec[i]); a_delete vec[i]; } } out.put_delimiter(']').put_symbol("def");}void ps_printer::reencode_font(ps_font *f){ out.put_literal_symbol(f->reencoded_name) .put_symbol(make_encoding_name(f->encoding_index)) .put_literal_symbol(f->get_internal_name()) .put_symbol("RE");}void ps_printer::encode_fonts(){ if (next_encoding_index == 0) return; char *done_encoding = new char[next_encoding_index]; for (int i = 0; i < next_encoding_index; i++) done_encoding[i] = 0; for (font_pointer_list *f = font_list; f; f = f->next) { int encoding_index = ((ps_font *)f->p)->encoding_index; if (encoding_index >= 0) { assert(encoding_index < next_encoding_index); if (!done_encoding[encoding_index]) { done_encoding[encoding_index] = 1; define_encoding(((ps_font *)f->p)->encoding, encoding_index); } reencode_font((ps_font *)f->p); } } a_delete done_encoding;}void ps_printer::set_style(const style &sty){ char buf[1 + INT_DIGITS + 1]; for (int i = 0; i < ndefined_styles; i++) if (sty == defined_styles[i]) { sprintf(buf, "F%d", i); out.put_symbol(buf); return; } if (ndefined_styles >= MAX_DEFINED_STYLES) ndefined_styles = 0; sprintf(buf, "F%d", ndefined_styles); out.put_literal_symbol(buf); const char *psname = sty.f->get_internal_name(); if (psname == 0) fatal("no internalname specified for font `%1'", sty.f->get_name()); char *encoding = ((ps_font *)sty.f)->encoding; if (encoding != 0) { char *s = ((ps_font *)sty.f)->reencoded_name; if (s == 0) { int ei = set_encoding_index((ps_font *)sty.f); char *tem = new char[strlen(psname) + 1 + INT_DIGITS + 1]; sprintf(tem, "%s@%d", psname, ei); psname = tem; ((ps_font *)sty.f)->reencoded_name = tem; } else psname = s; } out.put_fix_number((font::res/(72*font::sizescale))*sty.point_size); if (sty.height != 0 || sty.slant != 0) { 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) .put_symbol("MF"); } else { out.put_literal_symbol(psname).put_symbol("SF"); } defined_styles[ndefined_styles++] = sty;}void ps_printer::set_space_code(unsigned char c){ out.put_literal_symbol("SC").put_number(c).put_symbol("def");}void ps_printer::end_of_line(){ flush_sbuf(); // this ensures that we do an absolute motion to the beginning of a line output_vpos = output_hpos = -1;}void ps_printer::flush_sbuf(){ enum { NONE, RELATIVE_H, RELATIVE_V, RELATIVE_HV, ABSOLUTE } motion = NONE; int space_flag = 0; if (sbuf_len == 0) return; if (output_style != sbuf_style) { set_style(sbuf_style); output_style = sbuf_style; } int extra_space = 0; if (output_hpos < 0 || output_vpos < 0 || !is_small_h(output_hpos - sbuf_start_hpos) || !is_small_v(output_vpos - sbuf_vpos)) motion = ABSOLUTE; else { if (output_hpos != sbuf_start_hpos) motion = RELATIVE_H; if (output_vpos != sbuf_vpos) { if (motion != NONE) motion = RELATIVE_HV; else motion = RELATIVE_V; } } if (sbuf_space_code >= 0) { int w = sbuf_style.f->get_width(space_char_index, sbuf_style.point_size); if (w + sbuf_kern != sbuf_space_width) { if (sbuf_space_code != output_space_code) { set_space_code(sbuf_space_code); output_space_code = sbuf_space_code; } space_flag = 1; extra_space = sbuf_space_width - w - sbuf_kern; if (sbuf_space_diff_count > sbuf_space_count/2) extra_space++; else if (sbuf_space_diff_count < -(sbuf_space_count/2)) extra_space--; } } if (space_flag) out.put_fix_number(extra_space); if (sbuf_kern != 0) out.put_fix_number(sbuf_kern); out.put_string(sbuf, sbuf_len); char sym[2]; sym[0] = 'A' + motion*4 + space_flag + 2*(sbuf_kern != 0); sym[1] = '\0'; switch (motion) { case NONE: break; case ABSOLUTE: out.put_fix_number(sbuf_start_hpos) .put_fix_number(sbuf_vpos); break; case RELATIVE_H: out.put_fix_number(sbuf_start_hpos - output_hpos); break; case RELATIVE_V: out.put_fix_number(sbuf_vpos - output_vpos); break; case RELATIVE_HV: out.put_fix_number(sbuf_start_hpos - output_hpos) .put_fix_number(sbuf_vpos - output_vpos); break; default: assert(0); } out.put_symbol(sym); output_hpos = sbuf_end_hpos; output_vpos = sbuf_vpos; sbuf_len = 0;}void ps_printer::set_line_thickness(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"); 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"); output_line_thickness = line_thickness; output_draw_point_size = -1; } }}void ps_printer::fill_path(){ if (fill > FILL_MAX) out.put_symbol("BL"); else out.put_float(transform_fill(fill)).put_symbol("FL");}void ps_printer::draw(int code, int *p, int np, const environment *env){ if (invis_count > 0) return; 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; } out.put_fix_number(env->hpos + p[0]/2) .put_fix_number(env->vpos) .put_fix_number(p[0]/2) .put_symbol("DC"); if (fill_flag) { fill_path(); } else { set_line_thickness(env); out.put_symbol("ST"); } break; case 'l': if (np != 2) { error("2 arguments required for line"); break; } set_line_thickness(env); out.put_fix_number(p[0] + env->hpos) .put_fix_number(p[1] + env->vpos) .put_fix_number(env->hpos) .put_fix_number(env->vpos) .put_symbol("DL"); break; case 'E': fill_flag = 1; // fall through case 'e': if (np != 2) { error("2 arguments required for ellipse"); break; } out.put_fix_number(p[0]) .put_fix_number(p[1]) .put_fix_number(env->hpos + p[0]/2) .put_fix_number(env->vpos) .put_symbol("DE"); if (fill_flag) { fill_path(); } else { set_line_thickness(env); out.put_symbol("ST"); } 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; } out.put_fix_number(env->hpos) .put_fix_number(env->vpos) .put_symbol("MT"); for (int i = 0; i < np; i += 2) out.put_fix_number(p[i]) .put_fix_number(p[i+1]) .put_symbol("RL"); out.put_symbol("CL"); if (fill_flag) { fill_path(); } else { set_line_thickness(env); out.put_symbol("ST"); } break; } case '~': { if (np & 1) { error("even number of arguments required for spline"); break; } if (np == 0) { error("no arguments for spline"); break; } out.put_fix_number(env->hpos) .put_fix_number(env->vpos) .put_symbol("MT"); out.put_fix_number(p[0]/2) .put_fix_number(p[1]/2) .put_symbol("RL"); /* tnum/tden should be between 0 and 1; the closer it is to 1 the tighter the curve will be to the guiding lines; 2/3 is the standard value */ const int tnum = 2; const int tden = 3; for (int i = 0; i < np - 2; i += 2) { out.put_fix_number((p[i]*tnum)/(2*tden)) .put_fix_number((p[i + 1]*tnum)/(2*tden)) .put_fix_number(p[i]/2 + (p[i + 2]*(tden - tnum))/(2*tden)) .put_fix_number(p[i + 1]/2 + (p[i + 3]*(tden - tnum))/(2*tden)) .put_fix_number((p[i] - p[i]/2) + p[i + 2]/2) .put_fix_number((p[i + 1] - p[i + 1]/2) + p[i + 3]/2) .put_symbol("RC"); } 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); out.put_symbol("ST"); } break; case 'a': {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -