Coverage Report

Created: 2026-04-01 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pxl/pximage.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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
/* pximage.c */
18
/* PCL XL bitmap painting operators */
19
20
#include "std.h"
21
#include "string_.h"
22
#include "pxerrors.h"
23
#include "pxoper.h"
24
#include "pxstate.h"
25
#include "gdebug.h"
26
#include "gsrop.h"
27
#include "gsrefct.h"
28
#include "gsstruct.h"
29
#include "gsstate.h"
30
#include "gscoord.h"
31
#include "gsimage.h"
32
#include "gspaint.h"
33
#include "gspath.h"
34
#include "gspath2.h"
35
#include "gsuid.h"              /* for gxpcolor.h */
36
#include "gsutil.h"
37
#include "gxbitmap.h"
38
#include "gxcspace.h"
39
#include "gxdevice.h"           /* for gxpcolor.h */
40
#include "gxcolor2.h"
41
#include "gxdcolor.h"
42
#include "gxpcolor.h"
43
#include "scommon.h"
44
#include "strimpl.h"
45
#include "srlx.h"
46
#include "jpeglib_.h"           /* for jpeg filter */
47
#include "sdct.h"
48
#include "sjpeg.h"
49
#include "pxptable.h"
50
#include "gxgstate.h"
51
52
/* Define the "freeing" procedure for patterns in a dictionary. */
53
void
54
px_free_pattern(gs_memory_t * mem, void *vptr, client_name_t cname)
55
170
{
56
170
    px_pattern_t *pattern = vptr;
57
58
170
    rc_decrement(pattern, cname);
59
170
}
60
/* Define the real freeing procedure for patterns. */
61
static void
62
rc_free_px_pattern(gs_memory_t * mem, void *vptr, client_name_t cname)
63
170
{
64
170
    px_pattern_t *pattern = vptr;
65
66
170
    gs_free_string(mem, (void *)pattern->palette.data, pattern->palette.size,
67
170
                   cname);
68
170
    gs_free_object(mem, pattern->data, cname);
69
170
    gs_free_object(mem, pattern, cname);
70
170
}
71
/* Define the purging procedure for the Pattern cache. */
72
/* The proc_data points to a pxePatternPersistence_t that specifies */
73
/* the maximum persistence level to purge. */
74
static bool
75
px_pattern_purge_proc(gx_color_tile * ctile, void *proc_data)
76
0
{
77
0
    return ctile->uid.id % pxePatternPersistence_next <=
78
0
        *(pxePatternPersistence_t *) proc_data;
79
0
}
80
void
81
px_purge_pattern_cache(px_state_t * pxs, pxePatternPersistence_t max_persist)
82
16.3k
{
83
16.3k
    gx_pattern_cache_winnow(gstate_pattern_cache(pxs->pgs),
84
16.3k
                            px_pattern_purge_proc, (void *)&max_persist);
85
16.3k
}
86
87
/* active decompression types */
88
typedef enum
89
{
90
    unset  = 0,
91
    nocomp = 1,
92
    rle    = 2,
93
    jpeg   = 4,
94
    delta  = 8,
95
} decomp_init_t;
96
97
0
static inline bool nocomp_inited(uint comp)  {return comp & nocomp;}
98
0
static inline bool rle_inited(uint comp)     {return comp & rle;}
99
0
static inline bool jpeg_inited(uint comp)    {return comp & jpeg;}
100
0
static inline bool delta_inited(uint comp)   {return comp & delta;}
101
102
0
static inline void nocomp_set(uint *comp) {*comp |= nocomp;}
103
0
static inline void rle_set(uint *comp)    {*comp |= rle;}
104
0
static inline void jpeg_set(uint *comp)   {*comp |= jpeg;}
105
0
static inline void delta_set(uint *comp)  {*comp |= delta;}
106
107
0
static inline void comp_unset(uint *comp)  {*comp = unset;}
108
109
/* pxl delta row decompression state machine states */
110
typedef enum
111
{
112
    next_is_bytecount,
113
    partial_bytecount,
114
    next_is_cmd,
115
    partial_offset,
116
    partial_cnt
117
} deltarow_parse_state_t;
118
119
/* pxl delta row decompression state storage */
120
typedef struct deltarow_state_s
121
{
122
    deltarow_parse_state_t state;
123
    uint row_byte_count;
124
    uint short_cnt;
125
    uint short_offset;
126
    byte *seedrow;
127
    uint rowwritten;
128
} deltarow_state_t;
129
130
/* Define the structure for enumerating a bitmap being downloaded. */
131
typedef struct px_bitmap_enum_s
132
{
133
    gs_memory_t *mem;           /* used only for the jpeg filter */
134
    uint data_per_row;          /* ditto minus possible trailing padding */
135
    uint initialized;
136
    stream_RLD_state rld_stream_state;  /* decompressor states */
137
    stream_DCT_state dct_stream_state;
138
    jpeg_decompress_data jdd;
139
    deltarow_state_t deltarow_state;
140
141
    /* Entries to deal with 'rebuffering' - the idea of making
142
     * input image data appear a different (but equivalent) shape.
143
     * Currently just morphing '1xH' bitmaps into 'Hx1' ones. */
144
    uint rebuffered_data_per_row; /* equal to data_per_row except when flipping */
145
    bool rebuffered;
146
    uint rebuffered_width;
147
    uint rebuffered_height;
148
    int rebuffered_row_pos;
149
    bool grayscale;
150
} px_bitmap_enum_t;
151
152
typedef struct px_begin_image_args_s {
153
    uint width, height;
154
    int depth;
155
    pxeColorMapping_t mapping;
156
    real dest_width, dest_height;
157
} px_bitmap_args_t;
158
159
/* Define our image enumerator. */
160
#ifndef px_image_enum_DEFINED
161
#  define px_image_enum_DEFINED
162
typedef struct px_image_enum_s px_image_enum_t;
163
#endif
164
struct px_image_enum_s
165
{
166
    gs_image_t image;
167
    byte *row;                  /* buffer for one row of data */
168
    gs_image_enum *ienum;       /* state structure for driver */
169
    px_bitmap_enum_t benum;
170
    px_bitmap_args_t bi_args;
171
    bool enum_started;
172
};
173
174
gs_private_st_simple(st_px_image_enum, px_image_enum_t, "px_image_enum_t");
175
176
177
static int
178
stream_error(stream_state * st, const char *str)
179
0
{
180
0
    return_error(-1);
181
0
}
182
183
static int
184
px_jpeg_init(px_bitmap_enum_t * benum, px_bitmap_params_t * params, px_args_t * par)
185
0
{
186
0
    stream_cursor_read r;
187
0
    stream_cursor_write w;
188
0
    uint used;
189
0
    const byte *data = par->source.data;
190
0
    stream_DCT_state *ss = (&benum->dct_stream_state);
191
0
    jpeg_decompress_data *jddp = &(benum->jdd);
192
0
    uint avail = par->source.available;
193
0
    int code = 0;
194
195
0
    if (!jpeg_inited(benum->initialized)) {
196
0
        s_init_state((stream_state *)ss, &s_DCTD_template, benum->mem);
197
0
        ss->report_error = stream_error;
198
0
        s_DCTD_template.set_defaults((stream_state *)ss);
199
200
0
        ss->jpeg_memory = benum->mem;
201
0
        ss->data.decompress = jddp;
202
203
0
        jddp->templat = s_DCTD_template;
204
0
        jddp->memory = benum->mem;
205
0
        jddp->scanline_buffer = NULL;
206
0
        jddp->PassThrough = 0;
207
0
        jddp->PassThroughfn = 0;
208
0
        jddp->device = (void *)0;
209
210
0
        if (gs_jpeg_create_decompress(ss) < 0)
211
0
            return_error(errorInsufficientMemory);
212
213
0
        (*s_DCTD_template.init) ((stream_state *)ss);
214
0
        jpeg_set(&benum->initialized);
215
0
    }
216
217
0
    r.ptr = data - 1;
218
0
    r.limit = r.ptr + avail;
219
220
    /* this seems to be the way to just get the header info */
221
0
    w.ptr = w.limit = 0;
222
0
    code =
223
0
        (*s_DCTD_template.process) ((stream_state *)ss, &r, &w, false);
224
225
0
    if (code < 0)
226
0
        goto error;
227
228
0
    used = r.ptr + 1 - data;
229
0
    par->source.data = r.ptr + 1;
230
0
    par->source.available = avail - used;
231
232
    /* Needs more data to complete reading the header */
233
0
    if (ss->phase < 2)
234
0
        return pxNeedData;
235
236
0
    params->width = jddp->dinfo.output_width;
237
0
    params->height = jddp->dinfo.output_height;
238
0
    {
239
0
        int comps = jddp->dinfo.output_components;
240
0
        if (comps == 1) {
241
0
            params->color_space = eGray;
242
0
        } else if (comps == 3) {
243
0
            params->color_space = eRGB;
244
0
        }
245
0
        else {
246
0
            code = -1;
247
0
            goto error;
248
0
        }
249
0
        params->depth = 8;
250
0
        return 0;
251
0
    }
252
253
0
error:
254
0
    gs_jpeg_destroy(ss);
255
0
    return_error(code);
256
0
}
257
258
/* Extract the parameters for reading a bitmap image or raster pattern. */
259
static int
260
begin_bitmap(px_bitmap_params_t * params, px_bitmap_enum_t * benum,
261
             const px_bitmap_args_t * bar, const px_state_t * pxs, bool is_jpeg, px_args_t * par)
262
191
{
263
191
    int depth;
264
191
    int num_components;
265
191
    px_gstate_t *pxgs = pxs->pxgs;
266
267
191
    benum->mem = pxs->memory;
268
269
191
    if (is_jpeg) {
270
0
        int code = px_jpeg_init(benum, params, par);
271
0
        if (code < 0 || code == pxNeedData)
272
0
            return_error(code);
273
0
        depth = params->depth;
274
0
        num_components = (params->color_space == eGray ? 1 : 3);
275
0
        if (num_components == 3 && pxgs->color_space == eGray)
276
0
            benum->grayscale = true;
277
191
    } else {
278
191
        px_gstate_t *pxgs = pxs->pxgs;
279
191
        depth = "\001\004\010"[bar->depth];
280
191
        num_components = (pxgs->color_space == eGray ? 1 : 3);
281
191
        params->width = bar->width;
282
191
        params->height = bar->height;
283
191
        params->depth = depth;
284
191
        params->color_space = pxgs->color_space;
285
191
    }
286
287
191
    if (bar->mapping == eIndexedPixel && !is_jpeg) {
288
0
        if (pxgs->palette.data == 0)
289
0
            return_error(errorMissingPalette);
290
0
        if (pxgs->palette.size != (1 << depth) * num_components)
291
0
            return_error(errorImagePaletteMismatch);
292
0
        params->indexed = true;
293
0
        num_components = 1;
294
0
    } else
295
191
        params->indexed = false;
296
297
191
    params->dest_width = bar->dest_width;
298
191
    params->dest_height = bar->dest_height;
299
191
    benum->data_per_row =
300
191
        ((params->width * params->depth * num_components) + 7) >> 3;
301
191
    return 0;
302
191
}
303
304
/* Extract the parameters for reading a bitmap image or raster pattern. */
305
/* Attributes: pxaColorMapping, pxaColorDepth, pxaSourceWidth, */
306
/* pxaSourceHeight, pxaDestinationSize. */
307
static int
308
begin_rebuffered_bitmap(px_bitmap_params_t * params, px_bitmap_enum_t * benum,
309
                        const px_bitmap_args_t * bar, const px_state_t * pxs, bool is_jpeg, px_args_t * par)
310
0
{
311
0
    int code = begin_bitmap(params, benum, bar, pxs, is_jpeg, par);
312
313
0
    if (code < 0 || code == pxNeedData)
314
0
        return_error(code);
315
316
0
    if (params->width == 1 && params->height > 1) {
317
0
        benum->rebuffered_data_per_row = benum->data_per_row * params->height;
318
0
        benum->rebuffered = 1;
319
0
        benum->rebuffered_width = params->height;
320
0
        benum->rebuffered_height = params->width;
321
0
        benum->rebuffered_row_pos = 0;
322
0
    } else {
323
0
        benum->rebuffered_data_per_row = benum->data_per_row;
324
0
        benum->rebuffered = 0;
325
0
        benum->rebuffered_width = params->width;
326
0
        benum->rebuffered_height = params->height;
327
0
    }
328
329
0
    return code;
330
0
}
331
332
static int
333
read_jpeg_bitmap_data(px_bitmap_enum_t * benum, byte ** pdata,
334
                      px_args_t * par, bool last)
335
0
{
336
0
    uint data_per_row = benum->data_per_row;    /* jpeg doesn't pad */
337
0
    uint avail = par->source.available;
338
0
    uint end_pos = data_per_row * par->pv[1]->value.i;
339
0
    uint pos_in_row = par->source.position % data_per_row;
340
0
    const byte *data = par->source.data;
341
0
    stream_DCT_state *ss = (&benum->dct_stream_state);
342
0
    stream_cursor_read r;
343
0
    stream_cursor_write w;
344
0
    uint used;
345
0
    int code = -1;
346
347
    /* consumed all of the data */
348
0
    if ((par->source.position >= end_pos) && (ss->phase != 4) && (par->source.available == 0)) {
349
        /* shutdown jpeg filter if necessary */
350
0
        if (jpeg_inited(benum->initialized))
351
0
            gs_jpeg_destroy((&benum->dct_stream_state));
352
0
        return 0;
353
0
    }
354
355
0
    if (last)
356
0
        return_error(errorIllegalDataLength);
357
358
0
    if (!jpeg_inited(benum->initialized)) {
359
0
        jpeg_decompress_data *jddp = &(benum->jdd);
360
361
        /* we do not allow switching from other compression schemes to jpeg */
362
0
        if (benum->initialized != unset)
363
0
            return_error(errorIllegalAttributeValue);
364
        /* use the graphics library support for DCT streams */
365
0
        ss->memory = benum->mem;
366
0
        ss->templat = &s_DCTD_template;
367
0
        s_DCTD_template.set_defaults((stream_state *) ss);
368
0
        ss->report_error = stream_error;
369
0
        ss->data.decompress = jddp;
370
        /* set now for allocation */
371
0
        jddp->memory = ss->jpeg_memory = benum->mem;
372
        /* set this early for safe error exit */
373
0
        jddp->scanline_buffer = NULL;
374
0
        jddp->PassThrough = 0;
375
0
        jddp->PassThroughfn = 0;
376
0
        jddp->device = (void *)0;
377
0
        if (gs_jpeg_create_decompress(ss) < 0)
378
0
            return_error(errorInsufficientMemory);
379
0
        (*s_DCTD_template.init) ((stream_state *) ss);
380
0
        jddp->templat = s_DCTD_template;
381
0
        jpeg_set(&benum->initialized);
382
0
    }
383
0
    r.ptr = data - 1;
384
0
    r.limit = r.ptr + avail;
385
0
    if (pos_in_row < data_per_row) {
386
        /* Read more of the current row. */
387
0
        byte *data = *pdata;
388
389
0
        w.ptr = data + pos_in_row - 1;
390
0
        w.limit = data + data_per_row - 1;
391
0
        code =
392
0
            (*s_DCTD_template.process) ((stream_state *) ss, &r, &w, false);
393
        /* code = num scanlines processed (0=need more data, -ve=error) */
394
0
        used = w.ptr + 1 - data - pos_in_row;
395
396
        /* the filter process returns 1 to indicate more room is
397
         * needed for the output data, which should not happen unless
398
         * the parameters are specified incorrectly.
399
         */
400
401
0
        if (code == 1)
402
0
            code = -1;
403
0
        if ((code == EOFC) && (used > 0))
404
0
            code = 1;
405
0
        pos_in_row += used;
406
0
        par->source.position += used;
407
0
    }
408
0
    used = r.ptr + 1 - data;
409
0
    par->source.data = r.ptr + 1;
410
0
    par->source.available = avail - used;
411
    /* The spec for this function says: Return 0 if we've processed all the
412
     * data in the block, 1 if we have a complete scan line, pxNeedData for
413
     * an incomplete scan line, or <0 for an error condition. The only way
414
     * we can return 0 currently is if we get an EOF from the underlying
415
     * decoder. */
416
0
    if (code == 0)
417
0
        return pxNeedData;
418
0
    if (code == EOFC)
419
0
        return 0;
420
0
    if (code > 0)
421
0
        return 1;
422
0
    return code;
423
0
}
424
425
static int
426
read_uncompressed_bitmap_data(px_bitmap_enum_t * benum, byte ** pdata,
427
                              px_args_t * par, bool last)
428
1.82k
{
429
1.82k
    int code;
430
1.82k
    uint avail = par->source.available;
431
1.82k
    uint data_per_row = benum->data_per_row;
432
1.82k
    uint pad = 4;               /* default padding */
433
1.82k
    const byte *data = par->source.data;
434
1.82k
    uint pos_in_row, data_per_row_padded, used;
435
436
    /* overrided default padding */
437
1.82k
    if (par->pv[3])
438
0
        pad = par->pv[3]->value.i;
439
440
1.82k
    data_per_row_padded = round_up(data_per_row, (int)pad);
441
1.82k
    pos_in_row = par->source.position % data_per_row_padded;
442
443
    /* consumed all of the data */
444
1.82k
    if (par->pv[1]->value.i < 0 ||
445
1.82k
        par->source.position >= data_per_row_padded * (ulong)par->pv[1]->value.i)
446
182
        return 0;
447
448
1.64k
    if (last)
449
0
        return_error(errorIllegalDataLength);
450
451
1.64k
    if (avail >= data_per_row_padded && pos_in_row == 0) {
452
        /* Use the data directly from the input buffer. */
453
1.45k
        *pdata = (byte *) data;
454
1.45k
        used = data_per_row_padded;
455
1.45k
        code = 1;
456
1.45k
    } else {
457
185
        used = min(avail, data_per_row_padded - pos_in_row);
458
185
        if (pos_in_row < data_per_row)
459
185
            memcpy(*pdata + pos_in_row, data,
460
185
                   min(used, data_per_row - pos_in_row));
461
185
        code = (pos_in_row + used < data_per_row_padded ? pxNeedData : 1);
462
185
    }
463
1.64k
    par->source.position += used;
464
1.64k
    par->source.data = data + used;
465
1.64k
    par->source.available = avail - used;
466
1.64k
    return code;
467
1.64k
}
468
469
static int
470
read_rle_bitmap_data(px_bitmap_enum_t * benum, byte ** pdata, px_args_t * par, bool last)
471
0
{
472
0
    stream_RLD_state *ss = (&benum->rld_stream_state);
473
0
    uint avail = par->source.available;
474
0
    const byte *data = par->source.data;
475
0
    uint pad = 4;
476
0
    stream_cursor_read r;
477
0
    stream_cursor_write w;
478
0
    uint pos_in_row, data_per_row, data_per_row_padded, used;
479
480
    /* overrided default padding */
481
0
    if (par->pv[3])
482
0
        pad = par->pv[3]->value.i;
483
0
    data_per_row = benum->data_per_row;
484
0
    data_per_row_padded = round_up(benum->data_per_row, (int)pad);
485
0
    pos_in_row = par->source.position % data_per_row_padded;
486
487
    /* consumed all of the data */
488
0
    if (par->pv[1]->value.i < 0 ||
489
0
        par->source.position >= data_per_row_padded * (ulong)par->pv[1]->value.i)
490
0
        return 0;
491
492
0
    if (last)
493
0
        return_error(errorIllegalDataLength);
494
495
0
    if (!rle_inited(benum->initialized)) {
496
0
        ss->EndOfData = false;
497
0
        ss->templat = &s_RLD_template;
498
0
        s_RLD_init_inline(ss);
499
0
        rle_set(&benum->initialized);
500
0
    }
501
502
0
    stream_cursor_read_init(&r, (const byte *)data, avail);
503
504
0
    if (pos_in_row < data_per_row) {
505
        /* Read more of the current row. */
506
0
        byte *data = *pdata;
507
508
0
        stream_cursor_write_init(&w, (const byte *)(data + pos_in_row), data_per_row - pos_in_row);
509
0
        (*s_RLD_template.process) ((stream_state *) ss, &r, &w, false);
510
0
        used = w.ptr + 1 - data - pos_in_row;
511
0
        pos_in_row += used;
512
0
        par->source.position += used;
513
0
    }
514
0
    if (pos_in_row >= data_per_row && pos_in_row < data_per_row_padded) {       /* We've read all the real data; skip the padding. */
515
0
        byte pad[3];            /* maximum padding per row */
516
517
0
        stream_cursor_write_init(&w, (const byte *)pad, data_per_row_padded - pos_in_row);
518
0
        (*s_RLD_template.process) ((stream_state *) ss, &r, &w, false);
519
0
        used = w.ptr + 1 - pad;
520
0
        pos_in_row += used;
521
0
        par->source.position += used;
522
0
    }
523
524
0
    used = r.ptr + 1 - data;
525
0
    par->source.data = r.ptr + 1;
526
0
    par->source.available = avail - used;
527
0
    return (pos_in_row < data_per_row_padded ? pxNeedData : 1);
528
0
}
529
530
/** PCL XL delta row decompression
531
 *
532
 * delta row Algorithm:
533
 *
534
 * Seed Row is initialized with zeros.
535
 *
536
 * lsb,msb row byte count
537
 * delta row data
538
 * repeat for each row
539
 *
540
 * if row byte count is zero duplicate previous row
541
 * if row byte count doesn't fill row duplicate remainder and end the row (undocumented)
542
 *
543
 * delta row data: command byte, optional extra offset bytes, delta raster snippit
544
 * command byte 7-5 delta raster length: 4-0 offset
545
 *
546
 * offset = bits 4-0;
547
 * if offset == 31 then do { add next byte } repeat while next byte was 0xFF
548
 * example offset = 31 + 255 + 255 + 255 + 4
549
 *
550
 * delta length = bits 5-7  + 1; range 1 to 8 bytes.
551
 *
552
 * output raster is:
553
 * last position + offset; "copies" old data
554
 * copy delta length bytes from input to output
555
 *
556
 * Internal Algorithm:
557
 *
558
 *  No row padding is used.
559
 *  State is need since available data can be short at any time.
560
 *  read = *pin++; // out of data? save state, return eNeedData
561
 *
562
 * deltarow.state maintains state between requests for more data
563
 * state             : description
564
 *                   -> next state
565
 * ---------------------------------------
566
 * next_is_bytecount : lsb of row bytecount
567
 *                   -> partial_bytecount
568
 * partial_bytecount : msb of row bytecount
569
 *                   -> next_is_cmd
570
 * next_is_cmd       : 1 byte cmd contains cnt and partial offset
571
 *                   -> partial_offset or partial_cnt
572
 * partial_offset    : accumulates extra offset bytes, moves output by offset
573
 *                   -> partial_offset or partial_cnt
574
 * partial_cnt       : copies cnt bytes one at a time from input
575
 *                   -> partial_cnt or next_is_cmd or (next_bytecount && end_of_row)
576
 *
577
 * RETURN values:
578
 *  0 == end of image   // end of row returns, next call returns end of image.
579
 *  1 == end of row
580
 *  eNeedData == on need more input
581
 */
582
static int
583
read_deltarow_bitmap_data(px_bitmap_enum_t * benum, byte ** pdata,
584
                          px_args_t * par, bool last)
585
0
{
586
0
    deltarow_state_t *deltarow = &benum->deltarow_state;
587
0
    uint avail = par->source.available;
588
0
    const byte *pin = par->source.data;
589
0
    byte *pout = *pdata + par->source.position % benum->data_per_row;
590
0
    const byte *pout_start = pout;
591
0
    bool end_of_row = false;
592
593
0
    if (delta_inited(benum->initialized) && deltarow->rowwritten == par->pv[1]->value.i) {
594
0
        deltarow->rowwritten = 0;
595
0
        return 0;
596
0
    }
597
598
0
    if (last)
599
0
        return_error(errorIllegalDataLength);
600
601
    /* initialize at begin of image */
602
0
    if (!delta_inited(benum->initialized)) {
603
        /* zero seed row */
604
0
        deltarow->seedrow =
605
0
            gs_alloc_bytes(benum->mem, benum->data_per_row,
606
0
                           "read_deltarow_bitmap_data");
607
0
        if (deltarow->seedrow == NULL)
608
0
            return 0;
609
0
        memset(deltarow->seedrow, 0, benum->data_per_row);
610
0
        deltarow->row_byte_count = 0;
611
0
        deltarow->short_cnt = 0;
612
0
        deltarow->short_offset = 0;
613
0
        deltarow->state = next_is_bytecount;
614
0
        deltarow->rowwritten = 0;
615
0
        delta_set(&benum->initialized);
616
0
    }
617
618
0
    if (deltarow->row_byte_count == 0) {
619
0
        memcpy(*pdata, deltarow->seedrow, benum->data_per_row);
620
0
    }
621
622
    /* one byte at a time until end of input or end of row */
623
0
    while (avail && !end_of_row) {
624
0
        switch (deltarow->state) {
625
626
0
            case next_is_bytecount:{
627
0
                    deltarow->short_cnt = *pin++;
628
0
                    --avail;
629
0
                    deltarow->state = partial_bytecount;
630
0
                    break;
631
0
                }
632
633
0
            case partial_bytecount:{
634
0
                    deltarow->row_byte_count =
635
0
                        deltarow->short_cnt + ((*pin++) << 8);
636
0
                    --avail;
637
638
0
                    if (deltarow->row_byte_count == 0) {
639
                        /* duplicate the row */
640
0
                        deltarow->state = next_is_bytecount;
641
0
                        end_of_row = true;
642
0
                    } else
643
0
                        deltarow->state = next_is_cmd;
644
0
                    break;
645
0
                }
646
647
0
            case next_is_cmd:{
648
0
                    uint val = *pin++;
649
650
0
                    --avail;
651
652
0
                    if (deltarow->row_byte_count == 0) {
653
                        /* duplicate the row */
654
0
                        deltarow->state = next_is_bytecount;
655
0
                        end_of_row = true;
656
0
                    } else {
657
0
                        deltarow->row_byte_count--;
658
0
                        deltarow->short_cnt = (val >> 5) + 1;       /* 1 to 8 new bytes to copy */
659
0
                        deltarow->short_offset = val & 0x1f;        /* num to retain from last row, skip */
660
0
                        if (deltarow->short_offset == 0x1f)
661
0
                            deltarow->state = partial_offset;       /* accumulate more offset */
662
0
                        else {
663
0
                            pout += deltarow->short_offset; /* skip keeps old data in row */
664
0
                            deltarow->state = partial_cnt;  /* done with offset do count */
665
0
                        }
666
0
                    }
667
0
                    break;
668
0
                }
669
670
0
            case partial_offset:{
671
0
                    uint offset = *pin++;
672
673
0
                    avail--;
674
0
                    if (deltarow->row_byte_count == 0) {
675
                        /* duplicate the row */
676
0
                        deltarow->state = next_is_bytecount;
677
0
                        end_of_row = true;
678
0
                    } else {
679
0
                        deltarow->row_byte_count--;
680
681
0
                        deltarow->short_offset += offset;
682
683
0
                        if (offset == 0xff)
684
0
                            deltarow->state = partial_offset;       /* 0x1f + ff ff ff ff ff + 1 */
685
0
                        else {
686
0
                            pout += deltarow->short_offset; /* skip keeps old data in row */
687
0
                            deltarow->state = partial_cnt;  /* done with offset do count */
688
0
                        }
689
0
                    }
690
0
                    break;
691
0
                }
692
693
0
            case partial_cnt:{
694
                    /* check for possible row overflow */
695
0
                    if (pout >= *pdata + benum->data_per_row)
696
0
                        pin++;
697
0
                    else
698
0
                        *pout++ = *pin++;   /* copy new data into row */
699
0
                    avail--;
700
0
                    if (deltarow->row_byte_count == 0) {
701
0
                        end_of_row = true;
702
0
                        deltarow->state = next_is_bytecount;
703
0
                    } else {
704
0
                        deltarow->row_byte_count--;
705
0
                        deltarow->short_cnt--;
706
707
0
                        if (deltarow->row_byte_count == 0) {
708
0
                            end_of_row = true;
709
0
                            deltarow->state = next_is_bytecount;
710
0
                        } else if (deltarow->short_cnt == 0)
711
0
                            deltarow->state = next_is_cmd;
712
                        /* else more bytes to copy */
713
0
                    }
714
0
                    break;
715
0
                }
716
717
0
        }                       /* end switch */
718
0
    }                           /* end of while */
719
720
0
    par->source.available -= pin - par->source.data;    /* subract comressed data used */
721
0
    par->source.data = pin;     /* new compressed data position */
722
723
0
    if (end_of_row) {
724
        /* uncompressed raster position */
725
0
        par->source.position =
726
0
            (par->source.position / benum->data_per_row +
727
0
             1) * benum->data_per_row;
728
0
        deltarow->rowwritten++;
729
0
        memcpy(deltarow->seedrow, *pdata, benum->data_per_row);
730
0
        return 1;
731
0
    }
732
0
    par->source.position += pout - pout_start;  /* amount of raster written */
733
0
    return pxNeedData;          /* not end of row so request more data */
734
0
}
735
736
/*
737
 * Read a (possibly partial) row of bitmap data.  This is most of the
738
 * implementation of ReadImage and ReadRastPattern.  We use source.position
739
 * to track the uncompressed input byte position within the current block.
740
 * Return 0 if we've processed all the data in the block, 1 if we have a
741
 * complete scan line, pxNeedData for an incomplete scan line, or <0 for
742
 * an error condition.  *pdata must point to a scan line buffer; this
743
 * routine may reset it to point into the input buffer (if a complete
744
 * scan line is available).
745
 * Attributes: pxaStartLine (ignored), pxaBlockHeight, pxaCompressMode.
746
 */
747
static int
748
read_bitmap(px_bitmap_enum_t * benum, byte ** pdata, px_args_t * par, bool last)
749
1.82k
{
750
1.82k
    switch (par->pv[2]->value.i) {
751
0
        case eRLECompression:
752
0
            return read_rle_bitmap_data(benum, pdata, par, last);
753
0
        case eJPEGCompression:
754
0
            return read_jpeg_bitmap_data(benum, pdata, par, last);
755
0
        case eDeltaRowCompression:
756
0
            return read_deltarow_bitmap_data(benum, pdata, par, last);
757
1.82k
        case eNoCompression:
758
1.82k
            return read_uncompressed_bitmap_data(benum, pdata, par, last);
759
0
        default:
760
0
            break;
761
1.82k
    }
762
0
    return -1;
763
1.82k
}
764
765
static int read_rebuffered_bitmap(px_bitmap_enum_t * benum, byte ** pdata, px_args_t * par)
766
0
{
767
0
    int code;
768
769
0
    if (!benum->rebuffered)
770
0
        return read_bitmap(benum, pdata, par, /* last */ false);
771
772
0
    {
773
0
        int w = benum->rebuffered_width;
774
0
        byte *rowptr = *pdata;
775
0
        byte *data2 = rowptr + benum->rebuffered_row_pos * benum->data_per_row;
776
0
        for (; benum->rebuffered_row_pos < w; benum->rebuffered_row_pos++) {
777
0
            byte *data3 = data2;
778
0
            code = read_bitmap(benum, &data3, par, /* last */ false);
779
0
            if (code == 0) {
780
0
                return 0;
781
0
            } else if (code == 1) {
782
                /* got a scanline! (well, 1 pixel really, cos we are flipping) */
783
0
            } else {
784
0
                if (par->source.available == 0)
785
0
                    return pxNeedData;
786
0
                return code;
787
0
            }
788
0
            if (data3 != data2) {
789
0
                memcpy(data2, data3, benum->data_per_row);
790
0
            }
791
0
            data2 += benum->data_per_row;
792
0
        }
793
0
        benum->rebuffered_row_pos = 0;
794
0
    }
795
0
    return code;
796
0
}
797
798
799
/* ---------------- Image operators ---------------- */
800
801
const byte apxBeginImage[] = {
802
    pxaColorMapping, pxaColorDepth, pxaSourceWidth, pxaSourceHeight,
803
    pxaDestinationSize, 0, 0
804
};
805
806
int
807
pxBeginImage(px_args_t * par, px_state_t * pxs)
808
0
{
809
0
    px_image_enum_t *pxenum;
810
0
    px_bitmap_args_t bi_args;
811
812
0
    pxenum =
813
0
        gs_alloc_struct(pxs->memory, px_image_enum_t,
814
0
                        &st_px_image_enum, "setup_bitmap(pxenum)");
815
816
0
    if (pxenum == 0)
817
0
        return_error(errorInsufficientMemory);
818
819
    /*
820
     * store a copy of the args.  For JPEG these parameters may be
821
     * revised depending on the color parameters in the JPEG data.
822
     * We defer image set up until we read the image data.
823
     */
824
825
0
    bi_args.mapping     = par->pv[0]->value.i;
826
0
    bi_args.depth       = par->pv[1]->value.i;
827
0
    bi_args.width       = par->pv[2]->value.i;
828
0
    bi_args.height      = par->pv[3]->value.i;
829
0
    bi_args.dest_width  = real_value(par->pv[4], 0);
830
0
    bi_args.dest_height = real_value(par->pv[4], 1);
831
832
0
    pxenum->bi_args = bi_args;
833
0
    pxenum->enum_started = false;
834
0
    pxs->image_enum = pxenum;
835
0
    memset(&pxenum->benum, 0, sizeof(pxenum->benum));
836
0
    return 0;
837
0
}
838
839
static int
840
px_begin_image(px_state_t * pxs, bool is_jpeg, px_args_t * par)
841
0
{
842
0
    gs_point origin;
843
0
    px_bitmap_params_t params;
844
0
    gs_gstate *pgs = pxs->pgs;
845
0
    px_gstate_t *pxgs = pxs->pxgs;
846
0
    px_image_enum_t *pxenum = pxs->image_enum;
847
0
    px_bitmap_enum_t *pbenum = &pxenum->benum;
848
0
    int code;
849
850
0
    if (gs_currentpoint(pgs, &origin) < 0)
851
0
        return_error(errorCurrentCursorUndefined);
852
    /*
853
     * If the current logical operation doesn't involve the texture,
854
     * don't set a null brush, which would cause the image not to
855
     * appear.
856
     */
857
0
    if (pxs->pxgs->brush.type == pxpNull &&
858
0
        !rop3_uses_T(gs_currentrasterop(pgs)))
859
0
        code = gs_setgray(pgs, 0.0);
860
0
    else
861
0
        code = px_set_paint(&pxgs->brush, pxs);
862
863
0
    if (code < 0)
864
0
        return code;
865
    /*
866
     * Make sure the proper halftone is current.
867
     */
868
0
    code = px_set_halftone(pxs);
869
0
    if (code < 0)
870
0
        return code;
871
0
    code = begin_rebuffered_bitmap(&params, pbenum, &pxenum->bi_args, pxs, is_jpeg, par);
872
0
    if (code < 0 || code == pxNeedData)
873
0
        return_error(code);
874
875
0
    pxenum->row = gs_alloc_byte_array(pxs->memory, 1, pbenum->rebuffered_data_per_row,
876
0
                                      "pxReadImage(row)");
877
0
    if (pxenum->row == 0)
878
0
        code = gs_note_error(errorInsufficientMemory);
879
0
    else
880
0
        code =
881
0
            px_image_color_space(&pxenum->image, &params,
882
0
                                 (const gs_string *)&pxgs->palette, pgs);
883
884
0
    if (code < 0)
885
0
        goto free_buffers_and_exit;
886
887
    /* Set up the image parameters. */
888
0
    pxenum->image.Width = pbenum->rebuffered_width;
889
0
    pxenum->image.Height = pbenum->rebuffered_height;
890
0
    {
891
0
        gs_matrix imat, dmat;
892
893
        /* We need the cast because height is unsigned. */
894
        /* We also need to account for the upside-down H-P */
895
        /* coordinate system. */
896
0
        gs_make_scaling(params.width, params.height, &imat);
897
0
        if (pbenum->rebuffered) {
898
0
            imat.xy = imat.xx; imat.xx = 0;
899
0
            imat.yx = imat.yy; imat.yy = 0;
900
0
        }
901
0
        gs_make_translation(origin.x, origin.y, &dmat);
902
0
        gs_matrix_scale(&dmat, params.dest_width, params.dest_height, &dmat);
903
        /* The ImageMatrix is dmat' * imat. */
904
0
        code = gs_matrix_invert(&dmat, &dmat);
905
0
        if (code < 0)
906
0
            goto free_buffers_and_exit;
907
0
        gs_matrix_multiply(&dmat, &imat, &pxenum->image.ImageMatrix);
908
0
    }
909
0
    pxenum->image.CombineWithColor = true;
910
0
    pxenum->image.Interpolate = pxs->interpolate;
911
912
0
    pxenum->ienum = gs_image_enum_alloc(gs_gstate_memory(pgs), "px_begin_image");
913
0
    if (pxenum->ienum == NULL) {
914
0
        code = gs_note_error(gs_error_VMerror);
915
0
        goto free_buffers_and_exit;
916
0
    }
917
0
    code = gs_image_init(pxenum->ienum, &pxenum->image,
918
0
                         pxenum->image.ImageMask | pxenum->image.CombineWithColor,
919
0
                         false, pgs);
920
0
    if (code < 0) {
921
0
        gs_image_cleanup_and_free_enum(pxenum->ienum, pgs);
922
0
        pxenum->ienum = NULL;
923
        /* This procedure will be re-invoked if we are remapping the
924
           color so don't free the resources */
925
0
free_buffers_and_exit:
926
0
        if (code != gs_error_Remap_Color) {
927
0
            gs_free_object(pxs->memory, pxenum->row, "pxReadImage(row)");
928
0
            gs_free_object(pxs->memory, pxenum, "pxBeginImage(pxenum)");
929
0
        }
930
0
        return code;
931
0
    }
932
0
    return 0;
933
934
0
}
935
936
const byte apxReadImage[] = {
937
    pxaStartLine, pxaBlockHeight, pxaCompressMode, 0, pxaPadBytesMultiple,
938
        pxaBlockByteLength, 0
939
};
940
941
int
942
pxReadImage(px_args_t * par, px_state_t * pxs)
943
0
{
944
0
    px_image_enum_t *pxenum = pxs->image_enum;
945
0
    int code = 0;
946
947
0
    if (par->pv[1]->value.i == 0)
948
0
        return 0;               /* no data */
949
0
    if (par->pv[3] != NULL && (par->pv[3]->value.i < 1 || par->pv[3]->value.i > 4))
950
0
        return_error(gs_error_rangecheck);
951
    /* Make a quick check for the first call, when no data is available. */
952
0
    if (par->source.available == 0)
953
0
        return pxNeedData;
954
0
    if (!pxenum->enum_started) {
955
0
        bool is_jpeg = par->pv[2]->value.i == eJPEGCompression;
956
0
        code = px_begin_image(pxs, is_jpeg, par);
957
0
        if (code < 0 || code == pxNeedData)
958
0
            return code;
959
0
        pxenum->enum_started = true;
960
0
    }
961
0
    for (;;) {
962
0
        byte *data = pxenum->row;
963
0
        uint used;
964
0
        int code = read_rebuffered_bitmap(&pxenum->benum, &data, par);
965
0
        if (code != 1)
966
0
            return code;
967
968
0
        if (pxenum->benum.grayscale) {
969
0
            int i;
970
0
            for (i = 2; i < pxenum->benum.rebuffered_data_per_row; i+=3) {
971
0
                int r = data[i-2];
972
0
                int g = data[i-1];
973
0
                int b = data[i];
974
                /* we think this simple conversion is commensurate
975
                   with typical XL business graphics use cases. */
976
0
                int gray = (r + g + b) / 3;
977
0
                data[i-2] = data[i-1] = data[i] = gray;
978
0
            }
979
0
        }
980
981
0
        code = gs_image_next(pxenum->ienum, data,
982
0
                             pxenum->benum.rebuffered_data_per_row,
983
0
                             &used);
984
0
        if (code < 0)
985
0
            return code;
986
987
0
        pxs->have_page = true;
988
0
    }
989
0
}
990
991
const byte apxEndImage[] = { 0, 0 };
992
int
993
pxEndImage(px_args_t * par, px_state_t * pxs)
994
0
{
995
0
    px_image_enum_t *pxenum = pxs->image_enum;
996
0
    px_bitmap_enum_t *pbenum = &pxenum->benum;
997
0
    int code = gs_image_cleanup_and_free_enum(pxenum->ienum, pxs->pgs);
998
999
0
    gs_free_object(pxs->memory, pxenum->row, "pxEndImage(row)");
1000
0
    gs_free_object(pbenum->mem, pbenum->deltarow_state.seedrow,
1001
0
                   "pxEndImage(seedrow)");
1002
0
    if (pxenum->image.ColorSpace)
1003
0
        rc_decrement(pxenum->image.ColorSpace,
1004
0
                     "pxEndImage(image.ColorSpace)");
1005
0
    gs_free_object(pxs->memory, pxenum, "pxEndImage(pxenum)");
1006
0
    pxs->image_enum = 0;
1007
0
    return code;
1008
0
}
1009
1010
/* ---------------- Raster pattern operators ---------------- */
1011
1012
/* Define the enumerator for downloading raster patterns. */
1013
#ifndef px_pattern_enum_DEFINED
1014
#  define px_pattern_enum_DEFINED
1015
typedef struct px_pattern_enum_s px_pattern_enum_t;
1016
#endif
1017
struct px_pattern_enum_s
1018
{
1019
    px_bitmap_enum_t benum;
1020
    int32_t pattern_id;
1021
    pxePatternPersistence_t persistence;
1022
    px_pattern_t *pattern;
1023
    int lines_rendered;
1024
};
1025
1026
gs_private_st_simple(st_px_pattern_enum, px_pattern_enum_t,
1027
                     "px_pattern_enum_t");
1028
1029
const byte apxBeginRastPattern[] = {
1030
    pxaColorMapping, pxaColorDepth, pxaSourceWidth, pxaSourceHeight,
1031
    pxaDestinationSize, pxaPatternDefineID, pxaPatternPersistence, 0, 0
1032
};
1033
int
1034
pxBeginRastPattern(px_args_t * par, px_state_t * pxs)
1035
191
{
1036
191
    gs_memory_t *mem = pxs->memory;
1037
191
    px_bitmap_params_t params;
1038
191
    px_pattern_t *pattern;
1039
191
    px_pattern_enum_t *pxenum;
1040
191
    px_bitmap_enum_t benum;
1041
191
    px_bitmap_args_t bi_args;
1042
191
    byte *data;
1043
191
    uint psize;
1044
191
    byte *pdata;
1045
191
    int code;
1046
191
    static const gs_memory_struct_type_t st_px_pattern =
1047
191
        { sizeof(px_pattern_t), "", 0, 0, 0, 0, 0 };
1048
1049
1050
191
    bi_args.mapping     = par->pv[0]->value.i;
1051
191
    bi_args.depth       = par->pv[1]->value.i;
1052
191
    bi_args.width       = par->pv[2]->value.i;
1053
191
    bi_args.height      = par->pv[3]->value.i;
1054
191
    bi_args.dest_width  = real_value(par->pv[4], 0);
1055
191
    bi_args.dest_height = real_value(par->pv[4], 1);
1056
1057
191
    memset(&benum, 0, sizeof(benum));
1058
191
    code = begin_bitmap(&params, &benum, &bi_args, pxs, false, par);
1059
1060
191
    if (code < 0)
1061
0
        return code;
1062
191
    rc_alloc_struct_1(pattern, px_pattern_t, &st_px_pattern, mem,
1063
191
                      return_error(errorInsufficientMemory),
1064
191
                      "raster pattern");
1065
191
    pattern->rc.free = rc_free_px_pattern;
1066
191
    data = gs_alloc_byte_array(mem, params.height, benum.data_per_row,
1067
191
                               "raster pattern data");
1068
191
    if (params.indexed) {
1069
0
        psize = pxs->pxgs->palette.size;
1070
0
        pdata = gs_alloc_string(mem, psize, "raster pattern palette");
1071
0
        if (pdata != 0)
1072
0
            memcpy(pdata, pxs->pxgs->palette.data, psize);
1073
191
    } else {
1074
191
        psize = 0;
1075
191
        pdata = 0;
1076
191
    }
1077
191
    pxenum = gs_alloc_struct(mem, px_pattern_enum_t, &st_px_pattern_enum,
1078
191
                             "raster pattern enum");
1079
191
    if (data == 0 || (params.indexed && pdata == 0) || pxenum == 0) {
1080
0
        gs_free_object(mem, pxenum, "raster pattern enum");
1081
0
        gs_free_string(mem, pdata, psize, "raster pattern palette");
1082
0
        gs_free_object(mem, data, "raster pattern data");
1083
0
        gs_free_object(mem, pattern, "raster pattern");
1084
0
        return_error(errorInsufficientMemory);
1085
0
    }
1086
191
    pxenum->benum = benum;
1087
191
    pxenum->pattern_id = par->pv[5]->value.i;
1088
191
    pxenum->persistence = par->pv[6]->value.i;
1089
191
    pxenum->lines_rendered = 0;
1090
191
    pattern->params = params;
1091
191
    pattern->palette.data = pdata;
1092
191
    pattern->palette.size = psize;
1093
191
    pattern->data = data;
1094
191
    pattern->id = gs_next_ids(mem, 1);
1095
191
    pxenum->pattern = pattern;
1096
191
    pxs->pattern_enum = pxenum;
1097
191
    return 0;
1098
191
}
1099
1100
const byte apxReadRastPattern[] = {
1101
    pxaStartLine, pxaBlockHeight, pxaCompressMode, 0, pxaPadBytesMultiple,
1102
        pxaBlockByteLength, 0
1103
};
1104
1105
int
1106
pxReadRastPattern(px_args_t * par, px_state_t * pxs)
1107
369
{
1108
369
    px_pattern_enum_t *pxenum = pxs->pattern_enum;
1109
369
    int code;
1110
369
    byte *plimit = pxenum->pattern->data +
1111
369
        (pxenum->benum.data_per_row * pxenum->pattern->params.height);
1112
1113
369
    if (par->pv[1]->value.i == 0)
1114
0
        return 0;               /* no data */
1115
1116
    /* first call */
1117
369
    if (par->source.available == 0)
1118
186
        pxenum->lines_rendered = 0;
1119
1120
1.82k
    for (;;) {
1121
1.82k
        byte *data = pxenum->pattern->data +
1122
1.82k
            (par->pv[0]->value.i + pxenum->lines_rendered) * pxenum->benum.data_per_row;
1123
1.82k
        byte *rdata = data;
1124
1125
1.82k
        if (data > plimit)
1126
2
            return_error(gs_error_rangecheck);
1127
1128
1.82k
        code = read_bitmap(&pxenum->benum, &rdata, par, /* last */ data == plimit);
1129
1.82k
        if (code != 1)
1130
367
            break;
1131
1132
1.45k
        pxenum->lines_rendered++;
1133
1134
1.45k
        if (rdata != data)
1135
1.45k
            memcpy(data, rdata, pxenum->benum.data_per_row);
1136
1.45k
    }
1137
1138
367
    return code;
1139
369
}
1140
1141
const byte apxEndRastPattern[] = { 0, 0 };
1142
int
1143
pxEndRastPattern(px_args_t * par, px_state_t * pxs)
1144
170
{
1145
170
    px_pattern_enum_t *pxenum = pxs->pattern_enum;
1146
    /* We extract the key and value from the pattern_enum structure */
1147
    /* and then free the structure, to encourage LIFO allocation. */
1148
170
    px_pattern_t *pattern = pxenum->pattern;
1149
170
    int32_t id = pxenum->pattern_id;
1150
170
    px_value_t key;
1151
170
    px_dict_t *pdict;
1152
1153
170
    switch (pxenum->persistence) {
1154
0
        case eTempPattern:
1155
0
            pdict = &pxs->pxgs->temp_pattern_dict;
1156
0
            break;
1157
0
        case ePagePattern:
1158
0
            pdict = &pxs->page_pattern_dict;
1159
0
            break;
1160
170
        case eSessionPattern:
1161
170
            pdict = &pxs->session_pattern_dict;
1162
170
            break;
1163
0
        default:               /* can't happen */
1164
0
            return_error(errorIllegalAttributeValue);
1165
170
    }
1166
170
    key.type = pxd_array | pxd_ubyte;
1167
170
    key.value.array.data = (byte *) & id;
1168
170
    key.value.array.size = sizeof(id);
1169
170
    gs_free_object(pxs->memory, pxenum, "pxEndRastPattern(pxenum)");
1170
170
    return px_dict_put(pdict, &key, pattern);
1171
170
}
1172
1173
/* ---------------- Scan line operators ---------------- */
1174
1175
const byte apxBeginScan[] = { 0, 0 };
1176
int
1177
pxBeginScan(px_args_t * par, px_state_t * pxs)
1178
13
{
1179
13
    int code = px_set_paint(&pxs->pxgs->brush, pxs);
1180
1181
13
    if (code < 0)
1182
0
        return code;
1183
    /* We may as well reset the path now instead of at the end. */
1184
13
    return gs_newpath(pxs->pgs);
1185
13
}
1186
1187
const byte apxEndScan[] = { 0, 0 };
1188
int
1189
pxEndScan(px_args_t * par, px_state_t * pxs)
1190
0
{
1191
0
    return 0;
1192
0
}
1193
1194
const byte apxScanLineRel[] = {
1195
    0, pxaNumberOfScanLines, 0
1196
};
1197
int
1198
pxScanLineRel(px_args_t * par, px_state_t * pxs)
1199
0
{                               /*
1200
                                 * In order to keep the number of intermediate states down to a
1201
                                 * reasonable number, we require enough data to be present to be
1202
                                 * able to read the control information for each line, or an entire
1203
                                 * x-pair.  Initially, source.position is zero.  As soon as we have
1204
                                 * read the X/YStart type byte, we change it to:
1205
                                 *      (X/YStart type) << 28 + (x-pair type << 24) +
1206
                                 *        (# of full or partial scan lines left to process) + 1
1207
                                 * We use the separate variable source.count to keep track of
1208
                                 * the number of x-pairs left in the scan line.
1209
                                 */
1210
0
    gs_gstate *pgs = pxs->pgs;
1211
0
    bool big_endian = pxs->data_source_big_endian;
1212
0
    const byte *data = par->source.data;
1213
0
    pxeDataType_t
1214
0
        xystart_type = (par->source.position >> 28) & 0xf,
1215
0
        xpair_type = (par->source.position >> 24) & 0xf;
1216
0
    int code = 0;
1217
0
    int rcount;
1218
0
    gs_rect rlist[20];          /* 20 is arbitrary */
1219
1220
    /* High level pattern support kludge. We need to know if we are executing
1221
     * a high level pattern before we go consuming any of the input, because if
1222
     * we are we need to return to the interpreter, set up the high level
1223
     * pattern and then come back here. Obviously if we've consumed the data
1224
     * we can't come back and rerun it. So we do a 'no op' rectfill which will
1225
     * set the color, if it is a high level pattern then we will get an error
1226
     * which we return.
1227
     */
1228
0
    code = gs_rectfill(pgs, NULL, 0);
1229
0
    if (code < 0)
1230
0
        return code;
1231
1232
    /* Check for initial state. */
1233
0
    if (par->source.position == 0) {    /* Read XStart/YStart data type. */
1234
0
        if (par->source.available < 1)
1235
0
            return pxNeedData;
1236
0
        xystart_type = data[0];
1237
0
        if (xystart_type != eSInt16)
1238
0
            return_error(errorIllegalDataValue);
1239
0
        par->source.position =
1240
0
            ((ulong) xystart_type << 28) +
1241
0
            (par->pv[0] ? par->pv[0]->value.i : 1) + 1;
1242
0
        par->source.data = data += 1;
1243
0
        par->source.available -= 1;
1244
0
        par->source.count = 0;
1245
0
    }
1246
0
    for (rcount = 0;;) {
1247
1248
        /* Check for start of scan line. */
1249
0
        if (par->source.count == 0) {
1250
0
            int ystart;
1251
1252
0
            if ((par->source.position & 0xffffff) == 1) {
1253
0
                code = 0;
1254
0
                break;
1255
0
            }
1256
            /* Read XStart and YStart values. */
1257
            /* We know that eSInt16 is the only possible data type. */
1258
0
            if (par->source.available < 7) {
1259
0
                code = pxNeedData;
1260
0
                break;
1261
0
            }
1262
0
            pxs->scan_point.x = sint16at(data, big_endian);
1263
0
            ystart = sint16at(data + 2, big_endian);
1264
0
            pxs->scan_point.y0 = ystart - 0.5;
1265
0
            pxs->scan_point.y1 = ystart + 0.5;
1266
0
            par->source.count = uint16at(data + 4, big_endian);
1267
0
            if (par->source.count == 0) {
1268
0
                code = gs_note_error(errorIllegalDataValue);
1269
0
                break;
1270
0
            }
1271
0
            xpair_type = data[6];
1272
0
            par->source.position =
1273
0
                (par->source.position & 0xf0ffffff) +
1274
0
                ((ulong) xpair_type << 24);
1275
0
            par->source.data = data += 7;
1276
0
            par->source.available -= 7;
1277
0
        }
1278
        /* Read and process one x-pair. */
1279
0
        {
1280
0
            uint x0, x1;
1281
0
            uint used;
1282
1283
0
            switch (xpair_type) {
1284
0
                case eUByte:
1285
0
                    if (par->source.available < 2) {
1286
0
                        code = pxNeedData;
1287
0
                        goto out;       /* 2-level break */
1288
0
                    }
1289
0
                    x0 = data[0];
1290
0
                    x1 = data[1];
1291
0
                    used = 2;
1292
0
                    break;
1293
0
                case eUInt16:
1294
0
                    if (par->source.available < 4) {
1295
0
                        code = pxNeedData;
1296
0
                        goto out;       /* 2-level break */
1297
0
                    }
1298
0
                    x0 = uint16at(data, big_endian);
1299
0
                    x1 = uint16at(data + 2, big_endian);
1300
0
                    used = 4;
1301
0
                    break;
1302
0
                default:
1303
0
                    code = gs_note_error(errorIllegalDataValue);
1304
0
                    goto out;   /* 2-level break; */
1305
0
            }
1306
0
            if (rcount == countof(rlist)) {
1307
0
                code = gs_rectfill(pgs, rlist, rcount);
1308
0
                rcount = 0;
1309
0
                pxs->have_page = true;
1310
0
                if (code < 0)
1311
0
                    break;
1312
0
            }
1313
0
            {
1314
0
                gs_rect *pr = &rlist[rcount++];
1315
1316
0
                pr->p.x = pxs->scan_point.x += x0;
1317
0
                pr->p.y = pxs->scan_point.y0;
1318
0
                pr->q.x = pxs->scan_point.x += x1;
1319
0
                pr->q.y = pxs->scan_point.y1;
1320
0
            }
1321
0
            par->source.data = data += used;
1322
0
            par->source.available -= used;
1323
0
        }
1324
0
        if (!--(par->source.count))
1325
0
            --(par->source.position);
1326
0
    }
1327
0
  out:
1328
0
    if (rcount > 0 && code >= 0) {
1329
0
        int rcode = gs_rectfill(pgs, rlist, rcount);
1330
1331
0
        pxs->have_page = true;
1332
0
        if (rcode < 0)
1333
0
            code = rcode;
1334
0
    }
1335
0
    return code;
1336
0
}