diff options
author | Karl Berry <karl@freefriends.org> | 2006-01-17 21:41:51 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2006-01-17 21:41:51 +0000 |
commit | 487ca4806cc046076293cf6cc5fbba0db282bac7 (patch) | |
tree | 847b412ab5158dd7bdd7ed7e5a4cc3fbca94be32 /Build/source/texk/dvipdfm/mpost.c | |
parent | a3d3111bfe26b8e5f5bc6049dfb2a4ca2edc7881 (diff) |
texk 1
git-svn-id: svn://tug.org/texlive/trunk@1485 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/dvipdfm/mpost.c')
-rw-r--r-- | Build/source/texk/dvipdfm/mpost.c | 1365 |
1 files changed, 1365 insertions, 0 deletions
diff --git a/Build/source/texk/dvipdfm/mpost.c b/Build/source/texk/dvipdfm/mpost.c new file mode 100644 index 00000000000..4f84393312c --- /dev/null +++ b/Build/source/texk/dvipdfm/mpost.c @@ -0,0 +1,1365 @@ +/* $Header: SCCS/s.mpost.c 1.1 00/08/05 01:52:14-00:00 mwicks@gaspra $ + + This is dvipdfm, a DVI to PDF translator. + Copyright (C) 1998, 1999 by Mark A. Wicks + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + The author may be contacted via the e-mail address + + mwicks@kettering.edu +*/ + +#include <stdlib.h> +#include <ctype.h> +#include <math.h> +#include <string.h> +#include "system.h" +#include "mem.h" +#include "error.h" +#include "mfileio.h" +#include "dvi.h" +#include "pdfobj.h" +#include "pdfspecial.h" +#include "pdfparse.h" +#include "mpost.h" +#include "pdfparse.h" +#include "pdflimits.h" +#include "pdfdev.h" +#include "pdfdoc.h" + +int check_for_mp (FILE *image_file) +{ + rewind (image_file); + /* For now, this is an exact test that must be passed, character for + character */ + mfgets (work_buffer, WORK_BUFFER_SIZE, image_file); + if (strncmp (work_buffer, "%!PS", 4)) + return 0; + mfgets (work_buffer, WORK_BUFFER_SIZE, image_file); + if (strncmp (work_buffer, "%%BoundingBox", strlen("%%BoundingBox"))) + return 0; + mfgets (work_buffer, WORK_BUFFER_SIZE, image_file); + if (strncmp (work_buffer, "%%Creator: MetaPost", strlen("%%Creator: MetaPost"))) + return 0; + return 1; +} + +static struct mp_fonts +{ + char *tex_name; + int font_id; + double pt_size; +} *mp_fonts = NULL; + +int n_mp_fonts = 0, max_mp_fonts = 0; + +static void need_more_mp_fonts (unsigned n) +{ + if (n_mp_fonts + n > max_mp_fonts) { + max_mp_fonts += MAX_FONTS; + mp_fonts = RENEW (mp_fonts, max_mp_fonts, struct mp_fonts); + } +} + + + +int mp_locate_font (char *tex_name, double pt_size) +{ + int result=-1, i; + for (i=0; i<n_mp_fonts; i++) { + if (!strcmp (tex_name, mp_fonts[i].tex_name) && + mp_fonts[i].pt_size == pt_size) + break; + } + need_more_mp_fonts (1); + if (i == n_mp_fonts) { + n_mp_fonts += 1; + mp_fonts[i].tex_name = NEW (strlen(tex_name)+1, char); + strcpy (mp_fonts[i].tex_name, tex_name); + mp_fonts[i].pt_size = pt_size; + /* The following line is a bit of a kludge. MetaPost inclusion + was an afterthought */ + mp_fonts[i].font_id = dev_locate_font (tex_name, + pt_size/dvi_unit_size()); + result = mp_fonts[i].font_id; + } else + result = -1; + return result; +} + +static void release_fonts (void) +{ + int i; + for (i=0; i<n_mp_fonts; i++) { + RELEASE (mp_fonts[i].tex_name); + } + if (mp_fonts) { + RELEASE (mp_fonts); + mp_fonts = NULL; + } + n_mp_fonts = 0; + max_mp_fonts = 0; +} + +int mp_is_font_name (char *tex_name) +{ + int i; + for (i=0; i<n_mp_fonts; i++) { + if (!strcmp (tex_name, mp_fonts[i].tex_name)) + break; + } + if (i < n_mp_fonts) + return 1; + else + return 0; +} + +int mp_fontid (char *tex_name, double pt_size) +{ + int i; + for (i=0; i<n_mp_fonts; i++) { + if (!strcmp (tex_name, mp_fonts[i].tex_name) && + (mp_fonts[i].pt_size == pt_size)) + break; + } + if (i < n_mp_fonts) { + return i; + } + else { + return -1; + } +} + +static int mp_parse_headers (FILE *image_file, struct xform_info *p) +{ + int error = 0; + char *start, *end, *token, *name; + char *llx = NULL, *lly = NULL, *urx = NULL, *ury = NULL; + unsigned long save_position; +#ifdef MEM_DEBUG + MEM_START +#endif + /* Scan for bounding box record */ + for (;;) { + mfgets (work_buffer, WORK_BUFFER_SIZE, image_file); + if (work_buffer[0] != '%' || + !strncmp (work_buffer, "%%BoundingBox:", + strlen("%%BoundingBox"))) + break; + } + if (work_buffer[0] == '%') { /* Found %%BoundingBox */ + start = work_buffer + strlen("%%BoundingBox:"); + end = start+strlen(start); + skip_white (&start, end); + /* Expect 4 numbers or fail */ + if ((llx = parse_number (&start, end)) && + (lly = parse_number (&start, end)) && + (urx = parse_number (&start, end)) && + (ury = parse_number (&start, end))) { + /* Set the crop box to the true bounding box specified in the + file */ + p->c_llx = atof (llx); + p->c_lly = atof (lly); + p->c_urx = atof (urx); + p->c_ury = atof (ury); + } else{ + fprintf (stderr, "\nMissing expected number in bounding box specification:\n"); + dump (start, end); + error = 1; + } + } else { /* Didn't find Bounding box */ + fprintf (stderr, "\nFailed to find an expected BoundingBox record.\n"); + error = 1; + } + if (llx) RELEASE(llx); + if (lly) RELEASE(lly); + if (urx) RELEASE(urx); + if (ury) RELEASE(ury); + /* Got four numbers */ + /* Read all headers--act on *Font records */ + save_position = tell_position(image_file); + while (!error && !feof(image_file) && mfgets (work_buffer, WORK_BUFFER_SIZE, + image_file)) { + if (*work_buffer != '%') { + seek_absolute (image_file, save_position); + break; + } + save_position = tell_position (image_file); + if (*(work_buffer+1) == '*' && + !strncmp (work_buffer+2, "Font:", strlen("Font:"))) { + double ps_ptsize; + start = work_buffer+strlen("%*Font:"); + end = start+strlen(start); + skip_white (&start, end); + if ((name = parse_ident (&start, end))) { + skip_white (&start, end); + } else { + fprintf (stderr, "\nMissing expected font name:\n"); + dump (start, end); + error = 1; + break; + } + if ((token = parse_number (&start, end))) { + ps_ptsize = atof (token); + RELEASE (token); + } else { + fprintf (stderr, "\nMissing expected font point size specification:\n"); + dump (start, end); + error = 1; + break; + } + mp_locate_font (name, ps_ptsize); + RELEASE (name); + } + } +#ifdef MEM_DEBUG + MEM_END +#endif + return !error; +} + +struct point { + double x, y; +}; + +struct curve { + double x[3], y[3]; +}; + +static struct path_element +{ + char type; + void *element; +} *path = NULL; +static int n_path_pts = 0, max_path_pts = 0; +static int path_clip = 0, path_close = 0; + +#define MORE_PATH_POINTS 64 + +static void need_points (int n) +{ + if (n_path_pts+n > max_path_pts) { + max_path_pts += MORE_PATH_POINTS; + path = RENEW (path, max_path_pts, struct path_element); + } + return; +} + +static void clip_path (void) +{ + path_clip = 1; +} + +static void close_path (void) +{ + path_close = 1; +} + +static void add_point_to_path (double x, double y, char type) +{ + struct point *p; + need_points (1); + path[n_path_pts].type = type; + p = NEW (1, struct point); + p->x = x; p->y = y; + path[n_path_pts].element = p; + n_path_pts += 1; + return; +} + +static void add_curve_to_path (double x0, double y0, + double x1, double y1, + double x2, double y2) +{ + struct curve *c; + need_points (1); + c = NEW (1, struct curve); + path[n_path_pts].type = 'c'; + (c->x)[0] = x0; (c->y)[0] = y0; + (c->x)[1] = x1; (c->y)[1] = y1; + (c->x)[2] = x2; (c->y)[2] = y2; + path[n_path_pts].element = c; + n_path_pts += 1; + return; +} + +static void void_path (void) +{ + int i; + for (i=0; i<n_path_pts; i++) { + RELEASE (path[i].element); + } + path_clip = 0; + path_close = 0; + n_path_pts = 0; +} + +static void flush_path (void) +{ + int i, len; + for (i=0; i<n_path_pts; i++) { + switch (path[i].type) { + case 'm': /* moveto */ + /* Moveto must start a new path */ + /* void_path (); */ + case 'l': /* lineto */ + { + struct point *p; + p = path[i].element; + sprintf (work_buffer, "\n%g %g %c", + ROUND(p->x, 0.001), ROUND(p->y, 0.001), + path[i].type); + len = strlen (work_buffer); + pdf_doc_add_to_page (work_buffer, len); + RELEASE (p); + } + break; + case 'c': /* curveto */ + { + struct curve *p; + p = path[i].element; + sprintf (work_buffer, "\n%g %g %g %g %g %g c", + ROUND((p->x)[0], 0.001), ROUND((p->y)[0], 0.001), + ROUND((p->x)[1], 0.001), ROUND((p->y)[1], 0.001), + ROUND((p->x)[2], 0.001), ROUND((p->y)[2], 0.001)); + len = strlen (work_buffer); + pdf_doc_add_to_page (work_buffer, len); + RELEASE (p); + } + break; + default: /* This shouldn't happen! */ + ERROR ("Internal error in mpost.c, flush_path ()"); + } + } + n_path_pts = 0; + if (path_close) { + pdf_doc_add_to_page (" h", 2); + path_close = 0; + } + if (path_clip) { + pdf_doc_add_to_page (" W", 2); + path_clip = 0; + } + return; +} + +static void transform_path (double a, double b, double c, double d, + double e, double f) +{ + double an, bn, cn, dn, en, fn, delta, xn, yn; + unsigned i; + delta = a*d-b*c; + if (delta == 0.0) { + ERROR ("Determinant exactly zero in transform_path()"); + } + an=d/delta; bn=-b/delta; cn=-c/delta; dn=a/delta; + en=(c*f-e*d)/delta, fn=(b*e-a*f)/delta; + for (i=0; i<n_path_pts; i++) { + switch (path[i].type) { + case 'l': + case 'm': + { + struct point *p; + p = path[i].element; + xn = an*(p->x)+cn*(p->y)+en; + yn = bn*(p->x)+dn*(p->y)+fn; + p->x = xn; + p->y = yn; + } + break; + case 'c': + { + int j; + struct curve *c; + c = path[i].element; + for (j=0; j<3; j++) { + xn = an*(c->x)[j]+cn*(c->y)[j]+en; + yn = bn*(c->x)[j]+dn*(c->y)[j]+fn; + (c->x)[j] = xn; (c->y)[j] = yn; + } + } + } + } +} +static void dump_path (void) +{ + unsigned i; + for (i=0; i<n_path_pts; i++) { + switch (path[i].type) { + case 'l': + case 'm': + { + struct point *p; + p = path[i].element; + fprintf (stderr, "\t%g %g %c\n", p->x, p->y, path[i].type); + } + break; + case 'c': + { + struct curve *c; + int j; + c = path[i].element; + for (j=0; j<3; j++) { + fprintf (stderr, "\t%g %g\n", (c->x)[j], (c->y)[j]); + } + fprintf (stderr, "\t\t\tcurveto\n"); + break; + } + } + } +} + +#define PS_STACK_SIZE 1024 +static pdf_obj *stack[PS_STACK_SIZE]; +static unsigned top_stack; + +double x_state, y_state; +static int state = 0; +static int num_saves = 0; + +#define PUSH(o) { \ + if (top_stack<PS_STACK_SIZE) { \ + stack[top_stack++] = o; \ + } else { \ + fprintf (stderr, "PS stack overflow including MetaPost file or inline PS code"); \ + error=1; \ + break; \ + } \ + } + +#define POP_STACK() (top_stack>0?stack[--top_stack]:NULL) + +void dump_stack() +{ + int i; + fprintf (stderr, "\ndump_stack\n"); + for (i=0; i<top_stack; i++) { + pdf_write_obj (stderr, stack[i]); + fprintf (stderr, "\n"); + } +} +#define ADD 1 +#define CLIP 2 +#define CLOSEPATH 3 +#define CONCAT 4 +#define CURVETO 5 +#define DIV 6 +#define DTRANSFORM 7 +#define EXCH 8 +#define FILL 9 +#define FSHOW 10 +#define GSAVE 11 +#define GRESTORE 12 +#define IDTRANSFORM 13 +#define LINETO 14 +#define MOVETO 15 +#define MUL 16 +#define NEWPATH 17 +#define POP 18 +#define RLINETO 19 +#define SCALE 20 +#define SETCMYKCOLOR 21 +#define SETDASH 22 +#define SETGRAY 23 +#define SETLINECAP 24 +#define SETLINEJOIN 25 +#define SETLINEWIDTH 26 +#define SETMITERLIMIT 27 +#define SETRGBCOLOR 28 +#define SHOW 29 +#define SHOWPAGE 30 +#define STROKE 31 +#define SUB 32 +#define TRANSLATE 33 +#define TRUNCATE 34 +#define CURRENTPOINT 35 +#define NEG 36 +#define ROTATE 37 +#define TEXFIG 38 +#define ETEXFIG 39 +#define FONTNAME 99 + +struct operators +{ + char *t; + int v; +} operators[] = { + {"add", ADD}, + {"clip", CLIP}, + {"closepath", CLOSEPATH}, + {"concat", CONCAT}, + {"curveto", CURVETO}, + {"currentpoint", CURRENTPOINT}, /* This is here for rotate + support in graphics package-not MP support */ + {"div", DIV}, + {"dtransform", DTRANSFORM}, + {"exch", EXCH}, + {"fill", FILL}, + {"fshow", FSHOW}, + {"gsave", GSAVE}, + {"grestore", GRESTORE}, + {"idtransform", IDTRANSFORM}, + {"lineto", LINETO}, + {"moveto", MOVETO}, + {"mul", MUL}, + {"neg", NEG}, + {"newpath", NEWPATH}, + {"pop", POP}, + {"rlineto", RLINETO}, + {"rotate", ROTATE}, + {"scale", SCALE}, + {"setcmykcolor", SETCMYKCOLOR}, + {"setdash", SETDASH}, + {"setgray", SETGRAY}, + {"setlinecap", SETLINECAP}, + {"setlinejoin", SETLINEJOIN}, + {"setlinewidth", SETLINEWIDTH}, + {"setmiterlimit", SETMITERLIMIT}, + {"setrgbcolor", SETRGBCOLOR}, + {"show", SHOW}, + {"showpage", SHOWPAGE}, + {"startTexFig", TEXFIG}, + {"endTexFig", ETEXFIG}, + {"stroke", STROKE}, + {"sub", SUB}, + {"translate", TRANSLATE}, + {"truncate", TRUNCATE} +}; + +static int lookup_operator(char *token) +{ + int i, operator; + operator = -1; + for (i=0; i<sizeof(operators)/sizeof(operators[0]); i++) { + if (!strcmp (token, operators[i].t)) { + operator = operators[i].v; + break; + } + } + if (i == sizeof(operators)/sizeof(operators[0]) && + mp_is_font_name (token)) { + operator = FONTNAME; + } + return operator; +} + + +/* Following needed to save texfig state */ + +static long next_fig = 1; +static pdf_obj *fig_xobj = NULL; +struct xform_info *fig_p; +static char fig_res_name[16]; + +static int do_operator(char *token, + double x_user, double y_user) + /* Again, the only piece that needs x_user and y_user is + that piece dealing with texfig */ +{ + int operator, error = 0; + pdf_obj *tmp1=NULL, *tmp2=NULL, *tmp3=NULL, *tmp4 = NULL; + pdf_obj *tmp5=NULL, *tmp6=NULL; + int len; + /* PS to PDF conversion is not so simple. We maintain + state so we can change "gsave fill grestore stroke" to "B". + We need to keep track of what we have seen. This code is not + too smart and could be easily fooled by real postscript. + It makes some assumptions since it is only looking at MetaPost + + States are as follows: + 0: Nothing special + 1: Started a path + 2: Saw gsave in path + 3: Saw a painting operator in state 2(fill, stroke, or newpath) + 4: Saw a grestore in state 3 + */ + operator = lookup_operator (token); + switch (operator) { + case ADD: + tmp1 = POP_STACK(); + tmp2 = POP_STACK(); + if (tmp1 && tmp2) + pdf_set_number (tmp1, + pdf_number_value(tmp1)+pdf_number_value(tmp2)); + if (tmp2) + pdf_release_obj (tmp2); + if (tmp1) + PUSH(tmp1); + break; + case CLIP: + clip_path(); + break; + case CLOSEPATH: + close_path(); + break; + case CONCAT: + tmp1 = POP_STACK(); + if (tmp1 && tmp1 -> type == PDF_ARRAY) { + int i, len = 0; + for (i=0; i<6; i++) { + if (!(tmp2 = pdf_get_array(tmp1, i))) + break; + if (i == 0) { + sprintf (work_buffer+len, "\n"); + len += strlen (work_buffer+len); + } else { + sprintf (work_buffer+len, " "); + len += strlen (work_buffer+len); + } + sprintf (work_buffer+len, "%g", + ROUND(pdf_number_value(tmp2),0.0001)); + len += strlen (work_buffer+len); + } + sprintf (work_buffer+len, " cm"); + len += strlen (work_buffer+len); + pdf_doc_add_to_page (work_buffer, len); + /* Transform pending path, if any */ + transform_path (pdf_number_value(pdf_get_array(tmp1, 0)), + pdf_number_value(pdf_get_array(tmp1, 1)), + pdf_number_value(pdf_get_array(tmp1, 2)), + pdf_number_value(pdf_get_array(tmp1, 3)), + pdf_number_value(pdf_get_array(tmp1, 4)), + pdf_number_value(pdf_get_array(tmp1, 5))); + } else { + fprintf (stderr, "\nMissing array before \"concat\"\n"); + } + if (tmp1) + pdf_release_obj (tmp1); + break; + case CURRENTPOINT: + state = 0; + PUSH (pdf_new_number (x_user)); /* Remember that x_user and y_user */ + PUSH (pdf_new_number (y_user)); /* are off by 0.02 % */ + break; + case CURVETO: + if (state <= 1) /* In path now */ + state = 1; + else { + fprintf (stderr, "\nUnexpected path segment\n"); + } + if ((tmp6 = POP_STACK()) && tmp6->type == PDF_NUMBER && + (tmp5 = POP_STACK()) && tmp5->type == PDF_NUMBER && + (tmp4 = POP_STACK()) && tmp4->type == PDF_NUMBER && + (tmp3 = POP_STACK()) && tmp3->type == PDF_NUMBER && + (tmp2 = POP_STACK()) && tmp2->type == PDF_NUMBER && + (tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) { + add_curve_to_path (pdf_number_value(tmp1), + pdf_number_value(tmp2), + pdf_number_value(tmp3), + pdf_number_value(tmp4), + pdf_number_value(tmp5), + pdf_number_value(tmp6)); + x_state = pdf_number_value (tmp5); + y_state = pdf_number_value (tmp6); + } else { + fprintf (stderr, "\nMissing number(s) before \"curveto\"\n"); + } + if (tmp1) pdf_release_obj (tmp1); + if (tmp2) pdf_release_obj (tmp2); + if (tmp3) pdf_release_obj (tmp3); + if (tmp4) pdf_release_obj (tmp4); + if (tmp5) pdf_release_obj (tmp5); + if (tmp6) pdf_release_obj (tmp6); + break; + case DIV: + tmp2 = POP_STACK(); + tmp1 = POP_STACK(); + if (tmp1 && tmp2) + pdf_set_number (tmp1, + pdf_number_value(tmp1)/pdf_number_value(tmp2)); + if (tmp1) + PUSH(tmp1); + if (tmp2) + pdf_release_obj (tmp2); + break; + case DTRANSFORM: + if ((tmp2 = POP_STACK()) && tmp2 -> type == PDF_NUMBER && + (tmp1 = POP_STACK()) && tmp1 -> type == PDF_NUMBER) { + pdf_set_number (tmp1, pdf_number_value(tmp1)*100.0); + pdf_set_number (tmp2, pdf_number_value(tmp2)*100.0); + PUSH(tmp1); + PUSH(tmp2); + } else { + if (tmp1) + pdf_release_obj (tmp1); + if (tmp2) + pdf_release_obj (tmp2); + fprintf (stderr, "\nExpecting two numbers before \"dtransform\""); + } + break; + case EXCH: + if ((tmp1 = POP_STACK()) && + (tmp2 = POP_STACK())) { + PUSH (tmp1); + PUSH (tmp2); + } else { + if (tmp1) + pdf_release_obj (tmp1); + } + break; + case FILL: + switch (state) { + case 0: + state = 0; + break; + case 1: + flush_path (); + pdf_doc_add_to_page (" f", 2); + state = 0; + break; + case 2: + state = 3; + break; + case 3: + fprintf (stderr, "\nUnexpected fill\n"); + break; + case 4: + flush_path (); + pdf_doc_add_to_page (" B", 2); + state = 0; + break; + } + break; + case FSHOW: + { + int fontid; + if ((tmp3 = POP_STACK()) && (tmp3->type == PDF_NUMBER) && + (tmp2 = POP_STACK()) && (tmp2->type == PDF_STRING) && + (tmp1 = POP_STACK()) && (tmp1->type == PDF_STRING)) { + if ((fontid = mp_fontid (pdf_string_value(tmp2), + pdf_number_value(tmp3))) < 0) { + fprintf (stderr, "\n\"fshow\": Missing font in MetaPost file? %s@%g\n", + (char *) pdf_string_value(tmp2), pdf_number_value(tmp3)); + } + dev_set_string (x_state/dvi_unit_size(), y_state/dvi_unit_size(), + pdf_string_value(tmp1), + pdf_string_length(tmp1), 0, mp_fonts[fontid].font_id); + graphics_mode(); + } + /* Treat fshow as a path terminator of sorts */ + state = 0; + + if (tmp1) + pdf_release_obj (tmp1); + if (tmp2) + pdf_release_obj (tmp2); + if (tmp3) + pdf_release_obj (tmp3); + } + break; + case GSAVE: + switch (state) { + case 0: + pdf_doc_add_to_page ("\nq", 2); + num_saves += 1; + break; + case 1: + state = 2; + break; + case 4: + state = 2; + break; + default: + fprintf (stderr, "\nUnexpected gsave\n"); + break; + } + break; + case GRESTORE: + switch (state) { + case 0: + if (num_saves > 0) { + num_saves -= 1; + pdf_doc_add_to_page ("\nQ", 2); + /* Unfortunately, the following two lines are necessary in case of a font or color + change inside of the save/restore pair. Anything that was done + there must be redone, so in effect, we make no assumptions about + what fonts are active. We act like we are starting a new page */ + dev_reselect_font(); + /* The following line was causing trouble - 1/30/01 */ + /* dev_do_color(); */ + } + else { + fprintf (stderr, "PS special: \"grestore\" ignored. More restores than saves on a page.\n"); + } + break; + case 2: + state = 1; + break; + case 3: + state = 4; + break; + default: + fprintf (stderr, "\nUnexpected grestore\n"); + break; + } + break; + case IDTRANSFORM: + if ((tmp2 = POP_STACK()) && tmp2 -> type == PDF_NUMBER && + (tmp1 = POP_STACK()) && tmp1 -> type == PDF_NUMBER) { + pdf_set_number (tmp1, pdf_number_value(tmp1)/100.0); + pdf_set_number (tmp2, pdf_number_value(tmp2)/100.0); + PUSH(tmp1); + PUSH(tmp2); + } else { + if (tmp1) + pdf_release_obj (tmp1); + if (tmp2) + pdf_release_obj (tmp2); + fprintf (stderr, "\nExpecting two numbers before \"idtransform\""); + } + break; + case LINETO: + { + if (state <= 1) /* In path now */ + state = 1; + else { + fprintf (stderr, "\nUnexpected path segment\n"); + } + if ((tmp2 = POP_STACK()) && tmp2-> type == PDF_NUMBER && + (tmp1 = POP_STACK()) && tmp1-> type == PDF_NUMBER) { + x_state = pdf_number_value (tmp1); + y_state = pdf_number_value (tmp2); + add_point_to_path (x_state, y_state, 'l'); + } + if (tmp1) + pdf_release_obj (tmp1); + if (tmp2) + pdf_release_obj (tmp2); + } + break; + case MOVETO: + if (state <= 1) /* In path now */ + state = 1; + else { + fprintf (stderr, "\nUnexpected path segment\n"); + } + if ((tmp2 = POP_STACK()) && tmp2-> type == PDF_NUMBER && + (tmp1 = POP_STACK()) && tmp1-> type == PDF_NUMBER) { + /* MetaPost likes to ship out a moveto before displayed text. + Save the results so we know where to place the text. Save + the move but don't actually do it unless the next operator is + a graphics operator */ + x_state = pdf_number_value (tmp1); + y_state = pdf_number_value (tmp2); + add_point_to_path (x_state, y_state, 'm'); + } + if (tmp1) + pdf_release_obj (tmp1); + if (tmp2) + pdf_release_obj (tmp2); + break; + case MUL: + tmp2 = POP_STACK(); + tmp1 = POP_STACK(); + if (tmp1 && tmp2) + pdf_set_number (tmp1, + pdf_number_value(tmp1)*pdf_number_value(tmp2)); + if (tmp1) + PUSH(tmp1); + if (tmp2) + pdf_release_obj (tmp2); + break; + case NEG: + tmp1 = POP_STACK(); + if (tmp1 && tmp1 -> type == PDF_NUMBER) { + pdf_set_number (tmp1, -pdf_number_value(tmp1)); + PUSH (tmp1); + } + break; + case NEWPATH: + flush_path (); + pdf_doc_add_to_page ("\nn", 2); + break; + case POP: + tmp1 = POP_STACK(); + if (tmp1) + pdf_release_obj (tmp1); + break; + case RLINETO: + if (state <= 1) /* In path now */ + state = 1; + else { + fprintf (stderr, "\nUnexpected path segment\n"); + } + if ((tmp2 = POP_STACK()) && tmp2->type == PDF_NUMBER && + (tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) { + x_state += pdf_number_value (tmp1); + y_state += pdf_number_value (tmp2); + add_point_to_path (x_state, y_state, 'l'); + } + if (tmp1) + pdf_release_obj (tmp1); + if (tmp2) + pdf_release_obj (tmp2); + break; + case SCALE: + if ((tmp2 = POP_STACK()) && tmp2->type == PDF_NUMBER && + (tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) { + sprintf (work_buffer, "\n%g 0 0 %g 0 0 cm", + ROUND(pdf_number_value (tmp1),0.01), + ROUND(pdf_number_value (tmp2),0.01)); + len = strlen (work_buffer); + transform_path (pdf_number_value(tmp1), 0.0, + 0.0, pdf_number_value(tmp2), 0.0, 0.0); + pdf_doc_add_to_page (work_buffer, len); + } + if (tmp1) + pdf_release_obj (tmp1); + if (tmp2) + pdf_release_obj (tmp2); + break; + case SETCMYKCOLOR: + if ((tmp4 = POP_STACK()) && tmp4->type == PDF_NUMBER && + (tmp3 = POP_STACK()) && tmp3->type == PDF_NUMBER && + (tmp2 = POP_STACK()) && tmp2->type == PDF_NUMBER && + (tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) { + sprintf (work_buffer, "\n%g %g %g %g k", + ROUND(pdf_number_value (tmp1),0.001), + ROUND(pdf_number_value (tmp2),0.001), + ROUND(pdf_number_value (tmp3),0.001), + ROUND(pdf_number_value (tmp4),0.001)); + len = strlen (work_buffer); + pdf_doc_add_to_page (work_buffer, len); + sprintf (work_buffer, "\n%g %g %g %g K", + ROUND(pdf_number_value (tmp1),0.001), + ROUND(pdf_number_value (tmp2),0.001), + ROUND(pdf_number_value (tmp3),0.001), + ROUND(pdf_number_value (tmp4),0.001)); + len = strlen (work_buffer); + pdf_doc_add_to_page (work_buffer, len); + } else { + fprintf (stderr, "\nExpecting four numbers before \"setcmykcolor\"\n"); + } + if (tmp1) + pdf_release_obj (tmp1); + if (tmp2) + pdf_release_obj (tmp2); + if (tmp3) + pdf_release_obj (tmp3); + if (tmp4) + pdf_release_obj (tmp4); + break; + case SETDASH: + if ((tmp2 = POP_STACK()) && tmp2->type == PDF_NUMBER && + (tmp1 = POP_STACK()) && tmp1->type == PDF_ARRAY) { + int i; + pdf_doc_add_to_page ("\n[", 2); + for (i=0;; i++) { + if ((tmp3 = pdf_get_array (tmp1, i)) && + tmp3 -> type == PDF_NUMBER) { + sprintf (work_buffer, " %g", ROUND(pdf_number_value(tmp3),0.01)); + len = strlen (work_buffer); + pdf_doc_add_to_page (work_buffer, len); + } else + break; + } + pdf_doc_add_to_page (" ]", 2); + if (tmp2 -> type == PDF_NUMBER) { + sprintf (work_buffer, " %g d", ROUND(pdf_number_value(tmp2),0.01)); + len = strlen (work_buffer); + pdf_doc_add_to_page (work_buffer, len); + } + } else { + fprintf (stderr, "\nExpecting array and number before \"setdash\""); + } + if (tmp1) + pdf_release_obj (tmp1); + if (tmp2) + pdf_release_obj (tmp2); + break; + case SETGRAY: + if ((tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) { + sprintf (work_buffer, "\n%g g", + ROUND(pdf_number_value (tmp1),0.001)); + len = strlen (work_buffer); + pdf_doc_add_to_page (work_buffer, len); + sprintf (work_buffer, " %g G", + ROUND(pdf_number_value (tmp1),0.001)); + len = strlen (work_buffer); + pdf_doc_add_to_page (work_buffer, len); + } else { + fprintf (stderr, "\nExpecting a number before \"setgray\"\n"); + } + if (tmp1) + pdf_release_obj (tmp1); + break; + case SETLINECAP: + if ((tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) { + sprintf (work_buffer, "\n%g J", pdf_number_value (tmp1)); + len = strlen (work_buffer); + pdf_doc_add_to_page (work_buffer, len); + } else { + fprintf (stderr, "\nExpecting a number before \"setlinecap\"\n"); + } + if (tmp1) + pdf_release_obj (tmp1); + break; + case SETLINEJOIN: + if ((tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) { + sprintf (work_buffer, "\n%g j", pdf_number_value (tmp1)); + len = strlen (work_buffer); + pdf_doc_add_to_page (work_buffer, len); + } else { + fprintf (stderr, "\nExpecting a number before \"setlinejoin\"\n"); + } + if (tmp1) + pdf_release_obj (tmp1); + break; + case SETLINEWIDTH: + if ((tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) { + sprintf (work_buffer, "\n%g w", ROUND(pdf_number_value (tmp1),0.01)); + len = strlen (work_buffer); + pdf_doc_add_to_page (work_buffer, len); + } else { + fprintf (stderr, "\nExpecting a number before \"setlinewidth\"\n"); + } + if (tmp1) + pdf_release_obj (tmp1); + break; + case SETMITERLIMIT: + if ((tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) { + sprintf (work_buffer, "\n%g M", ROUND(pdf_number_value + (tmp1),0.01)); + len = strlen (work_buffer); + pdf_doc_add_to_page (work_buffer, len); + } else { + fprintf (stderr, "\nExpecting a number before \"setmiterlimit\"\n"); + } + if (tmp1) + pdf_release_obj (tmp1); + break; + case SETRGBCOLOR: + if ((tmp3 = POP_STACK()) && tmp3->type == PDF_NUMBER && + (tmp2 = POP_STACK()) && tmp2->type == PDF_NUMBER && + (tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) { + sprintf (work_buffer, "\n%g %g %g rg", + ROUND(pdf_number_value (tmp1),0.001), + ROUND(pdf_number_value (tmp2),0.001), + ROUND(pdf_number_value (tmp3),0.001)); + len = strlen (work_buffer); + pdf_doc_add_to_page (work_buffer, len); + sprintf (work_buffer, "\n%g %g %g RG", + ROUND(pdf_number_value (tmp1),0.001), + ROUND(pdf_number_value (tmp2),0.001), + ROUND(pdf_number_value (tmp3),0.001)); + len = strlen (work_buffer); + pdf_doc_add_to_page (work_buffer, len); + } else { + fprintf (stderr, "\nExpecting three numbers before \"setrgbcolor\"\n"); + } + if (tmp1) + pdf_release_obj (tmp1); + if (tmp2) + pdf_release_obj (tmp2); + if (tmp3) + pdf_release_obj (tmp3); + break; + case SHOWPAGE: + /* Let's ignore this for now */ + void_path (); + break; + case STROKE: + switch (state) { + case 0: + state = 0; + break; + case 1: + flush_path (); + pdf_doc_add_to_page (" S", 2); + state = 0; + break; + case 2: + state = 3; + break; + case 3: + fprintf (stderr, "\nUnexpected fill\n"); + break; + case 4: + flush_path (); + pdf_doc_add_to_page (" B", 2); + state = 0; + break; + } + break; + case SUB: + tmp2 = POP_STACK(); + tmp1 = POP_STACK(); + if (tmp1 && tmp2) + pdf_set_number (tmp1, + pdf_number_value(tmp1)-pdf_number_value(tmp2)); + if (tmp1) + PUSH(tmp1); + if (tmp2) + pdf_release_obj (tmp2); + break; + case ROTATE: + if ((tmp1 = POP_STACK()) && (tmp1 -> type == PDF_NUMBER)) { + double theta = pdf_number_value(tmp1)*M_PI/180.0; + sprintf (work_buffer, "\n%.4f %.4f %.4f %.4f 0 0 cm", + cos(theta), -sin(theta), + sin(theta), cos(theta)); + len = strlen (work_buffer); + pdf_doc_add_to_page (work_buffer, len); + } + if (tmp1) + pdf_release_obj (tmp1); + break; + case TEXFIG: + if ((tmp6 = POP_STACK()) && (tmp6 -> type == PDF_NUMBER) && + (tmp5 = POP_STACK()) && (tmp5 -> type == PDF_NUMBER) && + (tmp4 = POP_STACK()) && (tmp4 -> type == PDF_NUMBER) && + (tmp3 = POP_STACK()) && (tmp3 -> type == PDF_NUMBER) && + (tmp2 = POP_STACK()) && (tmp2 -> type == PDF_NUMBER) && + (tmp1 = POP_STACK()) && (tmp1 -> type == PDF_NUMBER)) { + double dvi2pts = dvi_unit_size(); + fig_p = new_xform_info (); + fig_p -> width = pdf_number_value(tmp1)*dvi2pts; + fig_p -> height = pdf_number_value(tmp2)*dvi2pts; + fig_p -> c_llx = pdf_number_value(tmp3)*dvi2pts; + fig_p -> c_lly = pdf_number_value(tmp4)*dvi2pts; + fig_p -> c_urx = pdf_number_value(tmp5)*dvi2pts; + fig_p -> c_ury = pdf_number_value(tmp6)*dvi2pts; + pdf_scale_image (fig_p); + sprintf (fig_res_name, "Tf%ld", next_fig); + fig_xobj = begin_form_xobj (fig_p->c_llx, -fig_p->c_ury, fig_p->c_llx, -fig_p->c_lly, + fig_p->c_urx, -fig_p->c_ury, fig_res_name); + } + if (tmp1) pdf_release_obj(tmp1); + if (tmp2) pdf_release_obj(tmp2); + if (tmp3) pdf_release_obj(tmp3); + if (tmp4) pdf_release_obj(tmp4); + if (tmp5) pdf_release_obj(tmp5); + if (tmp6) pdf_release_obj(tmp6); + break; + case ETEXFIG: + if (fig_xobj) { + next_fig += 1; + end_form_xobj (); + pdf_doc_add_to_page_xobjects (fig_res_name, pdf_ref_obj(fig_xobj)); + pdf_release_obj (fig_xobj); + fig_xobj = NULL; + pdf_doc_add_to_page ("\nq", 2); + add_xform_matrix (x_user, y_user, fig_p->xscale, -fig_p->yscale, fig_p->rotate); + if (fig_p->depth != 0.0) + add_xform_matrix (0.0, -fig_p->depth, 1.0, -1.0, 0.0); + release_xform_info (fig_p); + sprintf (work_buffer, " /%s Do Q", fig_res_name); + len = strlen (work_buffer); + pdf_doc_add_to_page (work_buffer, len); + } else { + fprintf (stderr, "\nendTexFig without valid startTexFig ignored\n"); + } + break; + case TRANSLATE: + if ((tmp2 = POP_STACK()) && tmp2->type == PDF_NUMBER && + (tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) { + sprintf (work_buffer, "\n1 0 0 1 %g %g cm", + ROUND(pdf_number_value (tmp1),0.01), + ROUND(pdf_number_value (tmp2),0.01)); + len = strlen (work_buffer); + pdf_doc_add_to_page (work_buffer, len); + transform_path (1.0, 0.0, 0.0, 1.0, + pdf_number_value (tmp1), + pdf_number_value (tmp2)); + } + if (tmp1) + pdf_release_obj (tmp1); + if (tmp2) + pdf_release_obj (tmp2); + break; + case TRUNCATE: + if ((tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) { + double val=pdf_number_value(tmp1); + pdf_set_number (tmp1, val>0? floor(val): ceil(val)); + PUSH (tmp1); + } else if (tmp1) + pdf_release_obj (tmp1); + break; + case FONTNAME: + PUSH (pdf_new_string (token, strlen(token))); + break; + default: + fprintf (stderr, + "\nIgnoring remaining special text following unknown PS operator: \"%s\"\n", token); + error = 1; + break; + } + return !error; +} + +static int do_one_ps_line (char **start, char *end, + double x_user, double y_user) + /* the only sections that need to know x_user and y _user are those + dealing with texfig */ +{ + char *token, *save = NULL; + pdf_obj *obj; + int error = 0; + skip_white (start, end); + while (*start < end && !error) { + save = *start; + if (isdigit (**start) || **start == '-' || **start == '.' ) { + token = parse_number (start, end); + PUSH (pdf_new_number(atof(token))); + RELEASE (token); + } else if (**start == '[' && /* This code assumes that arrays are contained on one line */ + (obj = parse_pdf_array (start, end))) { + PUSH (obj); + } else if (**start == '(' && + (obj = parse_pdf_string (start, end))) { + PUSH (obj); + } else if (**start == '/') { + fprintf (stderr, "\nUnable to handle names in raw PS code."); + dump (*start, end); + error = 1; + } else { + token = parse_ident (start, end); + if (!token || !do_operator (token, x_user, y_user)) { + error = 1; + } + if (token) + RELEASE (token); + } + skip_white (start, end); + } + if (*start < end) { + fprintf (stderr, "\nRemainder of line unparsed."); + dump (*start, end); + } + return !error; +} + +static char line_buffer[1024]; +int parse_contents (FILE *image_file) +{ + int error = 0; + top_stack = 0; + x_state = 0.0; + y_state = 0.0; + state = 0; + while (!feof(image_file) && mfgets (line_buffer, sizeof(line_buffer), + image_file)) { + char *start, *end; + start = line_buffer; + end = start+strlen(line_buffer); + if (!do_one_ps_line (&start, end, 0.0, 0.0)) { + error = 1; + break; + } + } + return !error; +} + +int do_raw_ps_special (char **start, char* end, int cleanup, + double x_user, double y_user) +{ + int error = 0; + state = 0; + do_one_ps_line (start, end, x_user, y_user); + if (cleanup) + mp_cleanup(1); + return !error; +} + +void mp_cleanup (int sloppy_ok) +{ + release_fonts(); + if (state != 0) { + if (!sloppy_ok) + fprintf (stderr, "mp_cleanup(): State not zero\n"); + state = 0; + } + if (top_stack != 0) { + if (!sloppy_ok) + fprintf (stderr, "\nPS/MetaPost: PS stack not empty at end of figure!\n"); + } + /* Cleanup paths */ + while (top_stack > 0) { + pdf_obj *p; + if ((p=POP_STACK())) + pdf_release_obj (p); + } + if (n_path_pts > 0) { + if (!sloppy_ok) { + fprintf (stderr, "\nPS/MetaPost: Pending path at end of figure!\n"); + dump_path (); + } + void_path (); + } + if (max_path_pts > 0) { + RELEASE (path); + path = NULL; + max_path_pts = 0; + } +} + +void mp_eop_cleanup(void) +{ + mp_cleanup(1); + num_saves = 0; +} + + +/* mp inclusion is a bit of a hack. The routine + * starts a form at the lower left corner of + * the page and then calls begin_form_xobj telling + * it to record the image drawn there and bundle it + * up in an xojbect. This allows us to use the coordinates + * in the MP file directly. This appears to be the + * easiest way to be able to use the dev_set_string() + * command (with its scaled and extended fonts) without + * getting all confused about the coordinate system. + * After the xobject is created, the whole thing can + * be scaled any way the user wants */ + +pdf_obj *mp_include (FILE *image_file, struct xform_info *p, + char *res_name, double x_user, double y_user) +{ + pdf_obj *xobj = NULL; + rewind (image_file); + if (mp_parse_headers (image_file, p)) { + /* Looks like an MP file. Setup xobj "capture" */ + pdf_scale_image (p); + xobj = begin_form_xobj (p->u_llx,p->u_lly, p->c_llx, p->c_lly, + p->c_urx, p->c_ury, res_name); + if (!xobj) + return NULL; + /* Flesh out the contents */ + if (!parse_contents (image_file)) { + fprintf (stderr, "Errors occured while interpreting MetaPost file.\n\n"); + } + /* Finish off the form */ + end_form_xobj(); + } else { + fprintf (stderr, "\nErrors occured while scanning MetaPost file headers.\n"); + } + mp_cleanup(0); + return xobj; +} + +/* struct xform_info *texfig_info (void) +{ + struct xform_info *p; + p = new_xform_info (); + p -> user_bbox = 1; + p -> width = fig_width; + p -> height = fig_height; + p -> u_llx = fig_llx; + p -> u_lly = fig_lly; + p -> u_urx = fig_urx; + p -> u_ury = fig_ury; + return p; +} */ |