Coverage Report

Created: 2025-06-24 07:01

/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
162k
{
44
162k
    os_ptr op = osp;
45
162k
    gs_halftone ht;
46
47
162k
    gs_currenthalftone(igs, &ht);
48
162k
    switch (ht.type) {
49
107
        case ht_type_screen:
50
107
            push(4);
51
107
            make_real(op - 3, ht.params.screen.frequency);
52
107
            make_real(op - 2, ht.params.screen.angle);
53
107
            op[-1] = istate->screen_procs.gray;
54
107
            make_int(op, 1);
55
107
            break;
56
53
        case ht_type_colorscreen:
57
53
            push(13);
58
53
            {
59
53
                os_ptr opc = op - 12;
60
53
                gs_screen_halftone *pht =
61
53
                    &ht.params.colorscreen.screens.colored.red;
62
63
53
                make_real(opc, pht->frequency);
64
53
                make_real(opc + 1, pht->angle);
65
53
                opc[2] = istate->screen_procs.red;
66
67
53
                opc = op - 9;
68
53
                pht = &ht.params.colorscreen.screens.colored.green;
69
53
                make_real(opc, pht->frequency);
70
53
                make_real(opc + 1, pht->angle);
71
53
                opc[2] = istate->screen_procs.green;
72
73
53
                opc = op - 6;
74
53
                pht = &ht.params.colorscreen.screens.colored.blue;
75
53
                make_real(opc, pht->frequency);
76
53
                make_real(opc + 1, pht->angle);
77
53
                opc[2] = istate->screen_procs.blue;
78
79
53
                opc = op - 3;
80
53
                pht = &ht.params.colorscreen.screens.colored.gray;
81
53
                make_real(opc, pht->frequency);
82
53
                make_real(opc + 1, pht->angle);
83
53
                opc[2] = istate->screen_procs.gray;
84
53
            }
85
53
            make_int(op, 2);
86
53
            break;
87
162k
        default:    /* Screen was set by sethalftone. */
88
162k
            push(2);
89
162k
            op[-1] = istate->halftone;
90
162k
            make_int(op, 0);
91
162k
            break;
92
162k
    }
93
162k
    return 0;
94
162k
}
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.23M
#define snumpush 4
118
31.6M
#define sproc esp[-1]
119
59.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
310k
{
128
310k
    os_ptr op = osp;
129
310k
    gs_screen_halftone screen = { 0 };
130
310k
    gx_ht_order order;
131
310k
    int code = zscreen_params(op, &screen);
132
310k
    gs_memory_t *mem;
133
310k
    int space_index;
134
135
310k
    check_op(3);
136
310k
    space_index = r_space_index(op);
137
138
310k
    if (code < 0)
139
14
        return code;
140
310k
    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
310k
    code = gs_screen_order_init_memory(&order, igs, &screen,
146
310k
                                       gs_currentaccuratescreens(mem), mem);
147
310k
    if (code < 0)
148
3
        return code;
149
310k
    return zscreen_enum_init(i_ctx_p, &order, &screen, op, 3,
150
310k
                             setscreen_finish, space_index);
151
310k
}
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.61M
{
160
1.61M
    gs_screen_enum *penum;
161
1.61M
    gs_memory_t * mem = (gs_memory_t *)idmemory->spaces_indexed[space_index];
162
1.61M
    int code;
163
164
1.61M
    check_estack(snumpush + 1);
165
1.61M
    penum = gs_screen_enum_alloc(mem, "setscreen");
166
1.61M
    if (penum == 0)
167
0
        return_error(gs_error_VMerror);
168
1.61M
    make_struct(esp + snumpush, space_index << r_space_shift, penum);  /* do early for screen_cleanup in case of error */
169
1.61M
    code = gs_screen_enum_init_memory(penum, porder, igs, psp, mem);
170
1.61M
    if (code < 0) {
171
0
        screen_cleanup(i_ctx_p);
172
0
        return code;
173
0
    }
174
    /* Push everything on the estack */
175
1.61M
    make_mark_estack(esp + 1, es_other, screen_cleanup);
176
1.61M
    esp += snumpush;
177
1.61M
    make_op_estack(esp - 2, finish_proc);
178
1.61M
    sproc = *pproc;
179
1.61M
    push_op_estack(screen_sample);
180
1.61M
    pop(npop);
181
1.61M
    return o_push_estack;
182
1.61M
}
183
/* Set up the next sample */
184
static int
185
screen_sample(i_ctx_t *i_ctx_p)
186
30.3M
{
187
30.3M
    os_ptr op = osp;
188
30.3M
    gs_screen_enum *penum = senum;
189
30.3M
    gs_point pt;
190
30.3M
    int code = gs_screen_currentpoint(penum, &pt);
191
30.3M
    ref proc;
192
193
30.3M
    switch (code) {
194
0
        default:
195
0
            return code;
196
1.61M
        case 1:
197
            /* All done */
198
1.61M
            if (real_opproc(esp - 2) != 0)
199
310k
                code = (*real_opproc(esp - 2)) (i_ctx_p);
200
1.61M
            esp -= snumpush;
201
1.61M
            screen_cleanup(i_ctx_p);
202
1.61M
            return (code < 0 ? code : o_pop_estack);
203
28.7M
        case 0:
204
28.7M
            ;
205
30.3M
    }
206
30.3M
    push(2);
207
28.7M
    make_real(op - 1, pt.x);
208
28.7M
    make_real(op, pt.y);
209
28.7M
    proc = sproc;
210
28.7M
    push_op_estack(set_screen_continue);
211
28.7M
    *++esp = proc;
212
28.7M
    return o_push_estack;
213
28.7M
}
214
/* Continuation procedure for processing sampled pixels. */
215
static int
216
set_screen_continue(i_ctx_t *i_ctx_p)
217
28.7M
{
218
28.7M
    os_ptr op = osp;
219
28.7M
    double value;
220
28.7M
    int code = real_param(op, &value);
221
222
28.7M
    if (code < 0)
223
0
        return code;
224
28.7M
    code = gs_screen_next(senum, value);
225
28.7M
    if (code < 0)
226
2
        return code;
227
28.7M
    ref_stack_pop(&o_stack, 1);
228
28.7M
    return screen_sample(i_ctx_p);
229
28.7M
}
230
/* Finish setscreen. */
231
static int
232
setscreen_finish(i_ctx_t *i_ctx_p)
233
310k
{
234
310k
    gs_screen_install(senum);
235
310k
    istate->screen_procs.red = sproc;
236
310k
    istate->screen_procs.green = sproc;
237
310k
    istate->screen_procs.blue = sproc;
238
310k
    istate->screen_procs.gray = sproc;
239
310k
    make_null(&istate->halftone);
240
310k
    return 0;
241
310k
}
242
/* Clean up after screen enumeration */
243
static int
244
screen_cleanup(i_ctx_t *i_ctx_p)
245
1.61M
{
246
1.61M
    gs_screen_enum *penum = r_ptr(esp + snumpush, gs_screen_enum);
247
248
1.61M
    gs_free_object(penum->halftone.rc.memory, penum, "screen_cleanup");
249
1.61M
    return 0;
250
1.61M
}
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.61M
{
258
1.61M
    double fa[2];
259
1.61M
    int code = num_params(op - 1, 2, fa);
260
261
1.61M
    if (code < 0)
262
5
        return code;
263
1.61M
    check_proc(*op);
264
1.61M
    phs->frequency = fa[0];
265
1.61M
    phs->angle = fa[1];
266
1.61M
    return 0;
267
1.61M
}
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
};