Coverage Report

Created: 2025-08-28 07:06

/src/ghostpdl/psi/zht.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 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.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, 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
189k
{
44
189k
    os_ptr op = osp;
45
189k
    gs_halftone ht;
46
47
189k
    gs_currenthalftone(igs, &ht);
48
189k
    switch (ht.type) {
49
103
        case ht_type_screen:
50
103
            push(4);
51
103
            make_real(op - 3, ht.params.screen.frequency);
52
103
            make_real(op - 2, ht.params.screen.angle);
53
103
            op[-1] = istate->screen_procs.gray;
54
103
            make_int(op, 1);
55
103
            break;
56
52
        case ht_type_colorscreen:
57
52
            push(13);
58
52
            {
59
52
                os_ptr opc = op - 12;
60
52
                gs_screen_halftone *pht =
61
52
                    &ht.params.colorscreen.screens.colored.red;
62
63
52
                make_real(opc, pht->frequency);
64
52
                make_real(opc + 1, pht->angle);
65
52
                opc[2] = istate->screen_procs.red;
66
67
52
                opc = op - 9;
68
52
                pht = &ht.params.colorscreen.screens.colored.green;
69
52
                make_real(opc, pht->frequency);
70
52
                make_real(opc + 1, pht->angle);
71
52
                opc[2] = istate->screen_procs.green;
72
73
52
                opc = op - 6;
74
52
                pht = &ht.params.colorscreen.screens.colored.blue;
75
52
                make_real(opc, pht->frequency);
76
52
                make_real(opc + 1, pht->angle);
77
52
                opc[2] = istate->screen_procs.blue;
78
79
52
                opc = op - 3;
80
52
                pht = &ht.params.colorscreen.screens.colored.gray;
81
52
                make_real(opc, pht->frequency);
82
52
                make_real(opc + 1, pht->angle);
83
52
                opc[2] = istate->screen_procs.gray;
84
52
            }
85
52
            make_int(op, 2);
86
52
            break;
87
189k
        default:    /* Screen was set by sethalftone. */
88
189k
            push(2);
89
189k
            op[-1] = istate->halftone;
90
189k
            make_int(op, 0);
91
189k
            break;
92
189k
    }
93
189k
    return 0;
94
189k
}
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
3.33M
#define snumpush 4
118
32.6M
#define sproc esp[-1]
119
61.4M
#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
302k
{
128
302k
    os_ptr op = osp;
129
302k
    gs_screen_halftone screen = { 0 };
130
302k
    gx_ht_order order;
131
302k
    int code = zscreen_params(op, &screen);
132
302k
    gs_memory_t *mem;
133
302k
    int space_index;
134
135
302k
    check_op(3);
136
302k
    space_index = r_space_index(op);
137
138
302k
    if (code < 0)
139
16
        return code;
140
302k
    mem = (gs_memory_t *)idmemory->spaces_indexed[space_index];
141
    /*
142
     * Allocate the halftone in the same VM space as the procedure.
143
     * This keeps the space relationships consistent.
144
     */
145
302k
    code = gs_screen_order_init_memory(&order, igs, &screen,
146
302k
                                       gs_currentaccuratescreens(mem), mem);
147
302k
    if (code < 0)
148
3
        return code;
149
302k
    return zscreen_enum_init(i_ctx_p, &order, &screen, op, 3,
150
302k
                             setscreen_finish, space_index);
151
302k
}
152
153
/* We break out the body of this operator so it can be shared with */
154
/* the code for Type 1 halftones in sethalftone. */
155
int
156
zscreen_enum_init(i_ctx_t *i_ctx_p, const gx_ht_order * porder,
157
                  gs_screen_halftone * psp, ref * pproc, int npop,
158
                  int (*finish_proc)(i_ctx_t *), int space_index)
159
1.66M
{
160
1.66M
    gs_screen_enum *penum;
161
1.66M
    gs_memory_t * mem = (gs_memory_t *)idmemory->spaces_indexed[space_index];
162
1.66M
    int code;
163
164
1.66M
    check_estack(snumpush + 1);
165
1.66M
    penum = gs_screen_enum_alloc(mem, "setscreen");
166
1.66M
    if (penum == 0)
167
0
        return_error(gs_error_VMerror);
168
1.66M
    make_struct(esp + snumpush, space_index << r_space_shift, penum);  /* do early for screen_cleanup in case of error */
169
1.66M
    code = gs_screen_enum_init_memory(penum, porder, igs, psp, mem);
170
1.66M
    if (code < 0) {
171
0
        screen_cleanup(i_ctx_p);
172
0
        return code;
173
0
    }
174
    /* Push everything on the estack */
175
1.66M
    make_mark_estack(esp + 1, es_other, screen_cleanup);
176
1.66M
    esp += snumpush;
177
1.66M
    make_op_estack(esp - 2, finish_proc);
178
1.66M
    sproc = *pproc;
179
1.66M
    push_op_estack(screen_sample);
180
1.66M
    pop(npop);
181
1.66M
    return o_push_estack;
182
1.66M
}
183
/* Set up the next sample */
184
static int
185
screen_sample(i_ctx_t *i_ctx_p)
186
31.4M
{
187
31.4M
    os_ptr op = osp;
188
31.4M
    gs_screen_enum *penum = senum;
189
31.4M
    gs_point pt;
190
31.4M
    int code = gs_screen_currentpoint(penum, &pt);
191
31.4M
    ref proc;
192
193
31.4M
    switch (code) {
194
0
        default:
195
0
            return code;
196
1.66M
        case 1:
197
            /* All done */
198
1.66M
            if (real_opproc(esp - 2) != 0)
199
302k
                code = (*real_opproc(esp - 2)) (i_ctx_p);
200
1.66M
            esp -= snumpush;
201
1.66M
            screen_cleanup(i_ctx_p);
202
1.66M
            return (code < 0 ? code : o_pop_estack);
203
29.7M
        case 0:
204
29.7M
            ;
205
31.4M
    }
206
31.4M
    push(2);
207
29.7M
    make_real(op - 1, pt.x);
208
29.7M
    make_real(op, pt.y);
209
29.7M
    proc = sproc;
210
29.7M
    push_op_estack(set_screen_continue);
211
29.7M
    *++esp = proc;
212
29.7M
    return o_push_estack;
213
29.7M
}
214
/* Continuation procedure for processing sampled pixels. */
215
static int
216
set_screen_continue(i_ctx_t *i_ctx_p)
217
29.7M
{
218
29.7M
    os_ptr op = osp;
219
29.7M
    double value;
220
29.7M
    int code = real_param(op, &value);
221
222
29.7M
    if (code < 0)
223
1
        return code;
224
29.7M
    code = gs_screen_next(senum, value);
225
29.7M
    if (code < 0)
226
1
        return code;
227
29.7M
    ref_stack_pop(&o_stack, 1);
228
29.7M
    return screen_sample(i_ctx_p);
229
29.7M
}
230
/* Finish setscreen. */
231
static int
232
setscreen_finish(i_ctx_t *i_ctx_p)
233
302k
{
234
302k
    gs_screen_install(senum);
235
302k
    istate->screen_procs.red = sproc;
236
302k
    istate->screen_procs.green = sproc;
237
302k
    istate->screen_procs.blue = sproc;
238
302k
    istate->screen_procs.gray = sproc;
239
302k
    make_null(&istate->halftone);
240
302k
    return 0;
241
302k
}
242
/* Clean up after screen enumeration */
243
static int
244
screen_cleanup(i_ctx_t *i_ctx_p)
245
1.66M
{
246
1.66M
    gs_screen_enum *penum = r_ptr(esp + snumpush, gs_screen_enum);
247
248
1.66M
    gs_free_object(penum->halftone.rc.memory, penum, "screen_cleanup");
249
1.66M
    return 0;
250
1.66M
}
251
252
/* ------ Utility procedures ------ */
253
254
/* Get parameters for a single screen. */
255
int
256
zscreen_params(os_ptr op, gs_screen_halftone * phs)
257
1.66M
{
258
1.66M
    double fa[2];
259
1.66M
    int code = num_params(op - 1, 2, fa);
260
261
1.66M
    if (code < 0)
262
15
        return code;
263
1.66M
    check_proc(*op);
264
1.66M
    phs->frequency = fa[0];
265
1.66M
    phs->angle = fa[1];
266
1.66M
    return 0;
267
1.66M
}
268
269
/* ------ Initialization procedure ------ */
270
271
const op_def zht_op_defs[] =
272
{
273
    {"0.currenthalftone", zcurrenthalftone},
274
    {"0.currentscreenlevels", zcurrentscreenlevels},
275
    {"3setscreen", zsetscreen},
276
                /* Internal operators */
277
    {"0%screen_sample", screen_sample},
278
    {"1%set_screen_continue", set_screen_continue},
279
    {"0%setscreen_finish", setscreen_finish},
280
    op_def_end(0)
281
};