Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/simscale.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
/* Image mask interpolation filter */
18
19
#include "memory_.h"
20
#include "gserrors.h"
21
#include "strimpl.h"
22
#include "sisparam.h"
23
#include "simscale.h"
24
#include "simscale_foo.h"
25
26
gs_private_st_ptrs2(st_imscale_state, stream_imscale_state,
27
                    "ImscaleDecode state",
28
                    imscale_state_enum_ptrs, imscale_state_reloc_ptrs,
29
                    window, dst);
30
31
static void
32
s_imscale_release(stream_state *st)
33
0
{
34
0
    stream_imscale_state *const ss = (stream_imscale_state *) st;
35
0
    gs_memory_t *mem = ss->memory;
36
37
0
    gs_free_object(mem, (void *)ss->window, "imscale window");
38
0
    ss->window = 0;
39
0
    gs_free_object(mem, (void *)ss->dst, "imscale dst");
40
0
    ss->dst = 0;
41
0
}
42
43
static int
44
s_imscale_init(stream_state *st)
45
0
{
46
0
    stream_imscale_state *const ss = (stream_imscale_state *) st;
47
0
    gs_memory_t *mem = ss->memory;
48
0
    int bytesin = (ss->params.WidthIn + 7) >> 3;
49
0
    int bytesout = (ss->params.WidthIn + 1) >> 1;
50
51
0
    ss->src_y = 0;
52
0
    ss->src_offset = 0;
53
0
    ss->src_size = bytesin;
54
0
    ss->src_line_padded = bytesin + 10;
55
56
0
    ss->dst_line_padded = bytesout + 10; /* to compensate for overshoots in zoom() */
57
0
    ss->dst_line_size = bytesout;
58
0
    ss->dst_size = bytesout*4;
59
0
    ss->dst_offset = ss->dst_size;
60
0
    ss->dst_togo = (long long)ss->dst_size * ss->params.HeightIn;
61
0
    ss->window = (byte *)gs_alloc_byte_array(mem, ss->src_line_padded, 5, "imscale window");
62
0
    ss->dst = (byte *)gs_alloc_bytes(mem, ss->dst_line_padded * 4, "imscale dst");
63
0
    if (ss->window == NULL || ss->dst == NULL)
64
0
        return_error(gs_error_VMerror);
65
0
    memset(ss->window, 0xff, ss->src_line_padded * 5);
66
0
    return 0;
67
0
}
68
69
static void
70
0
zoom_line(stream_imscale_state *ss) {
71
    /* src_y is 2 scan lines ahead of dst_y/4, although the latter counter is implicit.
72
     * For instance, during the 1st call to this function, src_y == 2, dst_y == 0.
73
     * (src_y + 3) % 5 == 0 and points to the beginning of the window.
74
     * (src_y + 4) % 5 == 1 and points to the next line.
75
     * (src_y    ) % 5 == 2 and points to the last scanned line.
76
     * The next 2 lines in the window correspond to the blank lines above the first
77
     * line of the image.
78
     */
79
0
  unsigned char * const p0 = ss->window + (ss->src_line_padded * ((ss->src_y + 1) % 5));
80
0
  unsigned char * const p1 = ss->window + (ss->src_line_padded * ((ss->src_y + 2) % 5));
81
0
  unsigned char * const p2 = ss->window + (ss->src_line_padded * ((ss->src_y + 3) % 5));
82
0
  unsigned char * const p3 = ss->window + (ss->src_line_padded * ((ss->src_y + 4) % 5));
83
0
  unsigned char * const p4 = ss->window + (ss->src_line_padded * ((ss->src_y    ) % 5));
84
85
  /* Pointers to the lines in the destination buffer. */
86
0
  unsigned char * const dst0 = ss->dst;
87
0
  unsigned char * const dst1 = ss->dst + ss->dst_line_padded;
88
0
  unsigned char * const dst2 = ss->dst + 2*ss->dst_line_padded;
89
0
  unsigned char * const dst3 = ss->dst + 3*ss->dst_line_padded;
90
0
    unsigned int i;
91
92
    /* r0..r4 are shift registers that contain 5x5 bit matrix and serve
93
     * as buffers for byte-based access to memory. The registers have
94
     * the following structure and initial content.
95
     * r0: ........ ........ ......11 XXXxxxxx
96
     * r1: ........ ........ .11XXXxx xxx00000
97
     * r2: ........ ....11XX Xxxxxxyy yyyyyy00
98
     * r3: .......1 1XXXxxxx xyyyyyyy y0000000
99
     * r3: ..11XXXx xxxxyyyy yyyyzzzz zzzz0000
100
     * where
101
     * '.' denotes an unused bit
102
     * '1' denotes the initial blank bits that precede leading bits of every line
103
     * 'X' denotes leading bits of the 1st byte. '1' and 'X' belong to 5x5 bit matrix
104
     * 'x' denotes remaining bits of the 1st byte
105
     * 'y','z' denote the positions of the following bytes
106
     * '0' denotes the initial empty bits
107
     */
108
0
    uint32_t r0  = 0x300 | p0[0];
109
0
    uint32_t r1  = 0x6000 | p1[0] << 5;
110
0
    uint32_t r2  = 0xc0000 | p2[0] << 10 | p2[1] << 2;
111
0
    uint32_t r3  = 0x1800000 | p3[0] << 15 | p3[1] << 7;
112
0
    uint32_t r4  = 0x30000000 | p4[0] << 20 | p4[1] << 12 | p4[2] << 4;
113
114
0
#define ZOOM(r0, r1, r2, r3, r4) imscale_foo((r0 & 0x3e0) | (r1 & 0x7c00) | (r2 & 0xf8000) | (r3 & 0x1f00000) | (r4 & 0x3e000000))
115
0
#define SHIFT(r0, r1, r2, r3, r4) r0 <<= 1, r1 <<= 1, r2 <<= 1, r3 <<= 1, r4 <<= 1
116
0
#define LOAD(n,i) r##n |= p##n[i]
117
0
#define STORE(i)  dst0[i] = out, dst1[i] = out >> 8, dst2[i] = out >> 16, dst3[i] = out >> 24
118
119
    /* Possible improvement: buffer output in a 64-bit accumulator and write 16-bit chunks. */
120
    /* Unfortunately in this case big- and little-endian systems need different code. */
121
0
    for (i=0; i < ss->src_size; i++) {
122
0
        uint32_t out;                         /* 0 5 2 7 4 : number of empty bits in r0..r4 */
123
124
0
        out = ZOOM(r0, r1, r2, r3, r4) << 4;
125
0
        SHIFT(r0, r1, r2, r3, r4);            /* 1 6 3 8 5 : every counter increases by 1 */
126
0
        LOAD(3, i+2);                         /* 1 6 3 0 5 : load r3 because it has 8 empty bits */
127
0
        out |= ZOOM(r0, r1, r2, r3, r4);
128
0
        SHIFT(r0, r1, r2, r3, r4);            /* 2 7 4 1 6 : and so on */
129
0
        STORE(4*i);
130
0
        out = ZOOM(r0, r1, r2, r3, r4) << 4;
131
0
        SHIFT(r0, r1, r2, r3, r4);            /* 3 8 5 2 7 */
132
0
        LOAD(1, i+1);                         /* 3 0 5 2 7 */
133
0
        out |= ZOOM(r0, r1, r2, r3, r4);
134
0
        SHIFT(r0, r1, r2, r3, r4);            /* 4 1 6 3 8 */
135
0
        STORE(4*i+1);
136
0
        LOAD(4, i+3);                         /* 4 1 6 3 0 */
137
0
        out = ZOOM(r0, r1, r2, r3, r4) << 4;
138
0
        SHIFT(r0, r1, r2, r3, r4);            /* 5 2 7 4 1 */
139
0
        out |= ZOOM(r0, r1, r2, r3, r4);
140
0
        STORE(4*i+2);
141
0
        SHIFT(r0, r1, r2, r3, r4);            /* 6 3 8 5 2 */
142
0
        LOAD(2, i+2);                         /* 6 3 0 5 2 */
143
0
        out = ZOOM(r0, r1, r2, r3, r4) << 4;
144
0
        SHIFT(r0, r1, r2, r3, r4);            /* 7 4 1 6 3 */
145
0
        out |= ZOOM(r0, r1, r2, r3, r4);
146
0
        STORE(4*i+3);
147
0
        SHIFT(r0, r1, r2, r3, r4);            /* 8 5 2 7 4 */
148
0
        LOAD(0, i+1);                         /* 0 5 2 7 4 */
149
0
    }
150
0
#undef ZOOM
151
0
#undef SHIFT
152
0
#undef LOAD
153
0
#undef STORE
154
0
}
155
156
157
static int
158
s_imscale_process(stream_state *st, stream_cursor_read *pr,
159
                stream_cursor_write *pw, bool last)
160
0
{
161
0
    stream_imscale_state *const ss = (stream_imscale_state *) st;
162
163
0
    while (1) {
164
0
        if (ss->dst_togo <= 0)
165
0
            return EOFC;
166
      /* deliver data from dst buffer */
167
0
        if (ss->dst_offset < ss->dst_size) {
168
0
            uint ncopy = min(pw->limit - pw->ptr, ss->dst_size - ss->dst_offset);
169
170
0
            if (ncopy == 0)
171
0
                return 1;
172
0
            ss->dst_togo -= ncopy;
173
174
0
            while (ncopy) {
175
0
                int line = ss->dst_offset / ss->dst_line_size;
176
0
                int offset = ss->dst_offset % ss->dst_line_size;
177
0
                int linecopy = min(ncopy, ss->dst_line_size - offset);
178
179
0
                memcpy(pw->ptr + 1, (byte *)ss->dst + line * ss->dst_line_padded  + offset, linecopy);
180
0
                pw->ptr += linecopy;
181
0
                ss->dst_offset += linecopy;
182
0
                ncopy -= linecopy;
183
0
            }
184
0
        }
185
186
        /* output a row, if possible */
187
0
        if (ss->dst_offset == ss->dst_size &&  /* dst is empty */
188
0
            ss->src_offset == ss->src_size) { /* src is full */
189
0
          if (ss->src_y >= 2) {
190
0
              zoom_line(ss);
191
0
                ss->dst_offset = 0;
192
0
          }
193
0
            ss->src_offset = 0;
194
0
            ss->src_y += 1;
195
0
        }
196
197
        /* input into window */
198
0
        if (ss->src_offset < ss->src_size) {
199
0
            uint rleft = pr->limit - pr->ptr;
200
0
            uint ncopy = min(rleft, ss->src_size - ss->src_offset);
201
202
0
            if (ss->src_y >= ss->params.HeightIn) {
203
0
                last = true;
204
0
                ncopy = 0;
205
0
            }
206
0
            if (rleft == 0 && !last)
207
0
                return 0; /* need more input */
208
0
            if (ncopy) {
209
0
                memcpy(ss->window + ss->src_line_padded * (ss->src_y % 5) + ss->src_offset, pr->ptr + 1, ncopy);
210
0
                ss->src_offset += ncopy;
211
0
                pr->ptr += ncopy;
212
0
            } else {
213
0
                memset(ss->window + ss->src_line_padded * (ss->src_y % 5) + ss->src_offset, 0xff, ss->src_size - ss->src_offset);
214
0
                ss->src_offset = ss->src_size;
215
0
            }
216
0
        }
217
0
    }
218
0
}
219
220
const stream_template s_imscale_template = {
221
    &st_imscale_state, s_imscale_init, s_imscale_process, 1, 1,
222
    s_imscale_release
223
};