Coverage Report

Created: 2025-11-16 07:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/gxclbits.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
/* Halftone and bitmap writing for command lists */
18
#include "memory_.h"
19
#include "gx.h"
20
#include "gpcheck.h"
21
#include "gserrors.h"
22
#include "gsbitops.h"
23
#include "gxdevice.h"
24
#include "gxdevmem.h"   /* must precede gxcldev.h */
25
#include "gdevprn.h"            /* for BLS_force_memory */
26
#include "gxcldev.h"
27
#include "gxfmap.h"
28
#include "gxpcolor.h"   /* for gx_device_is_pattern_clist */
29
30
/*
31
 * Define when, if ever, to write character bitmaps in all bands.
32
 * Set this to:
33
 *      0 to always write in all bands;
34
 *      N to write in all bands when the character has been seen in N+1
35
 *         bands on a page;
36
 *      max_ushort to never write in all bands.
37
 */
38
20.2M
#define CHAR_ALL_BANDS_COUNT max_ushort
39
40
/* ------ Writing ------ */
41
42
/*
43
 * Determine the (possibly unpadded) width in bytes for writing a bitmap,
44
 * per the algorithm in gxcldev.h.  If compression_mask has any of the
45
 * cmd_mask_compress_any bits set, we assume the bitmap will be compressed.
46
 * Return the total size of the bitmap.
47
 */
48
uint
49
clist_bitmap_bytes(uint width_bits, uint height, int compression_mask,
50
                   uint * width_bytes, uint * raster)
51
76.3M
{
52
76.3M
    uint full_raster = *raster = bitmap_raster(width_bits);
53
76.3M
    uint short_raster = (width_bits + 7) >> 3;
54
76.3M
    uint width_bytes_last;
55
56
76.3M
    if (compression_mask & cmd_mask_compress_any)
57
21.3M
        *width_bytes = width_bytes_last = full_raster;
58
55.0M
    else if (short_raster <= cmd_max_short_width_bytes ||
59
4.10M
             height <= 1 ||
60
519k
             (compression_mask & decompress_spread) != 0
61
55.0M
        )
62
54.5M
        *width_bytes = width_bytes_last = short_raster;
63
519k
    else
64
519k
        *width_bytes = full_raster, width_bytes_last = short_raster;
65
76.3M
    return
66
76.3M
        (height == 0 ? 0 : *width_bytes * (height - 1) + width_bytes_last);
67
76.3M
}
68
69
/*
70
 * Compress a bitmap, skipping extra padding bytes at the end of each row if
71
 * necessary.  We require height >= 1, raster >= bitmap_raster(width_bits).
72
 */
73
static int
74
go_process(stream_state * st, stream_cursor_read *pr, stream_cursor_write *pw, bool end)
75
243M
{
76
243M
    int status = (*st->templat->process) (st, pr, pw, end);
77
243M
    if (status)
78
1.60M
        return status;
79
    /* We don't attempt to handle compressors that */
80
    /* require >1 input byte to make progress. */
81
242M
    if (pr->ptr != pr->limit)
82
0
        return -1;
83
242M
    return 0;
84
242M
}
85
static byte zeros[1<<align_bitmap_mod] = { 0, };
86
static int
87
cmd_compress_bitmap(stream_state * st, const byte * data, uint width_bits,
88
                    uint raster, uint height, stream_cursor_write * pw)
89
4.19M
{
90
4.19M
    uint width_bytes = bitmap_raster(width_bits);
91
4.19M
    int status = 0;
92
4.19M
    stream_cursor_read r;
93
4.19M
    stream_cursor_read r2;
94
4.19M
    uint whole_bytes = width_bits>>3;
95
4.19M
    uint mask = (0xff00>>(width_bits & 7)) & 0xff;
96
4.19M
    uint padding = width_bytes - ((width_bits+7)>>3);
97
98
4.19M
    if (raster == whole_bytes) {
99
15.9k
        stream_cursor_read_init(&r, data, raster * (size_t)height);
100
15.9k
        status = (*st->templat->process) (st, &r, pw, true);
101
4.18M
    } else {     /* Compress row-by-row. */
102
4.18M
        uint y;
103
104
4.18M
        stream_cursor_read_init(&r, data, whole_bytes);
105
106
84.6M
        for (y = height-1; (r.limit = r.ptr + whole_bytes), y > 0; y--) {
107
80.6M
            status = go_process(st, &r, pw, false);
108
80.6M
            if (status)
109
112k
                break;
110
80.5M
            if (mask) {
111
73.3M
                byte b = r.ptr[1] & mask;
112
113
73.3M
                stream_cursor_read_init(&r2, &b, 1);
114
73.3M
                status = go_process(st, &r2, pw, false);
115
73.3M
                if (status)
116
2.80k
                    break;
117
73.3M
            }
118
80.5M
            if (padding) {
119
78.7M
                stream_cursor_read_init(&r2, zeros, padding);
120
78.7M
                status = go_process(st, &r2, pw, false);
121
78.7M
                if (status)
122
110k
                    break;
123
78.7M
            }
124
80.4M
            r.ptr += (int)(raster - whole_bytes);
125
80.4M
        }
126
4.18M
        if (status == 0) {
127
3.95M
            status = go_process(st, &r, pw, padding == 0 && mask == 0);
128
3.95M
            if (status == 0 && mask) {
129
3.41M
                byte b = r.ptr[1] & mask;
130
131
3.41M
                stream_cursor_read_init(&r2, &b, 1);
132
3.41M
                status = go_process(st, &r2, pw, padding == 0);
133
3.41M
            }
134
3.95M
            if (status == 0 && padding) {
135
3.59M
                stream_cursor_read_init(&r2, zeros, padding);
136
3.59M
                status = go_process(st, &r2, pw, true);
137
3.59M
            }
138
3.95M
        }
139
4.18M
    }
140
4.19M
    if (st->templat->release)
141
2.95M
        (*st->templat->release) (st);
142
4.19M
    return status;
143
4.19M
}
144
145
/*
146
 * Put a bitmap in the buffer, compressing if appropriate.
147
 * pcls == 0 means put the bitmap in all bands.
148
 * Return <0 if error, otherwise the compression method.
149
 * A return value of gs_error_limitcheck means that the bitmap was too big
150
 * to fit in the command reading buffer.
151
 * This won't happen if the compression_mask has allow_large_bitmap set.
152
 * Note that this leaves room for the command and initial arguments,
153
 * but doesn't fill them in.
154
 */
155
int
156
cmd_put_bits(gx_device_clist_writer * cldev, gx_clist_state * pcls,
157
  const byte * data, uint width_bits, uint height, uint raster, int op_size,
158
             int compression_mask, byte ** pdp, uint * psize)
159
26.6M
{
160
26.6M
    uint short_raster, full_raster;
161
26.6M
    uint short_size = clist_bitmap_bytes(width_bits, height,
162
26.6M
                          compression_mask & ~cmd_mask_compress_any,
163
26.6M
                          &short_raster, &full_raster);
164
26.6M
    uint uncompressed_raster;
165
26.6M
    uint uncompressed_size = clist_bitmap_bytes(width_bits, height, compression_mask,
166
26.6M
                       &uncompressed_raster, &full_raster);
167
26.6M
    uint max_size = (compression_mask & allow_large_bitmap) ? 0x7fffffff :
168
26.6M
                        data_bits_size - op_size;
169
26.6M
    gs_memory_t *mem = cldev->memory;
170
26.6M
    byte *dp;
171
26.6M
    int compress = 0;
172
26.6M
    int code;
173
174
    /*
175
     * See if compressing the bits is possible and worthwhile.
176
     * Currently we can't compress if the compressed data won't fit in
177
     * the command reading buffer, or if the decompressed data won't fit
178
     * in the buffer and decompress_elsewhere isn't set.
179
     */
180
26.6M
    if (short_size >= 50 &&
181
5.31M
        (compression_mask & ((1<<cmd_compress_rle) | (1<<cmd_compress_cfe))) != 0 &&
182
4.20M
        (uncompressed_size <= max_size ||
183
12.5k
         (compression_mask & decompress_elsewhere) != 0)
184
26.6M
        ) {
185
4.19M
        union ss_ {
186
4.19M
            stream_state ss;
187
4.19M
            stream_CFE_state cf;
188
4.19M
            stream_RLE_state rl;
189
4.19M
        } sstate;
190
4.19M
        int try_size = op_size + min(uncompressed_size, max_size);
191
192
4.19M
        *psize = try_size;
193
4.19M
        code = (pcls != 0 ?
194
4.19M
                set_cmd_put_op(&dp, cldev, pcls, 0, try_size) :
195
4.19M
                set_cmd_put_all_op(&dp, cldev, 0, try_size));
196
4.19M
        if (code < 0)
197
0
            return code;
198
4.19M
        cmd_uncount_op(0, try_size);
199
        /*
200
         * Note that we currently keep all the padding if we are
201
         * compressing.  This is ridiculous, but it's too hard to
202
         * change right now.
203
         */
204
4.19M
        if (compression_mask & (1 << cmd_compress_cfe)) {
205
            /* Try CCITTFax compression. */
206
2.95M
            clist_cfe_init(&sstate.cf,
207
2.95M
                           uncompressed_raster << 3 /*width_bits*/,
208
2.95M
                           mem);
209
2.95M
            compress = cmd_compress_cfe;
210
2.95M
        } else if (compression_mask & (1 << cmd_compress_rle)) {
211
            /* Try RLE compression. */
212
1.24M
            clist_rle_init(&sstate.rl);
213
1.24M
            compress = cmd_compress_rle;
214
1.24M
        }
215
4.19M
        if (compress) {
216
4.19M
            byte *wbase = dp + (op_size - 1);
217
4.19M
            stream_cursor_write w;
218
219
            /*
220
             * We can give up on compressing if we generate too much
221
             * output to fit in the command reading buffer, or too
222
             * much to make compression worthwhile.
223
             */
224
4.19M
            uint wmax = min(uncompressed_size, max_size);
225
4.19M
            int status;
226
227
4.19M
            w.ptr = wbase;
228
4.19M
            w.limit = w.ptr + min(wmax, short_size >> 1);
229
4.19M
            status = cmd_compress_bitmap((stream_state *) & sstate, data,
230
4.19M
                                  width_bits, /* was uncompressed_raster << 3, but this overruns. */
231
4.19M
                                         raster, height, &w);
232
4.19M
            if (status == 0) { /* Use compressed representation. */
233
2.58M
                uint wcount = w.ptr - wbase;
234
235
2.58M
                cmd_shorten_list_op(cldev,
236
2.58M
                             (pcls ? &pcls->list : cldev->band_range_list),
237
2.58M
                                    try_size - (op_size + wcount));
238
2.58M
                *psize = op_size + wcount;
239
2.58M
                goto out;
240
2.58M
            }
241
4.19M
        }
242
1.61M
        if (uncompressed_size > max_size) {
243
            /* Shorten to zero, erasing the operation altogether */
244
0
            if_debug1m('L', cldev->memory,
245
0
                       "[L]Uncompressed bits %u too large for buffer\n",
246
0
                       uncompressed_size);
247
0
            cmd_shorten_list_op(cldev,
248
0
                             (pcls ? &pcls->list : cldev->band_range_list),
249
0
                                try_size);
250
0
            return_error(gs_error_limitcheck);
251
0
        }
252
1.61M
        if (uncompressed_size != short_size) {
253
1.58M
            if_debug2m('L',cldev->memory,"[L]Shortening bits from %u to %u\n",
254
1.58M
                       try_size, op_size + short_size);
255
1.58M
            cmd_shorten_list_op(cldev,
256
1.58M
                             (pcls ? &pcls->list : cldev->band_range_list),
257
1.58M
                                try_size - (op_size + short_size));
258
1.58M
            *psize = op_size + short_size;
259
1.58M
        }
260
1.61M
        compress = 0;
261
22.4M
    } else if (uncompressed_size > max_size)
262
8.80k
        return_error(gs_error_limitcheck);
263
22.4M
    else {
264
22.4M
        *psize = op_size + short_size;
265
22.4M
        code = (pcls != 0 ?
266
22.4M
                set_cmd_put_op(&dp, cldev, pcls, 0, *psize) :
267
22.4M
                set_cmd_put_all_op(&dp, cldev, 0, *psize));
268
22.4M
        if (code < 0)
269
0
            return code;
270
22.4M
        cmd_uncount_op(0, *psize);
271
22.4M
    }
272
24.1M
    if ((compression_mask & (1 << cmd_compress_const)) &&
273
30
        (code = bytes_rectangle_is_const(data, raster, uncompressed_raster << 3, height)) >= 0) {
274
0
        cmd_shorten_list_op(cldev,
275
0
                            (pcls ? &pcls->list : cldev->band_range_list),
276
0
                            *psize - (op_size + 1));
277
0
        *psize = op_size + 1;
278
0
        dp[op_size] = code;
279
0
        compress = cmd_compress_const;
280
24.1M
    } else {
281
24.1M
        uint copy_bytes = (width_bits + 7) >> 3;
282
24.1M
        bytes_copy_rectangle_zero_padding_last_short(
283
24.1M
                             dp + op_size, short_raster, data, raster,
284
24.1M
                             copy_bytes, height);
285
24.1M
    }
286
26.6M
out:
287
26.6M
    *pdp = dp;
288
26.6M
    return compress;
289
24.1M
}
290
291
/* Add a command to set the tile size and depth. */
292
static uint
293
cmd_size_tile_params(const gx_strip_bitmap * tile, bool for_pattern)
294
6.94k
{
295
6.94k
    return 2 + (for_pattern ? cmd_size_w(tile->id) : 0) +
296
6.94k
        cmd_size_w(tile->rep_width) + cmd_size_w(tile->rep_height) +
297
6.94k
        (tile->rep_width == tile->size.x ? 0 :
298
6.94k
         cmd_size_w(tile->size.x / tile->rep_width)) +
299
6.94k
        (tile->rep_height == tile->size.y ? 0 :
300
6.94k
         cmd_size_w(tile->size.y / tile->rep_height)) +
301
6.94k
        (tile->rep_shift == 0 ? 0 : cmd_size_w(tile->rep_shift)) +
302
6.94k
        (tile->num_planes == 1 ? 0 : 1);
303
6.94k
}
304
static void
305
cmd_store_tile_params(byte * dp, const gx_strip_bitmap * tile, int depth,
306
                      uint csize, bool for_pattern, const gs_memory_t *mem)
307
6.94k
{
308
6.94k
    byte *p = dp + 2;
309
6.94k
    byte bd = cmd_depth_to_code(depth);
310
311
6.94k
    *dp = cmd_count_op(cmd_opv_set_tile_size, csize, mem);
312
6.94k
    if (for_pattern)
313
0
        p = cmd_put_w(tile->id, p);
314
6.94k
    p = cmd_put_w(tile->rep_width, p);
315
6.94k
    p = cmd_put_w(tile->rep_height, p);
316
6.94k
    if (tile->rep_width != tile->size.x) {
317
6.87k
        p = cmd_put_w(tile->size.x / tile->rep_width, p);
318
6.87k
        bd |= 0x20;
319
6.87k
    }
320
6.94k
    if (tile->rep_height != tile->size.y) {
321
2.07k
        p = cmd_put_w(tile->size.y / tile->rep_height, p);
322
2.07k
        bd |= 0x40;
323
2.07k
    }
324
6.94k
    if (tile->rep_shift != 0) {
325
0
        p = cmd_put_w(tile->rep_shift, p);
326
0
        bd |= 0x80;
327
0
    }
328
6.94k
    if (tile->num_planes != 1) {
329
0
        *p++ = (byte)tile->num_planes;
330
0
        bd |= 0x10;
331
0
    }
332
6.94k
    dp[1] = bd;
333
6.94k
}
334
335
/* Add a command to set the tile index. */
336
/* This is a relatively high-frequency operation, so we declare it `inline'. */
337
static inline int
338
cmd_put_tile_index(gx_device_clist_writer *cldev, gx_clist_state *pcls,
339
                   uint indx)
340
39.9M
{
341
39.9M
    int idelta = indx - pcls->tile_index + 8;
342
39.9M
    byte *dp;
343
39.9M
    int code;
344
345
39.9M
    if (!(idelta & ~15)) {
346
12.9M
        code = set_cmd_put_op(&dp, cldev, pcls,
347
12.9M
                              cmd_op_delta_tile_index + idelta, 1);
348
12.9M
        if (code < 0)
349
0
            return code;
350
27.0M
    } else {
351
27.0M
        code = set_cmd_put_op(&dp, cldev, pcls,
352
27.0M
                              cmd_op_set_tile_index + (indx >> 8), 2);
353
27.0M
        if (code < 0)
354
0
            return code;
355
27.0M
        dp[1] = indx & 0xff;
356
27.0M
    }
357
39.9M
    if_debug2m('L', cldev->memory, "[L]writing index=%u, offset=%lu\n",
358
39.9M
               indx, cldev->tile_table[indx].offset);
359
39.9M
    return 0;
360
39.9M
}
361
362
/* If necessary, write out data for a single color map. */
363
int
364
cmd_put_color_map(gx_device_clist_writer * cldev, cmd_map_index map_index,
365
        int comp_num, const gx_transfer_map * map, gs_id * pid)
366
551k
{
367
551k
    byte *dp;
368
551k
    int code;
369
370
551k
    if (map == 0) {
371
0
        if (pid && *pid == gs_no_id)
372
0
            return 0; /* no need to write */
373
0
        code = set_cmd_put_all_op(&dp, cldev, cmd_opv_set_misc, 3);
374
0
        if (code < 0)
375
0
            return code;
376
0
        dp[1] = cmd_set_misc_map + (cmd_map_none << 4) + map_index;
377
0
        dp[2] = comp_num;
378
0
        if (pid)
379
0
            *pid = gs_no_id;
380
551k
    } else {
381
551k
        if (pid && map->id == *pid)
382
475k
            return 0;  /* no need to write */
383
76.0k
        if (map->proc == gs_identity_transfer) {
384
12.6k
            code = set_cmd_put_all_op(&dp, cldev, cmd_opv_set_misc, 3);
385
12.6k
            if (code < 0)
386
0
                return code;
387
12.6k
            dp[1] = cmd_set_misc_map + (cmd_map_identity << 4) + map_index;
388
12.6k
            dp[2] = comp_num;
389
63.3k
        } else {
390
63.3k
            code = set_cmd_put_all_op(&dp, cldev, cmd_opv_set_misc,
391
63.3k
                                      3 + sizeof(map->values));
392
63.3k
            if (code < 0)
393
0
                return code;
394
63.3k
            dp[1] = cmd_set_misc_map + (cmd_map_other << 4) + map_index;
395
63.3k
            dp[2] = comp_num;
396
63.3k
            memcpy(dp + 3, map->values, sizeof(map->values));
397
63.3k
        }
398
76.0k
        if (pid)
399
76.0k
            *pid = map->id;
400
76.0k
    }
401
76.0k
    return 0;
402
551k
}
403
404
/* ------ Tile cache management ------ */
405
406
/* We want consecutive ids to map to consecutive hash slots if possible, */
407
/* so we can use a delta representation when setting the index. */
408
/* NB that we cannot emit 'delta' style tile indices if VM error recovery */
409
/* is in effect, since reader & writer's tile indices may get out of phase */
410
/* as a consequence of error recovery occurring. */
411
74.0M
#define tile_id_hash(id) (id)
412
3.09M
#define tile_hash_next(index) ((index) + 413)  /* arbitrary large odd # */
413
typedef struct tile_loc_s {
414
    uint index;
415
    tile_slot *tile;
416
} tile_loc;
417
418
/* Look up a tile or character in the cache.  If found, set the index and */
419
/* pointer; if not, set the index to the insertion point. */
420
static bool
421
clist_find_bits(gx_device_clist_writer * cldev, gx_bitmap_id id, tile_loc * ploc)
422
74.0M
{
423
74.0M
    uint index = tile_id_hash(id);
424
74.0M
    const tile_hash *table = cldev->tile_table;
425
74.0M
    uint mask = cldev->tile_hash_mask;
426
74.0M
    ulong offset;
427
428
74.4M
    for (; (offset = table[index &= mask].offset) != 0;
429
74.0M
         index = tile_hash_next(index)
430
74.0M
        ) {
431
61.4M
        tile_slot *tile = (tile_slot *) (cldev->data + offset);
432
433
61.4M
        if (tile->id == id) {
434
61.0M
            ploc->index = index;
435
61.0M
            ploc->tile = tile;
436
61.0M
            return true;
437
61.0M
        }
438
61.4M
    }
439
13.0M
    ploc->index = index;
440
13.0M
    return false;
441
74.0M
}
442
443
/* Delete a tile from the cache. */
444
static void
445
clist_delete_tile(gx_device_clist_writer * cldev, tile_slot * slot)
446
1.86M
{
447
1.86M
    tile_hash *table = cldev->tile_table;
448
1.86M
    uint mask = cldev->tile_hash_mask;
449
1.86M
    uint index = slot->index;
450
1.86M
    ulong offset;
451
452
1.86M
    if_debug2m('L', cldev->memory, "[L]deleting index=%u, offset=%lu\n",
453
1.86M
               index, (ulong) ((byte *) slot - cldev->data));
454
1.86M
    gx_bits_cache_free(&cldev->bits, (gx_cached_bits_head *) slot,
455
1.86M
                       cldev->cache_chunk);
456
1.86M
    table[index].offset = 0;
457
    /* Delete the entry from the hash table. */
458
    /* We'd like to move up any later entries, so that we don't need */
459
    /* a deleted mark, but it's too difficult to note this in the */
460
    /* band list, so instead, we just delete any entries that */
461
    /* would need to be moved. */
462
2.63M
    while ((offset = table[index = tile_hash_next(index) & mask].offset) != 0) {
463
767k
        tile_slot *tile = (tile_slot *) (cldev->data + offset);
464
767k
        tile_loc loc;
465
466
767k
        if (!clist_find_bits(cldev, tile->id, &loc)) { /* We didn't find it, so it should be moved into a slot */
467
            /* that we just vacated; instead, delete it. */
468
21.9k
            if_debug2m('L', cldev->memory,
469
21.9k
                       "[L]move-deleting index=%u, offset=%lu\n",
470
21.9k
                       index, offset);
471
21.9k
            gx_bits_cache_free(&cldev->bits,
472
21.9k
                             (gx_cached_bits_head *) (cldev->data + offset),
473
21.9k
                               cldev->cache_chunk);
474
21.9k
            table[index].offset = 0;
475
21.9k
        }
476
767k
    }
477
1.86M
}
478
479
/* Add a tile to the cache. */
480
/* tile->raster holds the raster for the replicated tile; */
481
/* we pass the raster of the actual data separately. */
482
static int
483
clist_add_tile(gx_device_clist_writer * cldev, const gx_strip_bitmap * tiles,
484
               uint sraster, int depth)
485
6.50M
{
486
6.50M
    uint raster = tiles->raster;
487
6.50M
    uint size_bytes = raster * tiles->size.y * tiles->num_planes;
488
6.50M
    uint tsize =
489
6.50M
    sizeof(tile_slot) + cldev->tile_band_mask_size + size_bytes;
490
6.50M
    tile_slot *slot;
491
492
6.50M
    if (cldev->bits.csize == cldev->tile_max_count) { /* Don't let the hash table get too full: delete an entry. */
493
        /* Since gx_bits_cache_alloc returns an entry to delete when */
494
        /* it fails, just force it to fail. */
495
0
        gx_bits_cache_alloc(&cldev->bits, (ulong) cldev->cache_chunk->size,
496
0
                            (gx_cached_bits_head **)&slot);
497
0
        if (slot == NULL) { /* Wrap around and retry. */
498
0
            cldev->bits.cnext = 0;
499
0
            gx_bits_cache_alloc(&cldev->bits, (ulong) cldev->cache_chunk->size,
500
0
                                (gx_cached_bits_head **)&slot);
501
#ifdef DEBUG
502
            if (slot == NULL) {
503
                lprintf("No entry to delete!\n");
504
                return_error(gs_error_Fatal);
505
            }
506
#endif
507
0
        }
508
0
        clist_delete_tile(cldev, slot);
509
0
    }
510
    /* Allocate the space for the new entry, deleting entries as needed. */
511
8.37M
    while (gx_bits_cache_alloc(&cldev->bits, (ulong) tsize, (gx_cached_bits_head **)&slot) < 0) {
512
1.87M
        if (slot == NULL) { /* Wrap around. */
513
8.59k
            if (cldev->bits.cnext == 0) { /* Too big to fit.  We should probably detect this */
514
                /* sooner, since if we get here, we've cleared the */
515
                /* cache. */
516
0
                return_error(gs_error_limitcheck);
517
0
            }
518
8.59k
            cldev->bits.cnext = 0;
519
8.59k
        } else
520
1.86M
            clist_delete_tile(cldev, slot);
521
1.87M
    }
522
    /* Fill in the entry. */
523
6.50M
    slot->head.depth = depth;
524
6.50M
    slot->raster = raster;
525
6.50M
    slot->width = tiles->rep_width;
526
6.50M
    slot->height = tiles->rep_height;
527
6.50M
    slot->shift = slot->rep_shift = tiles->rep_shift;
528
6.50M
    slot->x_reps = slot->y_reps = 1;
529
6.50M
    slot->id = tiles->id;
530
6.50M
    slot->num_planes = (byte)tiles->num_planes;
531
6.50M
    if (slot->num_planes != 1)
532
0
        depth /= slot->num_planes;
533
6.50M
    memset(ts_mask(slot), 0, cldev->tile_band_mask_size);
534
6.50M
    bytes_copy_rectangle_zero_padding(ts_bits(cldev, slot), raster,
535
6.50M
                                      tiles->data, sraster,
536
6.50M
                                      (tiles->rep_width * depth + 7) >> 3,
537
6.50M
                                      tiles->rep_height * slot->num_planes);
538
    /* Make the hash table entry. */
539
6.50M
    {
540
6.50M
        tile_loc loc;
541
542
#ifdef DEBUG
543
        if (clist_find_bits(cldev, tiles->id, &loc))
544
            lprintf1("clist_find_bits(0x%lx) should have failed!\n",
545
                     (ulong) tiles->id);
546
#else
547
6.50M
        clist_find_bits(cldev, tiles->id, &loc);  /* always fails */
548
6.50M
#endif
549
6.50M
        slot->index = loc.index;
550
6.50M
        cldev->tile_table[loc.index].offset =
551
6.50M
            (byte *) slot - cldev->data;
552
6.50M
        if_debug2m('L', cldev->memory, "[L]adding index=%u, offset=%lu\n",
553
6.50M
                   loc.index, cldev->tile_table[loc.index].offset);
554
6.50M
    }
555
6.50M
    slot->num_bands = 0;
556
6.50M
    return 0;
557
6.50M
}
558
559
/* ------ Driver procedure support ------ */
560
561
/* Change the tile parameters (size and depth). */
562
/* Currently we do this for all bands at once. */
563
static void
564
clist_new_tile_params(gx_strip_bitmap * new_tile, const gx_strip_bitmap * tiles,
565
                      int depth, const gx_device_clist_writer * cldev)
566
10.3k
{       /*
567
                                 * Adjust the replication factors.  If we can, we replicate
568
                                 * the tile in X up to 32 bytes, and then in Y up to 4 copies,
569
                                 * as long as we don't exceed a total tile size of 256 bytes,
570
                                 * or more than 255 repetitions in X or Y, or make the tile so
571
                                 * large that not all possible tiles will fit in the cache.
572
                                 * Also, don't attempt Y replication if shifting is required,
573
                                 * or if num_planes != 1.
574
                                 */
575
10.3k
#define max_tile_reps_x 255
576
10.3k
#define max_tile_bytes_x 32
577
10.3k
#define max_tile_reps_y 4
578
15.3k
#define max_tile_bytes 256
579
10.3k
    uint rep_width = tiles->rep_width;
580
10.3k
    uint rep_height = tiles->rep_height;
581
10.3k
    uint rep_width_bits;
582
10.3k
    uint tile_overhead =
583
10.3k
    sizeof(tile_slot) + cldev->tile_band_mask_size;
584
10.3k
    uint max_bytes;
585
586
10.3k
    if (tiles->num_planes != 1)
587
0
        depth /= tiles->num_planes;
588
10.3k
    rep_width_bits = rep_width * depth;
589
10.3k
    max_bytes = cldev->cache_chunk->size / (rep_width_bits * rep_height);
590
591
10.3k
    max_bytes -= min(max_bytes, tile_overhead);
592
10.3k
    if (max_bytes > max_tile_bytes)
593
5.03k
        max_bytes = max_tile_bytes;
594
10.3k
    *new_tile = *tiles;
595
10.3k
    {
596
10.3k
        uint max_bits_x = max_bytes * 8 / rep_height;
597
10.3k
        uint reps_x =
598
10.3k
        min(max_bits_x, max_tile_bytes_x * 8) / rep_width_bits;
599
10.3k
        uint reps_y;
600
601
10.3k
        while (reps_x > max_tile_reps_x)
602
0
            reps_x >>= 1;
603
10.3k
        new_tile->size.x = max(reps_x, 1) * rep_width;
604
10.3k
        new_tile->raster = bitmap_raster(new_tile->size.x * depth);
605
10.3k
        if (tiles->shift != 0 || tiles->num_planes != 1)
606
0
            reps_y = 1;
607
10.3k
        else {
608
10.3k
            reps_y = max_bytes / (new_tile->raster * rep_height);
609
10.3k
            if (reps_y > max_tile_reps_y)
610
0
                reps_y = max_tile_reps_y;
611
10.3k
            else if (reps_y < 1)
612
5.34k
                reps_y = 1;
613
10.3k
        }
614
10.3k
        new_tile->size.y = reps_y * rep_height;
615
10.3k
    }
616
10.3k
#undef max_tile_reps_x
617
10.3k
#undef max_tile_bytes_x
618
10.3k
#undef max_tile_reps_y
619
10.3k
#undef max_tile_bytes
620
10.3k
}
621
622
extern dev_proc_open_device(pattern_clist_open_device);
623
624
/* Change tile for clist_tile_rectangle. */
625
int
626
clist_change_tile(gx_device_clist_writer * cldev, gx_clist_state * pcls,
627
                  const gx_strip_bitmap * tiles, int depth)
628
1.20M
{
629
1.20M
    tile_loc loc;
630
1.20M
    int code;
631
632
1.20M
#define tile_params_differ(cldev, tiles, depth)\
633
1.20M
  ((tiles)->rep_width != (cldev)->tile_params.rep_width ||\
634
46.1k
   (tiles)->rep_height != (cldev)->tile_params.rep_height ||\
635
46.1k
   (tiles)->rep_shift != (cldev)->tile_params.rep_shift ||\
636
71.1k
   (depth) != (cldev)->tile_depth)
637
638
1.22M
  top:if (clist_find_bits(cldev, tiles->id, &loc)) { /* The bitmap is in the cache.  Check whether this band */
639
        /* knows about it. */
640
1.20M
        int band_index = pcls - cldev->states;
641
1.20M
        byte *bptr = ts_mask(loc.tile) + (band_index >> 3);
642
1.20M
        byte bmask = 1 << (band_index & 7);
643
1.20M
        bool for_pattern = gx_device_is_pattern_clist((gx_device *)cldev);
644
645
1.20M
        if (*bptr & bmask) { /* Already known.  Just set the index. */
646
1.17M
            if (pcls->tile_index == loc.index)
647
0
                return 0;
648
1.17M
            if ((code = cmd_put_tile_index(cldev, pcls, loc.index)) < 0)
649
0
                return code;
650
1.17M
        } else {
651
24.9k
            uint extra = 0;
652
653
24.9k
            if (tile_params_differ(cldev, tiles, depth) ||
654
19.6k
                for_pattern) {     /*
655
                                                 * We have a cached tile whose parameters differ from
656
                                                 * the current ones.  Because of the way tile IDs are
657
                                                 * managed, this is currently only possible when mixing
658
                                                 * Patterns and halftones, but if we didn't generate new
659
                                                 * IDs each time the main halftone cache needed to be
660
                                                 * refreshed, this could also happen simply from
661
                                                 * switching screens.
662
                                                 */
663
5.33k
                int band;
664
665
5.33k
                clist_new_tile_params(&cldev->tile_params, tiles, depth,
666
5.33k
                                      cldev);
667
5.33k
                cldev->tile_depth = depth;
668
                /* No band knows about the new parameters. */
669
5.33k
                for (band = cldev->tile_known_min;
670
9.07k
                     band <= cldev->tile_known_max;
671
5.33k
                     ++band
672
5.33k
                    )
673
3.74k
                    cldev->states[band].known &= ~tile_params_known;
674
5.33k
                cldev->tile_known_min = cldev->nbands;
675
5.33k
                cldev->tile_known_max = -1;
676
5.33k
                }
677
24.9k
            if (!(pcls->known & tile_params_known)) { /* We're going to have to write the tile parameters. */
678
6.94k
                extra = cmd_size_tile_params(&cldev->tile_params, for_pattern);
679
6.94k
            } {      /*
680
                                 * This band doesn't know this tile yet, so output the
681
                                 * bits.  Note that the offset we write is the one used by
682
                                 * the reading phase, not the writing phase.  Note also
683
                                 * that the size of the cached and written tile may differ
684
                                 * from that of the client's tile.  Finally, note that
685
                                 * this tile's size parameters are guaranteed to be
686
                                 * compatible with those stored in the device
687
                                 * (cldev->tile_params).
688
                                 */
689
24.9k
                ulong offset = (byte *) loc.tile - cldev->cache_chunk->data;
690
24.9k
                uint rsize =
691
24.9k
                    extra + 1 + cmd_size_w(loc.index) + cmd_size_w(offset);
692
24.9k
                byte *dp;
693
24.9k
                uint csize;
694
24.9k
                int code;
695
24.9k
                int pdepth = depth;
696
24.9k
                if (tiles->num_planes != 1)
697
0
                    pdepth /= tiles->num_planes;
698
699
                /* put the bits, but don't restrict to a single buffer */
700
24.9k
                code = cmd_put_bits(cldev, pcls, ts_bits(cldev, loc.tile),
701
24.9k
                                    tiles->rep_width * pdepth,
702
24.9k
                                    tiles->rep_height * tiles->num_planes,
703
24.9k
                                    loc.tile->raster, rsize,
704
24.9k
                                    allow_large_bitmap |
705
24.9k
                                        (cldev->tile_params.size.x > tiles->rep_width ?
706
24.7k
                                             decompress_elsewhere | decompress_spread :
707
24.9k
                                             decompress_elsewhere),
708
24.9k
                                    &dp, &csize);
709
710
24.9k
                if (code < 0)
711
0
                    return code;
712
24.9k
                if (extra) { /* Write the tile parameters before writing the bits. */
713
6.94k
                    if_debug1m('L', cldev->memory,
714
6.94k
                               "[L] fake end_run: really set_tile_size[%d]\n", extra);
715
6.94k
                    cmd_store_tile_params(dp, &cldev->tile_params, depth,
716
6.94k
                                          extra, for_pattern, cldev->memory);
717
6.94k
                    dp += extra;
718
                    /* This band now knows the parameters. */
719
6.94k
                    pcls->known |= tile_params_known;
720
6.94k
                    if (band_index < cldev->tile_known_min)
721
5.44k
                        cldev->tile_known_min = band_index;
722
6.94k
                    if (band_index > cldev->tile_known_max)
723
6.57k
                        cldev->tile_known_max = band_index;
724
6.94k
                }
725
24.9k
                if_debug1m('L', cldev->memory,
726
24.9k
                           "[L] fake end_run: really set_tile_bits[%d]\n", csize-extra);
727
24.9k
                *dp = cmd_count_op(cmd_opv_set_tile_bits, csize - extra, cldev->memory);
728
24.9k
                dp++;
729
24.9k
                dp = cmd_put_w(loc.index, dp);
730
24.9k
                cmd_put_w(offset, dp);
731
24.9k
                *bptr |= bmask;
732
24.9k
                loc.tile->num_bands++;
733
24.9k
            }
734
24.9k
        }
735
1.20M
        pcls->tile_index = loc.index;
736
1.20M
        pcls->tile_id = loc.tile->id;
737
1.20M
        return 0;
738
1.20M
    }
739
    /* The tile is not in the cache, add it. */
740
21.2k
    {
741
21.2k
        gx_strip_bitmap new_tile;
742
21.2k
        gx_strip_bitmap *ptile;
743
744
        /* Ensure that the tile size is compatible. */
745
21.2k
        if (tile_params_differ(cldev, tiles, depth)) { /* We'll reset cldev->tile_params when we write the bits. */
746
4.98k
            clist_new_tile_params(&new_tile, tiles, depth, cldev);
747
4.98k
            ptile = &new_tile;
748
16.2k
        } else {
749
16.2k
            cldev->tile_params.id = tiles->id;
750
16.2k
            cldev->tile_params.data = tiles->data;
751
16.2k
            ptile = &cldev->tile_params;
752
16.2k
        }
753
21.2k
        code = clist_add_tile(cldev, ptile, tiles->raster, depth);
754
21.2k
        if (code < 0)
755
0
            return code;
756
21.2k
    }
757
21.2k
    goto top;
758
21.2k
#undef tile_params_differ
759
21.2k
}
760
761
/* Change "tile" for clist_copy_*.  tiles->[rep_]shift must be zero. */
762
int
763
clist_change_bits(gx_device_clist_writer * cldev, gx_clist_state * pcls,
764
                  const gx_strip_bitmap * tiles, int depth)
765
59.0M
{
766
59.0M
    tile_loc loc;
767
59.0M
    int code;
768
59.0M
    uint band_index = pcls - cldev->states;
769
59.0M
    byte bmask = 1 << (band_index & 7);
770
59.0M
    byte *bptr;
771
772
65.5M
    while (!clist_find_bits(cldev, tiles->id, &loc)) {
773
        /* The tile is not in the cache. */
774
6.47M
        code = clist_add_tile(cldev, tiles, tiles->raster, depth);
775
6.47M
        if (code < 0)
776
0
            return code;
777
6.47M
    }
778
779
    /* The bitmap is in the cache.  Check whether this band */
780
    /* knows about it. */
781
59.0M
    bptr = ts_mask(loc.tile) + (band_index >> 3);
782
783
59.0M
    if (*bptr & bmask) { /* Already known.  Just set the index. */
784
38.7M
        if (pcls->tile_index == loc.index)
785
0
            return 0;
786
38.7M
        cmd_put_tile_index(cldev, pcls, loc.index);
787
38.7M
    } else {   /* Not known yet.  Output the bits. */
788
        /* Note that the offset we write is the one used by */
789
        /* the reading phase, not the writing phase. */
790
20.2M
        ulong offset = (byte *) loc.tile - cldev->cache_chunk->data;
791
20.2M
        uint rsize = 2 + cmd_size_w(loc.tile->width) +
792
20.2M
                     cmd_size_w(loc.tile->height) +
793
20.2M
                     (loc.tile->num_planes > 1 ? 1 : 0) +
794
20.2M
                     cmd_size_w(loc.index) +
795
20.2M
                     cmd_size_w(offset);
796
20.2M
        byte *dp;
797
20.2M
        uint csize;
798
20.2M
        gx_clist_state *bit_pcls = pcls;
799
20.2M
        int pdepth = depth;
800
801
20.2M
        if (tiles->num_planes != 1)
802
0
            pdepth /= loc.tile->num_planes;
803
20.2M
        if (loc.tile->num_bands == CHAR_ALL_BANDS_COUNT)
804
0
            bit_pcls = NULL;
805
        /* put the bits, but don't restrict to a single buffer */
806
20.2M
        code = cmd_put_bits(cldev, bit_pcls, ts_bits(cldev, loc.tile),
807
20.2M
                            loc.tile->width * pdepth,
808
20.2M
                            loc.tile->height * loc.tile->num_planes, loc.tile->raster,
809
20.2M
                            rsize,
810
20.2M
                            decompress_elsewhere |
811
20.2M
                                (cldev->target->BLS_force_memory ? (1 << cmd_compress_cfe) : 0),
812
20.2M
                            &dp, &csize);
813
814
20.2M
        if (code < 0)
815
94
            return code;
816
20.2M
        if_debug1m('L', cldev->memory,
817
20.2M
                   "[L] fake end_run: really set_bits[%d]\n", csize);
818
20.2M
        *dp = cmd_count_op(loc.tile->num_planes > 1 ? cmd_opv_set_bits_planar : cmd_opv_set_bits,
819
20.2M
                           csize, cldev->memory);
820
20.2M
        dp[1] = (depth << 2) + code;
821
20.2M
        dp += 2;
822
20.2M
        dp = cmd_put_w(loc.tile->width, dp);
823
20.2M
        dp = cmd_put_w(loc.tile->height, dp);
824
20.2M
        if (loc.tile->num_planes > 1)
825
0
            *dp++ = loc.tile->num_planes;
826
20.2M
        dp = cmd_put_w(loc.index, dp);
827
20.2M
        cmd_put_w(offset, dp);
828
20.2M
        if_debug7m('L', cldev->memory, " compress=%d depth=%d size=(%d,%d) planes=%d index=%d offset=%ld\n",
829
20.2M
                   code, depth, loc.tile->width, loc.tile->height, loc.tile->num_planes, loc.index, offset);
830
20.2M
        if (bit_pcls == NULL) {
831
0
            memset(ts_mask(loc.tile), 0xff,
832
0
                   cldev->tile_band_mask_size);
833
0
            loc.tile->num_bands = cldev->nbands;
834
20.2M
        } else {
835
20.2M
            *bptr |= bmask;
836
20.2M
            loc.tile->num_bands++;
837
20.2M
        }
838
20.2M
    }
839
59.0M
    pcls->tile_index = loc.index;
840
59.0M
    pcls->tile_id = loc.tile->id;
841
59.0M
    return 0;
842
59.0M
}