Coverage Report

Created: 2022-10-31 07:00

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