Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/psi/zform.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2024 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
/* Simple high level forms */
18
#include "ghost.h"
19
#include "oper.h"
20
#include "gxdevice.h"
21
#include "ialloc.h"
22
#include "idict.h"
23
#include "idparam.h"
24
#include "igstate.h"
25
#include "gxdevsop.h"
26
#include "gscoord.h"
27
#include "gsform1.h"
28
#include "gspath.h"
29
#include "gxpath.h"
30
#include "gzstate.h"
31
#include "store.h"
32
33
/* support for high level formss */
34
35
/* [CTM before Form Matrix applied] <<Form dictionary>> .beginform -
36
 */
37
static int zbeginform(i_ctx_t *i_ctx_p)
38
0
{
39
0
    os_ptr op = osp;
40
0
    gx_device *cdev = gs_currentdevice_inline(igs);
41
0
    int code;
42
0
    float BBox[4], Matrix[6];
43
0
    gs_form_template_t tmplate;
44
0
    gs_point ll, ur;
45
0
    gs_fixed_rect box;
46
47
0
    check_op(2);
48
0
    check_type(*op, t_dictionary);
49
0
    check_dict_read(*op);
50
51
0
    code = read_matrix(imemory, op - 1, &tmplate.CTM);
52
0
    if (code < 0)
53
0
        return code;
54
55
0
    code = dict_floats_param(imemory, op, "BBox", 4, BBox, NULL);
56
0
    if (code < 0)
57
0
        return code;
58
0
    if (code == 0)
59
0
       return_error(gs_error_undefined);
60
0
    tmplate.FormID = -1;
61
0
    tmplate.BBox.p.x = BBox[0];
62
0
    tmplate.BBox.p.y = BBox[1];
63
0
    tmplate.BBox.q.x = BBox[2];
64
0
    tmplate.BBox.q.y = BBox[3];
65
66
0
    code = dict_floats_param(imemory, op, "Matrix", 6, Matrix, NULL);
67
0
    if (code < 0)
68
0
        return code;
69
0
    if (code == 0)
70
0
       return_error(gs_error_undefined);
71
72
0
    tmplate.form_matrix.xx = Matrix[0];
73
0
    tmplate.form_matrix.xy = Matrix[1];
74
0
    tmplate.form_matrix.yx = Matrix[2];
75
0
    tmplate.form_matrix.yy = Matrix[3];
76
0
    tmplate.form_matrix.tx = Matrix[4];
77
0
    tmplate.form_matrix.ty = Matrix[5];
78
79
0
    tmplate.pcpath = igs->clip_path;
80
81
0
    tmplate.pgs = igs;
82
0
    code = dev_proc(cdev, dev_spec_op)(cdev, gxdso_form_begin,
83
0
                            &tmplate, 0);
84
85
    /* return value > 0 means the device sent us back a matrix
86
     * and wants the CTM set to that.
87
     */
88
0
    if (code > 0)
89
0
    {
90
0
        gs_setmatrix(igs, &tmplate.CTM);
91
0
        gs_distance_transform(tmplate.BBox.p.x, tmplate.BBox.p.y, &tmplate.CTM, &ll);
92
0
        gs_distance_transform(tmplate.BBox.q.x, tmplate.BBox.q.y, &tmplate.CTM, &ur);
93
94
        /* A form can legitimately have negative co-ordinates in paths
95
         * because it can be translated. But we always clip paths to the
96
         * page which (clearly) can't have negative co-ordinates. NB this
97
         * wouldn't be a problem if we didn't reset the CTM, but that would
98
         * break the form capture.
99
         * So here we temporarily set the clip to permit negative values,
100
         * fortunately this works.....
101
         */
102
        /* We choose to permit negative values of the same magnitude as the
103
         * positive ones.
104
         */
105
106
0
        box.p.x = float2fixed(ll.x);
107
0
        box.p.y = float2fixed(ll.y);
108
0
        box.q.x = float2fixed(ur.x);
109
0
        box.q.y = float2fixed(ur.y);
110
111
0
        if (box.p.x < 0) {
112
0
            if(box.q.x > 0 && box.p.x * -1 > box.q.x)
113
0
                box.q.x = box.p.x * -1;
114
0
        } else {
115
0
            if (fabs(ur.x) > fabs(ll.x))
116
0
                box.p.x = box.q.x * -1;
117
0
            else {
118
0
                box.p.x = float2fixed(ll.x * -1);
119
0
                box.q.x = float2fixed(ll.x);
120
0
            }
121
0
        }
122
0
        if (box.p.y < 0) {
123
0
            if(box.q.y > 0 && box.p.y * -1 > box.q.y)
124
0
                box.q.y = box.p.y * -1;
125
0
        } else {
126
0
            if (fabs(ur.y) > fabs(ll.y))
127
0
                box.p.y = box.q.y * -1;
128
0
            else {
129
0
                box.p.y = float2fixed(ll.y * -1);
130
0
                box.q.y = float2fixed(ll.y);
131
0
            }
132
0
        }
133
        /* This gets undone when we grestore after the form is executed */
134
0
        code = gx_clip_to_rectangle(igs, &box);
135
0
    }
136
137
0
    pop(2);
138
0
    return code;
139
0
}
140
141
/* - .endform -
142
 */
143
static int zendform(i_ctx_t *i_ctx_p)
144
0
{
145
0
    gx_device *cdev = gs_currentdevice_inline(igs);
146
0
    int code;
147
148
0
    code = dev_proc(cdev, dev_spec_op)(cdev, gxdso_form_end,
149
0
                            0, 0);
150
0
    return code;
151
0
}
152
153
/*
154
 * - .get_form_id <int>
155
 */
156
static int zget_form_id(i_ctx_t *i_ctx_p)
157
0
{
158
0
    os_ptr op = osp;
159
0
    gx_device *cdev = gs_currentdevice_inline(igs);
160
0
    int code, ID;
161
162
0
    code = dev_proc(cdev, dev_spec_op)(cdev, gxdso_get_form_ID,
163
0
                            &ID, sizeof(int));
164
165
0
    if (code < 0){
166
0
        ID = -1;
167
0
        code = 0;
168
0
    }
169
170
0
    push(1);
171
0
    make_int(op, ID);
172
0
    return code;
173
0
}
174
175
/*
176
 * [matrix] <dict> <int> .repeatform -
177
 */
178
static int zrepeatform(i_ctx_t *i_ctx_p)
179
0
{
180
0
    os_ptr op = osp;
181
0
    gx_device *cdev = gs_currentdevice_inline(igs);
182
0
    int code;
183
0
    gs_form_template_t tmplate;
184
0
    float BBox[4], Matrix[6];
185
186
0
    check_op(3);
187
0
    check_type(*op, t_integer);
188
189
0
    code = read_matrix(imemory, op - 2, &tmplate.CTM);
190
0
    if (code < 0)
191
0
        return code;
192
193
0
    check_type(op[- 1], t_dictionary);
194
0
    check_dict_read(*(op - 1));
195
196
0
    code = dict_floats_param(imemory, op - 1, "BBox", 4, BBox, NULL);
197
0
    if (code < 0)
198
0
        return code;
199
0
    if (code == 0)
200
0
       return_error(gs_error_undefined);
201
202
0
    tmplate.BBox.p.x = BBox[0];
203
0
    tmplate.BBox.p.y = BBox[1];
204
205
0
    code = dict_floats_param(imemory, op - 1, "Matrix", 6, Matrix, NULL);
206
0
    if (code < 0)
207
0
        return code;
208
0
    if (code == 0)
209
0
       return_error(gs_error_undefined);
210
211
0
    tmplate.form_matrix.xx = Matrix[0];
212
0
    tmplate.form_matrix.xy = Matrix[1];
213
0
    tmplate.form_matrix.yx = Matrix[2];
214
0
    tmplate.form_matrix.yy = Matrix[3];
215
0
    tmplate.form_matrix.tx = Matrix[4];
216
0
    tmplate.form_matrix.ty = Matrix[5];
217
218
0
    tmplate.pcpath = igs->clip_path;
219
220
0
    tmplate.FormID = op->value.intval;
221
222
0
    code = dev_proc(cdev, dev_spec_op)(cdev, gxdso_repeat_form,
223
0
                            &tmplate, sizeof(gs_form_template_t));
224
225
0
    pop(3);
226
0
    return code;
227
0
}
228
229
const op_def zform_op_defs[] =
230
{
231
    {"0.beginform", zbeginform},
232
    {"0.endform", zendform},
233
    {"0.get_form_id", zget_form_id},
234
    {"3.repeatform", zrepeatform},
235
op_def_end(0)
236
};