Coverage Report

Created: 2022-10-31 07:00

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