Coverage Report

Created: 2026-08-08 08:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pcl/pcrect.c
Line
Count
Source
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
/* pcrect.c - PCL5 rectangular area fill commands */
18
#include "math_.h"
19
#include "pcommand.h"
20
#include "pcstate.h"
21
#include "pcdraw.h"
22
#include "pcpatrn.h"
23
#include "pcbiptrn.h"
24
#include "pcuptrn.h"
25
#include "gspath.h"
26
#include "gspath2.h"
27
#include "gsmatrix.h"
28
#include "gscoord.h"
29
#include "gspaint.h"
30
#include "gsrop.h"
31
32
/*
33
 * The graphic library is, unfortunately, not equipped to produce accurate
34
 * PCL rectangles on its own. These rectangles must always be rendered with
35
 * the same pixel dimensions, regardless of location (ignoring clipping),
36
 * in the "grid intersection" pixel placement mode, must always add one
37
 * additional pixel in the "right" and "down" directions, relative to print
38
 * direction 0.
39
 *
40
 * To accomplish these tasks, it is necessary to properly adjust the rectangle
41
 * dimensions provided to the graphic layer. That task is accomplished by
42
 * this routine.
43
 *
44
 * Note that this code is designed to work with no fill adjustment in the
45
 * graphic library.
46
 */
47
static int
48
adjust_render_rectangle(pcl_state_t * pcs)
49
3.41k
{
50
3.41k
    gs_gstate *pgs = pcs->pgs;
51
3.41k
    const pcl_xfm_state_t *pxfmst = &(pcs->xfm_state);
52
3.41k
    coord w = pcs->rectangle.x;
53
3.41k
    coord h = pcs->rectangle.y;
54
3.41k
    gs_point dims;
55
3.41k
    gs_rect rect;
56
3.41k
    gs_matrix save_mtx, ident_mtx;
57
3.41k
    int code = 0;
58
59
    /* adjust the width and height to reflect the logical page boundaries */
60
3.41k
    if (pcs->cap.x + w > pxfmst->pd_size.x)
61
183
        w = pxfmst->pd_size.x - pcs->cap.x;
62
3.41k
    if (pcs->cap.y + h > pxfmst->pd_size.y)
63
84
        h = pxfmst->pd_size.y - pcs->cap.y;
64
65
    /* move the current point to an integral pixel location */
66
3.41k
    gs_transform(pgs, (double) pcs->cap.x, (double) pcs->cap.y, &(rect.p));
67
3.41k
    rect.p.x = floor(rect.p.x + 0.5);
68
3.41k
    rect.p.y = floor(rect.p.y + 0.5);
69
70
    /* set the dimensions to be a multiple of pixels */
71
3.41k
    gs_dtransform(pgs, (double) w, (double) h, &dims);
72
3.41k
    if (dims.x >= 0)
73
3.24k
        rect.q.x = rect.p.x + ceil(dims.x);
74
162
    else {
75
162
        rect.q.x = rect.p.x;
76
162
        rect.p.x += floor(dims.x);
77
162
    }
78
3.41k
    if (dims.y >= 0)
79
3.12k
        rect.q.y = rect.p.y + ceil(dims.y);
80
282
    else {
81
282
        rect.q.y = rect.p.y;
82
282
        rect.p.y += floor(dims.y);
83
282
    }
84
85
    /*
86
     * If the pixel-placement mode is 1, decrease the size of the rectangle
87
     * by one pixel. Note that this occurs only if the rectangle dimension is
88
     * not 0; rectangles with a zero dimension are never rendered, irrespective
89
     * of pixle placement mode.
90
     *
91
     * This trickiest part of this increase in dimension concerns correction
92
     * for the device orientation relative to print direction 0. The output
93
     * produced needs to be the same for pages produced with either long-edge
94
     * -feed or short-edge-feed printers, so it is not possible to add one
95
     * pixel in each direction in device space.
96
     */
97
3.41k
    if ((pcs->pp_mode == 1) && (dims.x != 0.0) && (dims.y != 0.0)) {
98
0
        gs_matrix dflt_mtx;
99
0
        gs_point disp;
100
101
0
        gs_defaultmatrix(pgs, &dflt_mtx);
102
0
        gs_distance_transform(1.0, 1.0, &dflt_mtx, &disp);
103
0
        if (disp.x < 0.0)
104
0
            rect.p.x += 1.0;
105
0
        else
106
0
            rect.q.x -= 1.0;
107
0
        if (disp.y < 0.0)
108
0
            rect.p.y += 1.0;
109
0
        else
110
0
            rect.q.y -= 1.0;
111
0
    }
112
113
    /* rectangles with 0-dimensions are never printed */
114
3.41k
    if ((rect.p.x == rect.q.x) || (rect.p.y == rect.q.y))
115
465
        return 0;
116
117
    /* transform back into pseudo-print-direction space */
118
2.94k
    gs_currentmatrix(pgs, &save_mtx);
119
2.94k
    gs_make_identity(&ident_mtx);
120
2.94k
    gs_setmatrix(pgs, &ident_mtx);
121
2.94k
    code = gs_rectfill(pgs, &rect, 1);
122
2.94k
    pcs->page_marked = true;
123
2.94k
    gs_setmatrix(pgs, &save_mtx);
124
2.94k
    return code;
125
3.41k
}
126
127
/*
128
 * ESC * c <dp> H
129
 */
130
static int
131
pcl_horiz_rect_size_decipoints(pcl_args_t * pargs, pcl_state_t * pcs)
132
926
{
133
926
    pcs->rectangle.x = (coord) (any_abs(float_arg(pargs)) * 10);
134
926
    return 0;
135
926
}
136
137
/*
138
 * ESC * c <units> A
139
 */
140
static int
141
pcl_horiz_rect_size_units(pcl_args_t * pargs, pcl_state_t * pcs)
142
2.88k
{
143
2.88k
    pcs->rectangle.x = (coord) (any_abs(int_arg(pargs)) * pcs->uom_cp);
144
2.88k
    return 0;
145
2.88k
}
146
147
/*
148
 * ESC * c <dp> V
149
 */
150
static int
151
pcl_vert_rect_size_decipoints(pcl_args_t * pargs, pcl_state_t * pcs)
152
2.22k
{
153
2.22k
    pcs->rectangle.y = (coord) any_abs(float_arg(pargs)) * 10;
154
2.22k
    return 0;
155
2.22k
}
156
157
/*
158
 * ESC * c B
159
 */
160
static int
161
pcl_vert_rect_size_units(pcl_args_t * pargs, pcl_state_t * pcs)
162
3.11k
{
163
3.11k
    pcs->rectangle.y = any_abs(int_arg(pargs)) * pcs->uom_cp;
164
3.11k
    return 0;
165
3.11k
}
166
167
/*
168
 * ESC * c <fill_enum> P
169
 */
170
static int
171
pcl_fill_rect_area(pcl_args_t * pargs, pcl_state_t * pcs)
172
4.56k
{
173
4.56k
    pcl_pattern_source_t type = (pcl_pattern_source_t) int_arg(pargs);
174
4.56k
    int id = pcs->pattern_id;
175
4.56k
    int code = 0;
176
177
    /*
178
     * Rectangles have a special property with respect to patterns:
179
     *
180
     *     a non-zero, non-existent pattern specification causes the command
181
     *        to be ignored, UNLESS this is the current pattern. This only
182
     *        applies to cross-hatch and user-defined patterns, as the
183
     *        pattern id. is interpreted as an intensity level for shade
184
     *        patterns, and patterns >= 100% are considered white.
185
     */
186
4.56k
    if (type == pcl_pattern_cross_hatch) {
187
1.63k
        if (pcl_pattern_get_cross(pcs, id) == 0)
188
1.00k
            return 0;
189
2.92k
    } else if (type == pcl_pattern_user_defined) {
190
72
        if (pcl_pattern_get_pcl_uptrn(pcs, id) == 0)
191
72
            return 0;
192
2.85k
    } else if (type == pcl_pattern_current_pattern) {
193
12
        type = pcs->pattern_type;
194
12
        id = pcs->current_pattern_id;
195
2.84k
    } else if (type > pcl_pattern_shading)
196
74
        return 0;
197
198
    /* set up the graphic state; render the rectangle */
199
3.41k
    if (((code = pcl_set_drawing_color(pcs, type, id, false)) >= 0) &&
200
3.41k
        ((code = pcl_set_graphics_state(pcs)) >= 0))
201
3.41k
        code = adjust_render_rectangle(pcs);
202
3.41k
    return code;
203
4.56k
}
204
205
/*
206
 * Initialization
207
 */
208
static int
209
pcrect_do_registration(pcl_parser_state_t * pcl_parser_state,
210
                       gs_memory_t * mem)
211
16.1k
{
212
    /* Register commands */
213
16.1k
    DEFINE_CLASS('*') {
214
16.1k
        'c', 'H',
215
16.1k
            PCL_COMMAND("Horizontal Rectangle Size Decipoints",
216
16.1k
                        pcl_horiz_rect_size_decipoints,
217
16.1k
                        pca_neg_error | pca_big_error | pca_in_rtl)
218
16.1k
    }, {
219
16.1k
        'c', 'A',
220
16.1k
            PCL_COMMAND("Horizontal Rectangle Size Units",
221
16.1k
                        pcl_horiz_rect_size_units,
222
16.1k
                        pca_neg_error | pca_big_error | pca_in_rtl)
223
16.1k
    }, {
224
16.1k
        'c', 'V',
225
16.1k
            PCL_COMMAND("Vertical Rectangle Size Decipoint",
226
16.1k
                        pcl_vert_rect_size_decipoints,
227
16.1k
                        pca_neg_error | pca_big_error | pca_in_rtl)
228
16.1k
    }, {
229
16.1k
        'c', 'B',
230
16.1k
            PCL_COMMAND("Vertical Rectangle Size Units",
231
16.1k
                        pcl_vert_rect_size_units,
232
16.1k
                        pca_neg_error | pca_big_error | pca_in_rtl)
233
16.1k
    }, {
234
16.1k
        'c', 'P',
235
16.1k
            PCL_COMMAND("Fill Rectangular Area",
236
16.1k
                        pcl_fill_rect_area,
237
16.1k
                        pca_neg_ignore | pca_big_ignore | pca_in_rtl)
238
16.1k
    }, END_CLASS return 0;
239
16.1k
}
240
241
static int
242
pcrect_do_reset(pcl_state_t * pcs, pcl_reset_type_t type)
243
49.4k
{
244
49.4k
    static const uint mask = (pcl_reset_initial
245
49.4k
                              | pcl_reset_printer | pcl_reset_overlay);
246
49.4k
    if ((type & mask) != 0) {
247
49.4k
        pcs->rectangle.x = 0;
248
49.4k
        pcs->rectangle.y = 0;
249
49.4k
    }
250
251
49.4k
    return 0;
252
49.4k
}
253
254
const pcl_init_t pcrect_init = { pcrect_do_registration, pcrect_do_reset, 0 };