diff options
Diffstat (limited to 'Build/source/texk/xdvipdfmx/src/spc_dvips.c')
-rw-r--r-- | Build/source/texk/xdvipdfmx/src/spc_dvips.c | 578 |
1 files changed, 572 insertions, 6 deletions
diff --git a/Build/source/texk/xdvipdfmx/src/spc_dvips.c b/Build/source/texk/xdvipdfmx/src/spc_dvips.c index 39578065626..2eac7ebcbd1 100644 --- a/Build/source/texk/xdvipdfmx/src/spc_dvips.c +++ b/Build/source/texk/xdvipdfmx/src/spc_dvips.c @@ -1,4 +1,4 @@ -/* $Header: /home/cvsroot/dvipdfmx/src/spc_dvips.c,v 1.9 2005/08/19 12:06:24 chofchof Exp $ +/* $Header: /home/cvsroot/dvipdfmx/src/spc_dvips.c,v 1.10 2008/02/13 20:22:21 matthias Exp $ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. @@ -32,6 +32,9 @@ #include "dpxfile.h" +#include "dvi.h" +#include "dvicodes.h" + #include "pdfparse.h" #include "pdfdoc.h" @@ -45,8 +48,10 @@ #include "specials.h" #include "spc_util.h" +#include "mfileio.h" #include "spc_dvips.h" +#include "spc_xtx.h" static int block_pending = 0; @@ -54,6 +59,39 @@ static double pending_x = 0.0; static double pending_y = 0.0; static int position_set = 0; +static char** ps_headers = 0; +static int num_ps_headers = 0; + +static int +spc_handler_ps_header (struct spc_env *spe, struct spc_arg *args) +{ + char *ps_header, *pro; + + skip_white(&args->curptr, args->endptr); + if (args->curptr + 1 >= args->endptr || + args->curptr[0] != '=') { + spc_warn(spe, "No filename specified for PSfile special."); + return -1; + } + args->curptr++; + + pro = malloc(args->endptr - args->curptr + 1); + strncpy(pro, args->curptr, args->endptr - args->curptr); + pro[args->endptr - args->curptr] = 0; + ps_header = kpse_find_file(pro, kpse_tex_ps_header_format, 0); + if (!ps_header) { + spc_warn(spe, "PS header %s not found.", pro); + return -1; + } + free(pro); + + if (!(num_ps_headers & 0x0f)) + ps_headers = realloc(ps_headers, sizeof(char*) * (num_ps_headers + 16)); + ps_headers[num_ps_headers++] = ps_header; + args->curptr = args->endptr; + return 0; +} + static char * parse_filename (char **pp, char *endptr) { @@ -119,12 +157,12 @@ spc_handler_ps_file (struct spc_env *spe, struct spc_arg *args) } transform_info_clear(&ti); - if (spc_util_read_dimtrns(spe, &ti, args, 1) < 0) { + if (spc_util_read_dimtrns(spe, &ti, args, NULL, 1) < 0) { RELEASE(filename); return -1; } - form_id = pdf_ximage_findresource(filename, 0, 0); + form_id = pdf_ximage_findresource(filename, 1); if (form_id < 0) { spc_warn(spe, "Failed to read image file: %s", filename); RELEASE(filename); @@ -157,7 +195,7 @@ spc_handler_ps_plotfile (struct spc_env *spe, struct spc_arg *args) return -1; } - form_id = pdf_ximage_findresource(filename, 0, 0); + form_id = pdf_ximage_findresource(filename, 1); if (form_id < 0) { spc_warn(spe, "Could not open PS file: %s", filename); error = -1; @@ -243,6 +281,462 @@ spc_handler_ps_literal (struct spc_env *spe, struct spc_arg *args) return error; } +static char *global_defs = 0; +static char *page_defs = 0; +static char *temporary_defs = 0; +static char *distiller_template = 0; +static pdf_coord *put_stack; +static int put_stack_depth = -1; +static char *gs_in = 0; + +static int +spc_handler_ps_tricks_gdef (struct spc_env *spe, struct spc_arg *args) +{ + FILE* fp; + + fp = fopen(global_defs, "a"); + fwrite(args->curptr, 1, args->endptr - args->curptr, fp); + fprintf(fp, "\n"); + fclose(fp); + + return 0; +} + +static int +spc_handler_ps_tricks_pdef (struct spc_env *spe, struct spc_arg *args) +{ + FILE* fp; + pdf_tmatrix M, T = { 1, 0, 0, 1, 0, 0 }; + pdf_coord pt; + + pdf_dev_currentmatrix(&M); + pdf_dev_get_fixed_point(&pt); + T.e = pt.x; + T.f = pt.y; + pdf_concatmatrix(&M, &T); + if (page_defs == 0) + page_defs = dpx_create_temp_file(); + fp = fopen(page_defs, "a"); + fprintf(fp, "gsave initmatrix [%f %f %f %f %f %f] concat %f %f moveto\n", M.a, M.b, M.c, M.d, M.e, M.f, spe->x_user - pt.x, spe->y_user - pt.y); + fwrite(args->curptr, 1, args->endptr - args->curptr, fp); + fprintf(fp, "\ngrestore\n"); + fclose(fp); + + return 0; +} + +static int +spc_handler_ps_tricks_tdef (struct spc_env *spe, struct spc_arg *args) +{ + FILE* fp; + if (!temporary_defs) + temporary_defs = dpx_create_temp_file(); + fp = fopen(temporary_defs, "w"); + fwrite(args->curptr, 1, args->endptr - args->curptr, fp); + fprintf(fp, "\n"); + fclose(fp); + + return 0; +} + +static int calculate_PS (char *string, int length, double *res1, double *res2); + +static int +spc_handler_ps_tricks_bput (struct spc_env *spe, struct spc_arg *args, int must_def, int pre_def) +{ + char *PutBegin, *formula, *ncLabel; + int label = 0; + pdf_coord tr; + pdf_tmatrix M, T = { 1, 0, 0, 1, 0, 0 }; + + if (must_def != 0) { + ncLabel = strstr(args->curptr, "LPut"); + if (ncLabel != 0 && ncLabel < args->endptr - 3) + label = 1; + ncLabel = strstr(args->curptr, "HPutPos"); + if (ncLabel != 0 && ncLabel < args->endptr - 6) + label = 1; + } + + if (pre_def == 0) { + dpx_delete_temp_file(temporary_defs); + temporary_defs = 0; + } + + pdf_dev_currentmatrix(&M); + formula = malloc(args->endptr - args->curptr + 120); + if (label != 0) { + sprintf(formula, "[%f %f %f %f %f %f] concat %f %f moveto\n", M.a, M.b, M.c, M.d, M.e, M.f, spe->x_user + get_origin(1), spe->y_user + get_origin(0)); + } else + sprintf(formula, "[%f %f %f %f %f %f] concat %f %f moveto\n", M.a, M.b, M.c, M.d, M.e, M.f, spe->x_user, spe->y_user); + strncat(formula, args->curptr, args->endptr - args->curptr); + PutBegin = strstr(formula, "PutBegin"); + strcpy(PutBegin, "exch = ="); + *(PutBegin + 8) = 0; + if (calculate_PS(formula, strlen(formula), &tr.x, &tr.y) == 0) { + if (!(++put_stack_depth & 0x0f)) + put_stack = realloc(put_stack, (put_stack_depth + 16) * sizeof(pdf_coord)); + put_stack[put_stack_depth] = tr; + } + T.e = tr.x; T.f = tr.y; + + pdf_dev_concat(&T); + + if (must_def != 0) { + FILE* fp; + if (!temporary_defs) + temporary_defs = dpx_create_temp_file(); + fp = fopen(temporary_defs, "a"); + fprintf(fp, "gsave\n"); + if (label == 0) + fprintf(fp, "[%f %f %f %f %f %f] concat %f %f moveto\n", M.a, M.b, M.c, M.d, M.e, M.f, spe->x_user, spe->y_user); + fwrite(args->curptr, 1, args->endptr - args->curptr, fp); + fprintf(fp, "\ngrestore\n"); + fclose(fp); + } + + free(formula); + return 0; +} + +static int +spc_handler_ps_tricks_eput (struct spc_env *spe, struct spc_arg *args) +{ + pdf_coord tr = put_stack[put_stack_depth--]; + pdf_tmatrix M = { 1, 0, 0, 1, -tr.x, -tr.y }; + + pdf_dev_concat(&M); + + return 0; +} + +/* Rotation without gsave/grestore. */ +static double* RAngles = 0; +static int RAngleCount = -1; + +static int +spc_handler_ps_tricks_brotate (struct spc_env *spe, struct spc_arg *args) +{ + double value, RAngle = 0; + char *cmd, *RotBegin; + int i, l = args->endptr - args->curptr; + + static char *pre = "tx@Dict begin /RAngle { %f } def\n"; + static char *post = "= end"; + + if (!(++RAngleCount & 0x0f)) + RAngles = realloc(RAngles, (RAngleCount + 16) * sizeof(double)); + for (i = 0; i < RAngleCount; i++) + RAngle += RAngles[i]; + cmd = calloc(l + strlen(pre) + strlen(post) + 12, 1); + sprintf(cmd, pre, RAngle); + strncat(cmd, args->curptr, l); + RotBegin = strstr(cmd, "RotBegin"); + strcpy(RotBegin, post); + if (calculate_PS(cmd, strlen(cmd), &value, 0) != 0) + return -1; + RAngles[RAngleCount] = value; + + return spc_handler_xtx_do_rotate (spe->x_user, spe->y_user, value); +} + +static int +spc_handler_ps_tricks_erotate (struct spc_env *spe, struct spc_arg *args) +{ + double value = RAngles[RAngleCount--]; + + return spc_handler_xtx_do_rotate (spe->x_user, spe->y_user, (-1.0) * value); +} + +static int +check_next_obj(unsigned char * buffer) +{ + switch (buffer[0]) { + case XXX1: + if (buffer[1] < 5) + return 0; + buffer += 2; + break; + case XXX2: + buffer += 3; + break; + case XXX3: + buffer += 4; + break; + case XXX4: + buffer += 5; + break; + default: + return 0; + } + + if (strncmp(buffer, "pst:", 4)) + return 0; + return 1; +} + +static int +spc_handler_ps_tricks_parse_path (struct spc_env *spe, struct spc_arg *args, + int flag) +{ + FILE* fp; + int k; + pdf_tmatrix M; + char *distiller_template = get_distiller_template(); + char *gs_out; + char *clip; + int error; + + if (!distiller_template) + distiller_template = get_distiller_template(); + + pdf_dev_currentmatrix(&M); + if (!gs_in) { + gs_in = dpx_create_temp_file(); + if (!gs_in) { + WARN("Failed to create temporary input file for PSTricks image conversion."); + return -1; + } + fp = fopen(gs_in, "w"); + for (k = 0; k < num_ps_headers; k++) + fprintf(fp, "(%s) run\n", ps_headers[k]); + fprintf(fp, "[%f %f %f %f %f %f] concat %f %f translate 0 0 moveto\n", M.a, M.b, M.c, M.d, M.e, M.f, spe->x_user, spe->y_user); + fprintf(fp, "(%s) run\n", global_defs); + if (page_defs != 0) + fprintf(fp, "(%s) run\n", page_defs); + +#if 0 + fprintf(fp, "/clip {stroke} def\n"); + fwrite(args->curptr, 1, args->endptr - args->curptr, fp); +#else + clip = strstr(args->curptr, " clip"); + if (clip == 0 || clip > args->endptr - 5) { + fprintf(fp, "tx@TextPathDict begin /stroke {} def\n"); + fwrite(args->curptr, 1, args->endptr - args->curptr, fp); + fprintf(fp, "\nend\n"); + fclose(fp); + return 0; + } else { + fwrite(args->curptr, 1, clip - args->curptr, fp); + fprintf(fp, " stroke "); + skip_white(&clip, args->endptr); + parse_ident(&clip, args->endptr); + fwrite(clip, 1, args->endptr - clip, fp); + } +#endif + } else { + fp = fopen(gs_in, "a"); + fprintf(fp, "flattenpath stroke\n"); + } + fclose(fp); + + gs_out = dpx_create_temp_file(); + if (!gs_out) { + WARN("Failed to create temporary output file for PSTricks image conversion."); + RELEASE(gs_in); + gs_in = 0; + return -1; + } + + error = dpx_file_apply_filter(distiller_template, gs_in, gs_out); + if (error) { + WARN("Image format conversion for PSTricks failed."); + RELEASE(gs_in); + gs_in = 0; + return error; + } + + fp = fopen(gs_out, "r"); + if (pdf_copy_clip(fp, 1, 0, 0) != 0) { + spc_warn(spe, "Failed to parse the clipping path."); + RELEASE(gs_in); + gs_in = 0; + RELEASE(gs_out); + return -1; + } + fclose(fp); + + dpx_delete_temp_file(gs_out); + dpx_delete_temp_file(gs_in); + gs_in = 0; + + return 0; +} + +static int +spc_handler_ps_tricks_render (struct spc_env *spe, struct spc_arg *args) +{ + FILE* fp; + int k; + pdf_tmatrix M; + + if (!distiller_template) + distiller_template = get_distiller_template(); + + pdf_dev_currentmatrix(&M); + if (!gs_in) { + gs_in = dpx_create_temp_file(); + if (!gs_in) { + WARN("Failed to create temporary input file for PSTricks image conversion."); + return -1; + } + fp = fopen(gs_in, "w"); + for (k = 0; k < num_ps_headers; k++) + fprintf(fp, "(%s) run\n", ps_headers[k]); + fprintf(fp, "[%f %f %f %f %f %f] concat %f %f translate 0 0 moveto\n", M.a, M.b, M.c, M.d, M.e, M.f, spe->x_user, spe->y_user); + fprintf(fp, "(%s) run\n", global_defs); + if (page_defs != 0) + fprintf(fp, "(%s) run\n", page_defs); + } else + fp = fopen(gs_in, "a"); + + fprintf(fp, "\nsave\n"); + fwrite(args->curptr, 1, args->endptr - args->curptr, fp); + fprintf(fp, "\ncount 1 sub {pop} repeat restore\n"); + + if (check_next_obj(args->endptr)) { + fclose(fp); + } else { + char *distiller_template = get_distiller_template(); + char *gs_out; + int error, form_id; + transform_info p; + transform_info_clear(&p); + pdf_invertmatrix(&M); + p.matrix = M; + + fclose(fp); + + gs_out = dpx_create_temp_file(); + if (!gs_out) { + WARN("Failed to create temporary output file for PSTricks image conversion."); + RELEASE(gs_in); + gs_in = 0; + return -1; + } + + error = dpx_file_apply_filter(distiller_template, gs_in, gs_out); + if (error) { + WARN("Image format conversion for PSTricks failed."); + RELEASE(gs_in); + gs_in = 0; + return error; + } + + form_id = pdf_ximage_findresource(gs_out, 1/*, 0*/); + if (form_id < 0) { + spc_warn(spe, "Failed to read converted PSTricks image file."); + RELEASE(gs_in); + gs_in = 0; + RELEASE(gs_out); + return -1; + } + pdf_dev_put_image(form_id, &p, 0, 0); + + dpx_delete_temp_file(gs_out); + dpx_delete_temp_file(gs_in); + gs_in = 0; + } + + return 0; +} + +typedef enum { + render = 1 << 0, + global_def = 1 << 1, + page_def = 1 << 2, + new_temp = 1 << 3, + add_temp = 1 << 4, + begin_put = 1 << 5, + end_put = 1 << 6, + begin_rotate = 1 << 7, + end_rotate = 1 << 8, + parse = 1 << 9, + req_ref = 1 << 10 +} Operation; + +/* ToDo: all the substring search must be centralized so that * + * keys can be read from external configuration. */ +struct pstricks_key_ { + char * key; + Operation exec; +} pstricks_key[] = { + /* The first 5 are hard-coded here. */ + {"LPut", add_temp | req_ref}, + {"HPutPos", add_temp | req_ref}, + {"PutBegin", begin_put}, + {"RotBegin", begin_rotate}, + {"clip", parse}, + /* The rest can be read from an external source. */ + {"NewNode", page_def | req_ref}, + {"InitNC", render | new_temp}, + {"/Glbx", add_temp}, + {"NewtonSolving", add_temp}, + {"PutEnd", end_put}, + {"RotEnd", end_rotate}, + {"mtrxc", parse}, + {"stroke", render}, + {"fill", render}, + {"Fill", render}, + {" Glbx", req_ref}, + {"TextPathShow", parse}, + {"/rotAngle", page_def}, + {"NAngle", req_ref} +}; + +static int +spc_handler_ps_trickscmd (struct spc_env *spe, struct spc_arg *args) +{ + char *test_string; + int k, error = 0, f_exec = 0; + + /* Hack time! */ + /* The problem is that while any macros in pstricks.tex + * can be overridden by the codes in pstricks.con, you cannot + * modify the pst@Verb specials generated by other PSTricks + * packages. So pstricks generate specials won't signal what + * to expect for you. + */ + test_string = malloc(args->endptr - args->curptr + 1); + strncpy(test_string, args->curptr, args->endptr - args->curptr); + test_string[args->endptr - args->curptr] = 0; + for (k = 0; k < sizeof(pstricks_key) / sizeof(pstricks_key[0]); k++) { + if (strstr(test_string, pstricks_key[k].key) != 0) + f_exec |= pstricks_key[k].exec; + } + free(test_string); + + if (f_exec & new_temp) + error |= spc_handler_ps_tricks_tdef(spe, args); + if (f_exec & render) + error |= spc_handler_ps_tricks_render(spe, args); + if (f_exec & parse) + error |= spc_handler_ps_tricks_parse_path(spe, args, f_exec); + if (f_exec & begin_put) + error |= spc_handler_ps_tricks_bput(spe, args, (f_exec & add_temp), (f_exec & req_ref)); + if (f_exec & end_put) + error |= spc_handler_ps_tricks_eput(spe, args); + if (f_exec & begin_rotate) + error |= spc_handler_ps_tricks_brotate(spe, args); + if (f_exec & end_rotate) + error |= spc_handler_ps_tricks_erotate(spe, args); + if (f_exec & page_def) + error |= spc_handler_ps_tricks_pdef (spe, args); + if (f_exec == 0) + error |= spc_handler_ps_tricks_pdef (spe, args); + + args->curptr = args->endptr; + return error; +} + +static int +spc_handler_ps_tricksobj (struct spc_env *spe, struct spc_arg *args) +{ + int error = spc_handler_ps_tricks_render(spe, args); + args->curptr = args->endptr; + return error; +} + static int spc_handler_ps_default (struct spc_env *spe, struct spc_arg *args) { @@ -283,18 +777,30 @@ spc_handler_ps_default (struct spc_env *spe, struct spc_arg *args) } static struct spc_handler dvips_handlers[] = { + {"header", spc_handler_ps_header}, {"PSfile", spc_handler_ps_file}, {"psfile", spc_handler_ps_file}, {"ps: plotfile", spc_handler_ps_plotfile}, /* FIXME */ {"PS: plotfile", spc_handler_ps_plotfile}, /* FIXME */ {"PS:", spc_handler_ps_literal}, {"ps:", spc_handler_ps_literal}, + {"PST:", spc_handler_ps_trickscmd}, + {"pst:", spc_handler_ps_tricksobj}, {"\" ", spc_handler_ps_default} }; int spc_dvips_at_begin_page (void) { + FILE* fp; + + if (page_defs) { + dpx_delete_temp_file(page_defs); + page_defs = 0; + } + + put_stack_depth = -1; + return 0; } @@ -302,18 +808,31 @@ int spc_dvips_at_end_page (void) { mps_eop_cleanup(); + if (!temporary_defs) { + dpx_delete_temp_file(temporary_defs); + temporary_defs = 0; + } return 0; } int spc_dvips_at_begin_document (void) { + FILE* fp; + + /* This, together with \pscharpath support code, must be moved to xtex.pro header. */ + global_defs = dpx_create_temp_file(); + fp = fopen(global_defs, "w"); + fprintf(fp, "tx@Dict begin /STV {} def end\n"); + fclose(fp); return 0; } int spc_dvips_at_end_document (void) { + dpx_delete_temp_file(global_defs); + dpx_delete_temp_file(page_defs); return 0; } @@ -376,8 +895,8 @@ spc_dvips_setup_handler (struct spc_handler *handle, for (i = 0; i < sizeof(dvips_handlers) / sizeof(struct spc_handler); i++) { - if (keylen == strlen(dvips_handlers[i].key) && - !strncmp(key, dvips_handlers[i].key, keylen)) { + if (keylen <= strlen(dvips_handlers[i].key) && + !strncmp(key, dvips_handlers[i].key, strlen(dvips_handlers[i].key))) { skip_white(&args->curptr, args->endptr); @@ -393,3 +912,50 @@ spc_dvips_setup_handler (struct spc_handler *handle, return -1; } +#ifdef __EMX__ +#define GS_CALCULATOR "gsos2 -q -dNOPAUSE -dBATCH -sDEVICE=nullpage -f " +#else +#define GS_CALCULATOR "gs -q -dNOPAUSE -dBATCH -sDEVICE=nullpage -f " +#endif + +static +int calculate_PS (char *string, int length, double *res1, double *res2) { + char *formula, *cmd; + FILE *fp, *coord; + int k; + + if (res1 == 0 && res2 == 0) + return -1; + formula = dpx_create_temp_file(); + fp = fopen(formula, "w"); + for (k = 0; k < num_ps_headers; k++) + fprintf(fp, "(%s) run\n", ps_headers[k]); + fprintf(fp, "0 0 moveto\n"); + fprintf(fp, "(%s) run\n", global_defs); + if (page_defs != 0) + fprintf(fp, "(%s) run\n", page_defs); + if (temporary_defs) + fprintf(fp, "(%s) run\n", temporary_defs); + fwrite(string, 1, length, fp); + fclose(fp); + k = strlen(GS_CALCULATOR) + strlen(formula) + 2; + cmd = malloc(k); + strcpy(cmd, GS_CALCULATOR); + strcat(cmd, " "); + strcat(cmd, formula); + + coord = popen(cmd, "r"); + if (coord) { + if (res1 == 0) + fscanf(coord, " %lf ", res2); + else if (res2 == 0) + fscanf(coord, " %lf ", res1); + else + fscanf(coord, " %lf %lf ", res1, res2); + } else + return -1; + + pclose(coord); + dpx_delete_temp_file(formula); + return 0; +} |