1 /* Copyright (C) 1989, 1995, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved. 2 3 This file is part of AFPL Ghostscript. 4 5 AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or 6 distributor accepts any responsibility for the consequences of using it, or 7 for whether it serves any particular purpose or works at all, unless he or 8 she says so in writing. Refer to the Aladdin Free Public License (the 9 "License") for full details. 10 11 Every copy of AFPL Ghostscript must include a copy of the License, normally 12 in a plain ASCII text file named PUBLIC. The License grants you the right 13 to copy, modify and redistribute AFPL Ghostscript, but only under certain 14 conditions described in the License. Among other things, the License 15 requires that the copyright notice and this notice be preserved on all 16 copies. 17 */ 18 19 /*$Id: zpath1.c,v 1.2 2000/09/19 19:00:55 lpd Exp $ */ 20 /* PostScript Level 1 additional path operators */ 21 #include "memory_.h" 22 #include "ghost.h" 23 #include "oper.h" 24 #include "oparc.h" /* for prototypes */ 25 #include "estack.h" /* for pathforall */ 26 #include "ialloc.h" 27 #include "igstate.h" 28 #include "gsstruct.h" 29 #include "gspath.h" 30 #include "store.h" 31 32 /* Forward references */ 33 private int common_arc(P2(i_ctx_t *, 34 int (*)(P6(gs_state *, floatp, floatp, floatp, floatp, floatp)))); 35 private int common_arct(P2(i_ctx_t *, float *)); 36 37 /* <x> <y> <r> <ang1> <ang2> arc - */ 38 int 39 zarc(i_ctx_t *i_ctx_p) 40 { 41 return common_arc(i_ctx_p, gs_arc); 42 } 43 44 /* <x> <y> <r> <ang1> <ang2> arcn - */ 45 int 46 zarcn(i_ctx_t *i_ctx_p) 47 { 48 return common_arc(i_ctx_p, gs_arcn); 49 } 50 51 /* Common code for arc[n] */ 52 private int 53 common_arc(i_ctx_t *i_ctx_p, 54 int (*aproc)(P6(gs_state *, floatp, floatp, floatp, floatp, floatp))) 55 { 56 os_ptr op = osp; 57 double xyra[5]; /* x, y, r, ang1, ang2 */ 58 int code = num_params(op, 5, xyra); 59 60 if (code < 0) 61 return code; 62 code = (*aproc)(igs, xyra[0], xyra[1], xyra[2], xyra[3], xyra[4]); 63 if (code >= 0) 64 pop(5); 65 return code; 66 } 67 68 /* <x1> <y1> <x2> <y2> <r> arct - */ 69 int 70 zarct(i_ctx_t *i_ctx_p) 71 { 72 int code = common_arct(i_ctx_p, (float *)0); 73 74 if (code < 0) 75 return code; 76 pop(5); 77 return 0; 78 } 79 80 /* <x1> <y1> <x2> <y2> <r> arcto <xt1> <yt1> <xt2> <yt2> */ 81 private int 82 zarcto(i_ctx_t *i_ctx_p) 83 { 84 os_ptr op = osp; 85 float tanxy[4]; /* xt1, yt1, xt2, yt2 */ 86 int code = common_arct(i_ctx_p, tanxy); 87 88 if (code < 0) 89 return code; 90 make_real(op - 4, tanxy[0]); 91 make_real(op - 3, tanxy[1]); 92 make_real(op - 2, tanxy[2]); 93 make_real(op - 1, tanxy[3]); 94 pop(1); 95 return 0; 96 } 97 98 /* Common code for arct[o] */ 99 private int 100 common_arct(i_ctx_t *i_ctx_p, float *tanxy) 101 { 102 os_ptr op = osp; 103 double args[5]; /* x1, y1, x2, y2, r */ 104 int code = num_params(op, 5, args); 105 106 if (code < 0) 107 return code; 108 return gs_arcto(igs, args[0], args[1], args[2], args[3], args[4], tanxy); 109 } 110 111 /* - .dashpath - */ 112 private int 113 zdashpath(i_ctx_t *i_ctx_p) 114 { 115 return gs_dashpath(igs); 116 } 117 118 /* - flattenpath - */ 119 private int 120 zflattenpath(i_ctx_t *i_ctx_p) 121 { 122 return gs_flattenpath(igs); 123 } 124 125 /* - reversepath - */ 126 private int 127 zreversepath(i_ctx_t *i_ctx_p) 128 { 129 return gs_reversepath(igs); 130 } 131 132 /* - strokepath - */ 133 private int 134 zstrokepath(i_ctx_t *i_ctx_p) 135 { 136 return gs_strokepath(igs); 137 } 138 139 /* - clippath - */ 140 private int 141 zclippath(i_ctx_t *i_ctx_p) 142 { 143 return gs_clippath(igs); 144 } 145 146 /* <bool> .pathbbox <llx> <lly> <urx> <ury> */ 147 private int 148 zpathbbox(i_ctx_t *i_ctx_p) 149 { 150 os_ptr op = osp; 151 gs_rect box; 152 int code; 153 154 check_type(*op, t_boolean); 155 code = gs_upathbbox(igs, &box, op->value.boolval); 156 if (code < 0) 157 return code; 158 push(3); 159 make_real(op - 3, box.p.x); 160 make_real(op - 2, box.p.y); 161 make_real(op - 1, box.q.x); 162 make_real(op, box.q.y); 163 return 0; 164 } 165 166 /* <moveproc> <lineproc> <curveproc> <closeproc> pathforall - */ 167 private int path_continue(P1(i_ctx_t *)); 168 private int path_cleanup(P1(i_ctx_t *)); 169 private int 170 zpathforall(i_ctx_t *i_ctx_p) 171 { 172 os_ptr op = osp; 173 gs_path_enum *penum; 174 int code; 175 176 check_proc(op[-3]); 177 check_proc(op[-2]); 178 check_proc(op[-1]); 179 check_proc(*op); 180 check_estack(8); 181 if ((penum = gs_path_enum_alloc(imemory, "pathforall")) == 0) 182 return_error(e_VMerror); 183 code = gs_path_enum_init(penum, igs); 184 if (code < 0) { 185 ifree_object(penum, "path_cleanup"); 186 return code; 187 } 188 /* Push a mark, the four procedures, and the path enumerator. */ 189 push_mark_estack(es_for, path_cleanup); /* iterator */ 190 memcpy(esp + 1, op - 3, 4 * sizeof(ref)); /* 4 procs */ 191 esp += 5; 192 make_istruct(esp, 0, penum); 193 push_op_estack(path_continue); 194 pop(4); 195 op -= 4; 196 return o_push_estack; 197 } 198 /* Continuation procedure for pathforall */ 199 private void pf_push(P3(i_ctx_t *, gs_point *, int)); 200 private int 201 path_continue(i_ctx_t *i_ctx_p) 202 { 203 gs_path_enum *penum = r_ptr(esp, gs_path_enum); 204 gs_point ppts[3]; 205 int code; 206 207 /* Make sure we have room on the o-stack for the worst case */ 208 /* before we enumerate the next path element. */ 209 check_ostack(6); /* 3 points for curveto */ 210 code = gs_path_enum_next(penum, ppts); 211 switch (code) { 212 case 0: /* all done */ 213 esp -= 6; 214 path_cleanup(i_ctx_p); 215 return o_pop_estack; 216 default: /* error */ 217 return code; 218 case gs_pe_moveto: 219 esp[2] = esp[-4]; /* moveto proc */ 220 pf_push(i_ctx_p, ppts, 1); 221 break; 222 case gs_pe_lineto: 223 esp[2] = esp[-3]; /* lineto proc */ 224 pf_push(i_ctx_p, ppts, 1); 225 break; 226 case gs_pe_curveto: 227 esp[2] = esp[-2]; /* curveto proc */ 228 pf_push(i_ctx_p, ppts, 3); 229 break; 230 case gs_pe_closepath: 231 esp[2] = esp[-1]; /* closepath proc */ 232 break; 233 } 234 push_op_estack(path_continue); 235 ++esp; /* include pushed procedure */ 236 return o_push_estack; 237 } 238 /* Internal procedure to push one or more points */ 239 private void 240 pf_push(i_ctx_t *i_ctx_p, gs_point * ppts, int n) 241 { 242 os_ptr op = osp; 243 244 while (n--) { 245 op += 2; 246 make_real(op - 1, ppts->x); 247 make_real(op, ppts->y); 248 ppts++; 249 } 250 osp = op; 251 } 252 /* Clean up after a pathforall */ 253 private int 254 path_cleanup(i_ctx_t *i_ctx_p) 255 { 256 gs_path_enum *penum = r_ptr(esp + 6, gs_path_enum); 257 258 gs_path_enum_cleanup(penum); 259 ifree_object(penum, "path_cleanup"); 260 return 0; 261 } 262 263 /* ------ Initialization procedure ------ */ 264 265 const op_def zpath1_op_defs[] = 266 { 267 {"5arc", zarc}, 268 {"5arcn", zarcn}, 269 {"5arct", zarct}, 270 {"5arcto", zarcto}, 271 {"0clippath", zclippath}, 272 {"0.dashpath", zdashpath}, 273 {"0flattenpath", zflattenpath}, 274 {"4pathforall", zpathforall}, 275 {"0reversepath", zreversepath}, 276 {"0strokepath", zstrokepath}, 277 {"1.pathbbox", zpathbbox}, 278 /* Internal operators */ 279 {"0%path_continue", path_continue}, 280 op_def_end(0) 281 }; 282