123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484 |
- /* Copyright (C) 1990, 1996, 1997, 1998, 1999, 2000 Aladdin Enterprises. All rights reserved.
-
- This file is part of AFPL Ghostscript.
-
- AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or
- distributor accepts any responsibility for the consequences of using it, or
- for whether it serves any particular purpose or works at all, unless he or
- she says so in writing. Refer to the Aladdin Free Public License (the
- "License") for full details.
-
- Every copy of AFPL Ghostscript must include a copy of the License, normally
- in a plain ASCII text file named PUBLIC. The License grants you the right
- to copy, modify and redistribute AFPL Ghostscript, but only under certain
- conditions described in the License. Among other things, the License
- requires that the copyright notice and this notice be preserved on all
- copies.
- */
- /*$Id: zdps1.c,v 1.3 2000/12/02 20:39:37 lpd Exp $ */
- /* Level 2 / Display PostScript graphics extensions */
- #include "ghost.h"
- #include "oper.h"
- #include "gsmatrix.h"
- #include "gspath.h"
- #include "gspath2.h"
- #include "gsstate.h"
- #include "ialloc.h"
- #include "igstate.h"
- #include "ivmspace.h"
- #include "store.h"
- #include "stream.h"
- #include "ibnum.h"
- /* Forward references */
- private int gstate_unshare(P1(i_ctx_t *));
- /* Structure descriptors */
- public_st_igstate_obj();
- /* Extend the `copy' operator to deal with gstates. */
- /* This is done with a hack -- we know that gstates are the only */
- /* t_astruct subtype that implements copy. */
- private int
- z1copy(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- int code = zcopy(i_ctx_p);
- if (code >= 0)
- return code;
- if (!r_has_type(op, t_astruct))
- return code;
- return zcopy_gstate(i_ctx_p);
- }
- /* ------ Graphics state ------ */
- /* <bool> setstrokeadjust - */
- private int
- zsetstrokeadjust(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- check_type(*op, t_boolean);
- gs_setstrokeadjust(igs, op->value.boolval);
- pop(1);
- return 0;
- }
- /* - currentstrokeadjust <bool> */
- private int
- zcurrentstrokeadjust(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- push(1);
- make_bool(op, gs_currentstrokeadjust(igs));
- return 0;
- }
- /* ------ Graphics state objects ------ */
- /*
- * Check to make sure that all the elements of a graphics state
- * can be stored in the given allocation space.
- */
- /* ****** DOESN'T CHECK THE NON-REFS. ****** */
- private int
- gstate_check_space(i_ctx_t *i_ctx_p, int_gstate *isp, uint space)
- {
- /*
- * ****** WORKAROUND ALERT ******
- * This code doesn't check the space of the non-refs, or copy their
- * contents, so it can create dangling references from global VM to
- * local VM. Because of this, we simply disallow writing into gstates
- * in global VM (including creating them in the first place) if the
- * save level is greater than 0.
- * ****** WORKAROUND ALERT ******
- */
- #if 1 /* ****** WORKAROUND ****** */
- if (space != avm_local && imemory_save_level(iimemory) > 0)
- return_error(e_invalidaccess);
- #endif /* ****** END ****** */
- #define gsref_check(p) store_check_space(space, p)
- int_gstate_map_refs(isp, gsref_check);
- #undef gsref_check
- return 0;
- }
- /* - gstate <gstate> */
- int
- zgstate(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- int code = gstate_check_space(i_ctx_p, istate, icurrent_space);
- igstate_obj *pigo;
- gs_state *pnew;
- int_gstate *isp;
- if (code < 0)
- return code;
- pigo = ialloc_struct(igstate_obj, &st_igstate_obj, "gstate");
- if (pigo == 0)
- return_error(e_VMerror);
- pnew = gs_state_copy(igs, imemory);
- if (pnew == 0) {
- ifree_object(pigo, "gstate");
- return_error(e_VMerror);
- }
- isp = gs_int_gstate(pnew);
- int_gstate_map_refs(isp, ref_mark_new);
- push(1);
- /*
- * Since igstate_obj isn't a ref, but only contains a ref, save won't
- * clear its l_new bit automatically, and restore won't set it
- * automatically; we have to make sure this ref is on the changes chain.
- */
- make_iastruct(op, a_all, pigo);
- make_null(&pigo->gstate);
- ref_save(op, &pigo->gstate, "gstate");
- make_istruct_new(&pigo->gstate, 0, pnew);
- return 0;
- }
- /* copy for gstates */
- int
- zcopy_gstate(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- os_ptr op1 = op - 1;
- gs_state *pgs;
- gs_state *pgs1;
- int_gstate *pistate;
- gs_memory_t *mem;
- int code;
- check_stype(*op, st_igstate_obj);
- check_stype(*op1, st_igstate_obj);
- check_write(*op);
- code = gstate_unshare(i_ctx_p);
- if (code < 0)
- return code;
- pgs = igstate_ptr(op);
- pgs1 = igstate_ptr(op1);
- pistate = gs_int_gstate(pgs);
- code = gstate_check_space(i_ctx_p, gs_int_gstate(pgs1), r_space(op));
- if (code < 0)
- return code;
- #define gsref_save(p) ref_save(op, p, "copygstate")
- int_gstate_map_refs(pistate, gsref_save);
- #undef gsref_save
- mem = gs_state_swap_memory(pgs, imemory);
- code = gs_copygstate(pgs, pgs1);
- gs_state_swap_memory(pgs, mem);
- if (code < 0)
- return code;
- int_gstate_map_refs(pistate, ref_mark_new);
- *op1 = *op;
- pop(1);
- return 0;
- }
- /* <gstate> currentgstate <gstate> */
- int
- zcurrentgstate(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- gs_state *pgs;
- int_gstate *pistate;
- int code;
- gs_memory_t *mem;
- check_stype(*op, st_igstate_obj);
- check_write(*op);
- code = gstate_unshare(i_ctx_p);
- if (code < 0)
- return code;
- pgs = igstate_ptr(op);
- pistate = gs_int_gstate(pgs);
- code = gstate_check_space(i_ctx_p, istate, r_space(op));
- if (code < 0)
- return code;
- #define gsref_save(p) ref_save(op, p, "currentgstate")
- int_gstate_map_refs(pistate, gsref_save);
- #undef gsref_save
- mem = gs_state_swap_memory(pgs, imemory);
- code = gs_currentgstate(pgs, igs);
- gs_state_swap_memory(pgs, mem);
- if (code < 0)
- return code;
- int_gstate_map_refs(pistate, ref_mark_new);
- return 0;
- }
- /* <gstate> setgstate - */
- int
- zsetgstate(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- int code;
- check_stype(*op, st_igstate_obj);
- check_read(*op);
- code = gs_setgstate(igs, igstate_ptr(op));
- if (code < 0)
- return code;
- pop(1);
- return 0;
- }
- /* ------ Rectangles ------- */
- /*
- * We preallocate a short list for rectangles, because
- * the rectangle operators usually will involve very few rectangles.
- */
- #define MAX_LOCAL_RECTS 5
- typedef struct local_rects_s {
- gs_rect *pr;
- uint count;
- gs_rect rl[MAX_LOCAL_RECTS];
- } local_rects_t;
- /* Forward references */
- private int rect_get(P3(local_rects_t *, os_ptr, gs_memory_t *));
- private void rect_release(P2(local_rects_t *, gs_memory_t *));
- /* <x> <y> <width> <height> .rectappend - */
- /* <numarray|numstring> .rectappend - */
- private int
- zrectappend(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- local_rects_t lr;
- int npop = rect_get(&lr, op, imemory);
- int code;
- if (npop < 0)
- return npop;
- code = gs_rectappend(igs, lr.pr, lr.count);
- rect_release(&lr, imemory);
- if (code < 0)
- return code;
- pop(npop);
- return 0;
- }
- /* <x> <y> <width> <height> rectclip - */
- /* <numarray|numstring> rectclip - */
- private int
- zrectclip(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- local_rects_t lr;
- int npop = rect_get(&lr, op, imemory);
- int code;
- if (npop < 0)
- return npop;
- code = gs_rectclip(igs, lr.pr, lr.count);
- rect_release(&lr, imemory);
- if (code < 0)
- return code;
- pop(npop);
- return 0;
- }
- /* <x> <y> <width> <height> rectfill - */
- /* <numarray|numstring> rectfill - */
- private int
- zrectfill(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- local_rects_t lr;
- int npop = rect_get(&lr, op, imemory);
- int code;
- if (npop < 0)
- return npop;
- code = gs_rectfill(igs, lr.pr, lr.count);
- rect_release(&lr, imemory);
- if (code < 0)
- return code;
- pop(npop);
- return 0;
- }
- /* <x> <y> <width> <height> rectstroke - */
- /* <numarray|numstring> rectstroke - */
- private int
- zrectstroke(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- gs_matrix mat;
- local_rects_t lr;
- int npop, code;
- if (read_matrix(op, &mat) >= 0) {
- /* Concatenate the matrix to the CTM just before stroking the path. */
- npop = rect_get(&lr, op - 1, imemory);
- if (npop < 0)
- return npop;
- code = gs_rectstroke(igs, lr.pr, lr.count, &mat);
- npop++;
- } else {
- /* No matrix. */
- npop = rect_get(&lr, op, imemory);
- if (npop < 0)
- return npop;
- code = gs_rectstroke(igs, lr.pr, lr.count, (gs_matrix *) 0);
- }
- rect_release(&lr, imemory);
- if (code < 0)
- return code;
- pop(npop);
- return 0;
- }
- /* --- Internal routines --- */
- /* Get rectangles from the stack. */
- /* Return the number of elements to pop (>0) if OK, <0 if error. */
- private int
- rect_get(local_rects_t * plr, os_ptr op, gs_memory_t *mem)
- {
- int format, code;
- uint n, count;
- gs_rect *pr;
- double rv[4];
- switch (r_type(op)) {
- case t_array:
- case t_mixedarray:
- case t_shortarray:
- case t_string:
- code = num_array_format(op);
- if (code < 0)
- return code;
- format = code;
- count = num_array_size(op, format);
- if (count % 4)
- return_error(e_rangecheck);
- count /= 4;
- break;
- default: /* better be 4 numbers */
- code = num_params(op, 4, rv);
- if (code < 0)
- return code;
- plr->pr = plr->rl;
- plr->count = 1;
- plr->rl[0].q.x = (plr->rl[0].p.x = rv[0]) + rv[2];
- plr->rl[0].q.y = (plr->rl[0].p.y = rv[1]) + rv[3];
- return 4;
- }
- plr->count = count;
- if (count <= MAX_LOCAL_RECTS)
- pr = plr->rl;
- else {
- pr = (gs_rect *)gs_alloc_byte_array(mem, count, sizeof(gs_rect),
- "rect_get");
- if (pr == 0)
- return_error(e_VMerror);
- }
- plr->pr = pr;
- for (n = 0; n < count; n++, pr++) {
- ref rnum;
- int i;
- for (i = 0; i < 4; i++) {
- code = num_array_get((const ref *)op, format,
- (n << 2) + i, &rnum);
- switch (code) {
- case t_integer:
- rv[i] = rnum.value.intval;
- break;
- case t_real:
- rv[i] = rnum.value.realval;
- break;
- default: /* code < 0 */
- return code;
- }
- }
- pr->q.x = (pr->p.x = rv[0]) + rv[2];
- pr->q.y = (pr->p.y = rv[1]) + rv[3];
- }
- return 1;
- }
- /* Release the rectangle list if needed. */
- private void
- rect_release(local_rects_t * plr, gs_memory_t *mem)
- {
- if (plr->pr != plr->rl)
- gs_free_object(mem, plr->pr, "rect_release");
- }
- /* ------ Graphics state ------ */
- /* <llx> <lly> <urx> <ury> setbbox - */
- int
- zsetbbox(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- double box[4];
- int code = num_params(op, 4, box);
- if (code < 0)
- return code;
- if ((code = gs_setbbox(igs, box[0], box[1], box[2], box[3])) < 0)
- return code;
- pop(4);
- return 0;
- }
- /* ------ Initialization procedure ------ */
- const op_def zdps1_l2_op_defs[] =
- {
- op_def_begin_level2(),
- /* Graphics state */
- {"0currentstrokeadjust", zcurrentstrokeadjust},
- {"1setstrokeadjust", zsetstrokeadjust},
- /* Graphics state objects */
- {"1copy", z1copy},
- {"1currentgstate", zcurrentgstate},
- {"0gstate", zgstate},
- {"1setgstate", zsetgstate},
- /* Rectangles */
- {"1.rectappend", zrectappend},
- {"1rectclip", zrectclip},
- {"1rectfill", zrectfill},
- {"1rectstroke", zrectstroke},
- /* Graphics state components */
- {"4setbbox", zsetbbox},
- op_def_end(0)
- };
- /* ------ Internal routines ------ */
- /* Ensure that a gstate is not shared with an outer save level. */
- /* *op is of type t_astruct(igstate_obj). */
- private int
- gstate_unshare(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- ref *pgsref = &r_ptr(op, igstate_obj)->gstate;
- gs_state *pgs = r_ptr(pgsref, gs_state);
- gs_state *pnew;
- int_gstate *isp;
- if (!ref_must_save(pgsref))
- return 0;
- /* Copy the gstate. */
- pnew = gs_gstate(pgs);
- if (pnew == 0)
- return_error(e_VMerror);
- isp = gs_int_gstate(pnew);
- int_gstate_map_refs(isp, ref_mark_new);
- ref_do_save(op, pgsref, "gstate_unshare");
- make_istruct_new(pgsref, 0, pnew);
- return 0;
- }
|