1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: zht.c 9043 2008-08-28 22:48:19Z giles $ */
15 /* Halftone definition operators */
16 #include "ghost.h"
17 #include "memory_.h"
18 #include "oper.h"
19 #include "estack.h"
20 #include "gsstruct.h"		/* must precede igstate.h, */
21 					/* because of #ifdef in gsht.h */
22 #include "ialloc.h"
23 #include "igstate.h"
24 #include "gsmatrix.h"
25 #include "gxdevice.h"		/* for gzht.h */
26 #include "gzht.h"
27 #include "gsstate.h"
28 #include "iht.h"		/* prototypes */
29 #include "store.h"
30 
31 /* Forward references */
32 static int screen_sample(i_ctx_t *);
33 static int set_screen_continue(i_ctx_t *);
34 static int screen_cleanup(i_ctx_t *);
35 
36 /* - .currenthalftone <dict> 0 */
37 /* - .currenthalftone <frequency> <angle> <proc> 1 */
38 /* - .currenthalftone <red_freq> ... <gray_proc> 2 */
39 static int
zcurrenthalftone(i_ctx_t * i_ctx_p)40 zcurrenthalftone(i_ctx_t *i_ctx_p)
41 {
42     os_ptr op = osp;
43     gs_halftone ht;
44 
45     gs_currenthalftone(igs, &ht);
46     switch (ht.type) {
47 	case ht_type_screen:
48 	    push(4);
49 	    make_real(op - 3, ht.params.screen.frequency);
50 	    make_real(op - 2, ht.params.screen.angle);
51 	    op[-1] = istate->screen_procs.gray;
52 	    make_int(op, 1);
53 	    break;
54 	case ht_type_colorscreen:
55 	    push(13);
56 	    {
57 		os_ptr opc = op - 12;
58 		gs_screen_halftone *pht =
59 		    &ht.params.colorscreen.screens.colored.red;
60 
61 		make_real(opc, pht->frequency);
62 		make_real(opc + 1, pht->angle);
63 		opc[2] = istate->screen_procs.red;
64 
65 		opc = op - 9;
66 		pht = &ht.params.colorscreen.screens.colored.green;
67 		make_real(opc, pht->frequency);
68 		make_real(opc + 1, pht->angle);
69 		opc[2] = istate->screen_procs.green;
70 
71 		opc = op - 6;
72 		pht = &ht.params.colorscreen.screens.colored.blue;
73 		make_real(opc, pht->frequency);
74 		make_real(opc + 1, pht->angle);
75 		opc[2] = istate->screen_procs.blue;
76 
77 		opc = op - 3;
78 		pht = &ht.params.colorscreen.screens.colored.gray;
79 		make_real(opc, pht->frequency);
80 		make_real(opc + 1, pht->angle);
81 		opc[2] = istate->screen_procs.gray;
82 	    }
83 	    make_int(op, 2);
84 	    break;
85 	default:		/* Screen was set by sethalftone. */
86 	    push(2);
87 	    op[-1] = istate->halftone;
88 	    make_int(op, 0);
89 	    break;
90     }
91     return 0;
92 }
93 
94 /* - .currentscreenlevels <int> */
95 static int
zcurrentscreenlevels(i_ctx_t * i_ctx_p)96 zcurrentscreenlevels(i_ctx_t *i_ctx_p)
97 {
98     os_ptr op = osp;
99 
100     push(1);
101     make_int(op, gs_currentscreenlevels(igs));
102     return 0;
103 }
104 
105 /* The setscreen operator is complex because it has to sample */
106 /* each pixel in the pattern cell, calling a procedure, and then */
107 /* sort the result into a whitening order. */
108 
109 /* Layout of stuff pushed on estack: */
110 /*      Control mark, */
111 /*      [other stuff for other screen-setting operators], */
112 /*      finishing procedure (or 0), */
113 /*      spot procedure, */
114 /*      enumeration structure (as bytes). */
115 #define snumpush 4
116 #define sproc esp[-1]
117 #define senum r_ptr(esp, gs_screen_enum)
118 
119 /* Forward references */
120 static int setscreen_finish(i_ctx_t *);
121 
122 /* <frequency> <angle> <proc> setscreen - */
123 static int
zsetscreen(i_ctx_t * i_ctx_p)124 zsetscreen(i_ctx_t *i_ctx_p)
125 {
126     os_ptr op = osp;
127     gs_screen_halftone screen;
128     gx_ht_order order;
129     int code = zscreen_params(op, &screen);
130     gs_memory_t *mem;
131     int space_index = r_space_index(op);
132 
133     if (code < 0)
134 	return code;
135     mem = (gs_memory_t *)idmemory->spaces_indexed[space_index];
136     /*
137      * Allocate the halftone in the same VM space as the procedure.
138      * This keeps the space relationships consistent.
139      */
140     code = gs_screen_order_init_memory(&order, igs, &screen,
141 				       gs_currentaccuratescreens(), mem);
142     if (code < 0)
143 	return code;
144     return zscreen_enum_init(i_ctx_p, &order, &screen, op, 3,
145 			     setscreen_finish, space_index);
146 }
147 /* We break out the body of this operator so it can be shared with */
148 /* the code for Type 1 halftones in sethalftone. */
149 int
zscreen_enum_init(i_ctx_t * i_ctx_p,const gx_ht_order * porder,gs_screen_halftone * psp,ref * pproc,int npop,int (* finish_proc)(i_ctx_t *),int space_index)150 zscreen_enum_init(i_ctx_t *i_ctx_p, const gx_ht_order * porder,
151 		  gs_screen_halftone * psp, ref * pproc, int npop,
152 		  int (*finish_proc)(i_ctx_t *), int space_index)
153 {
154     gs_screen_enum *penum;
155     gs_memory_t * mem = (gs_memory_t *)idmemory->spaces_indexed[space_index];
156     int code;
157 
158     check_estack(snumpush + 1);
159     penum = gs_screen_enum_alloc(mem, "setscreen");
160     if (penum == 0)
161 	return_error(e_VMerror);
162     make_struct(esp + snumpush, space_index << r_space_shift, penum);	/* do early for screen_cleanup in case of error */
163     code = gs_screen_enum_init_memory(penum, porder, igs, psp, mem);
164     if (code < 0) {
165 	screen_cleanup(i_ctx_p);
166 	return code;
167     }
168     /* Push everything on the estack */
169     make_mark_estack(esp + 1, es_other, screen_cleanup);
170     esp += snumpush;
171     make_op_estack(esp - 2, finish_proc);
172     sproc = *pproc;
173     push_op_estack(screen_sample);
174     pop(npop);
175     return o_push_estack;
176 }
177 /* Set up the next sample */
178 static int
screen_sample(i_ctx_t * i_ctx_p)179 screen_sample(i_ctx_t *i_ctx_p)
180 {
181     os_ptr op = osp;
182     gs_screen_enum *penum = senum;
183     gs_point pt;
184     int code = gs_screen_currentpoint(penum, &pt);
185     ref proc;
186 
187     switch (code) {
188 	default:
189 	    return code;
190 	case 1:
191 	    /* All done */
192 	    if (real_opproc(esp - 2) != 0)
193 		code = (*real_opproc(esp - 2)) (i_ctx_p);
194 	    esp -= snumpush;
195 	    screen_cleanup(i_ctx_p);
196 	    return (code < 0 ? code : o_pop_estack);
197 	case 0:
198 	    ;
199     }
200     push(2);
201     make_real(op - 1, pt.x);
202     make_real(op, pt.y);
203     proc = sproc;
204     push_op_estack(set_screen_continue);
205     *++esp = proc;
206     return o_push_estack;
207 }
208 /* Continuation procedure for processing sampled pixels. */
209 static int
set_screen_continue(i_ctx_t * i_ctx_p)210 set_screen_continue(i_ctx_t *i_ctx_p)
211 {
212     os_ptr op = osp;
213     double value;
214     int code = real_param(op, &value);
215 
216     if (code < 0)
217 	return code;
218     code = gs_screen_next(senum, value);
219     if (code < 0)
220 	return code;
221     pop(1);
222     return screen_sample(i_ctx_p);
223 }
224 /* Finish setscreen. */
225 static int
setscreen_finish(i_ctx_t * i_ctx_p)226 setscreen_finish(i_ctx_t *i_ctx_p)
227 {
228     gs_screen_install(senum);
229     istate->screen_procs.red = sproc;
230     istate->screen_procs.green = sproc;
231     istate->screen_procs.blue = sproc;
232     istate->screen_procs.gray = sproc;
233     make_null(&istate->halftone);
234     return 0;
235 }
236 /* Clean up after screen enumeration */
237 static int
screen_cleanup(i_ctx_t * i_ctx_p)238 screen_cleanup(i_ctx_t *i_ctx_p)
239 {
240     gs_screen_enum *penum = r_ptr(esp + snumpush, gs_screen_enum);
241 
242     gs_free_object(penum->halftone.rc.memory, penum, "screen_cleanup");
243     return 0;
244 }
245 
246 /* ------ Utility procedures ------ */
247 
248 /* Get parameters for a single screen. */
249 int
zscreen_params(os_ptr op,gs_screen_halftone * phs)250 zscreen_params(os_ptr op, gs_screen_halftone * phs)
251 {
252     double fa[2];
253     int code = num_params(op - 1, 2, fa);
254 
255     if (code < 0)
256 	return code;
257     check_proc(*op);
258     phs->frequency = fa[0];
259     phs->angle = fa[1];
260     return 0;
261 }
262 
263 /* ------ Initialization procedure ------ */
264 
265 const op_def zht_op_defs[] =
266 {
267     {"0.currenthalftone", zcurrenthalftone},
268     {"0.currentscreenlevels", zcurrentscreenlevels},
269     {"3setscreen", zsetscreen},
270 		/* Internal operators */
271     {"0%screen_sample", screen_sample},
272     {"1%set_screen_continue", set_screen_continue},
273     {"0%setscreen_finish", setscreen_finish},
274     op_def_end(0)
275 };
276