Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gdevflp.c
Line
Count
Source (jump to first uncovered line)
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
/* Device for first/last page handling device */
17
/* This device is the first 'subclassing' device; the intention of subclassing
18
 * is to allow us to develop a 'chain' or 'pipeline' of devices, each of which
19
 * can process some aspect of the graphics methods before passing them on to the
20
 * next device in the chain.
21
 *
22
 * This device's purpose is to implement the 'FirstPage' and 'LastPage' parameters
23
 * in Ghostscript. Initially only implemented in the PDF interpreter this functionality
24
 * has been shifted internally so that it can be implemented in all the interpreters.
25
 * The approach is pretty simple, we modify gdevprn.c and gdevvec.c so that if -dFirstPage
26
 * or -dLastPage is defined the device in question is subclassed and this device inserted.
27
 * This device then 'black hole's any graphics operations until we reach 'FirstPage'. We then
28
 * allow graphics to pass to the device until we reach the end of 'LastPage' at which time we
29
 * discard operations again until we reach the end, and close the device.
30
 */
31
32
#include "math_.h"
33
#include "string_.h"    /* for strlen */
34
#include "memory_.h"
35
#include "gx.h"
36
#include "gserrors.h"
37
#include "gsparam.h"
38
#include "gxdevice.h"
39
#include "gsdevice.h"   /* requires gsmatrix.h */
40
#include "gxdcolor.h"   /* for gx_device_black/white */
41
#include "gxiparam.h"   /* for image source size */
42
#include "gxgstate.h"
43
#include "gxpaint.h"
44
#include "gxpath.h"
45
#include "gxcpath.h"
46
#include "gxcmap.h"         /* color mapping procs */
47
#include "gsstype.h"
48
#include "gdevprn.h"
49
#include "gdevp14.h"        /* Needed to patch up the procs after compositor creation */
50
#include "gximage.h"        /* For gx_image_enum */
51
#include "gdevsclass.h"
52
#include "gdevflp.h"
53
#include "pagelist.h"
54
#include <stdlib.h>
55
56
/* GC descriptor */
57
public_st_device_flp();
58
/* we need text and image enumerators, because of the crazy way that text and images work */
59
private_st_flp_text_enum();
60
61
/* Device procedures, we need quite a lot of them */
62
static dev_proc_output_page(flp_output_page);
63
static dev_proc_close_device(flp_close_device);
64
static dev_proc_fill_rectangle(flp_fill_rectangle);
65
static dev_proc_copy_mono(flp_copy_mono);
66
static dev_proc_copy_color(flp_copy_color);
67
static dev_proc_get_bits_rectangle(flp_get_bits_rectangle);
68
static dev_proc_get_params(flp_put_params);
69
static dev_proc_get_alpha_bits(flp_get_alpha_bits);
70
static dev_proc_copy_alpha(flp_copy_alpha);
71
static dev_proc_fill_path(flp_fill_path);
72
static dev_proc_stroke_path(flp_stroke_path);
73
static dev_proc_fill_mask(flp_fill_mask);
74
static dev_proc_fill_trapezoid(flp_fill_trapezoid);
75
static dev_proc_fill_parallelogram(flp_fill_parallelogram);
76
static dev_proc_fill_triangle(flp_fill_triangle);
77
static dev_proc_draw_thin_line(flp_draw_thin_line);
78
static dev_proc_strip_tile_rectangle(flp_strip_tile_rectangle);
79
static dev_proc_begin_typed_image(flp_begin_typed_image);
80
static dev_proc_get_bits_rectangle(flp_get_bits_rectangle);
81
static dev_proc_composite(flp_composite);
82
static dev_proc_text_begin(flp_text_begin);
83
static dev_proc_begin_transparency_group(flp_begin_transparency_group);
84
static dev_proc_end_transparency_group(flp_end_transparency_group);
85
static dev_proc_begin_transparency_mask(flp_begin_transparency_mask);
86
static dev_proc_end_transparency_mask(flp_end_transparency_mask);
87
static dev_proc_discard_transparency_layer(flp_discard_transparency_layer);
88
static dev_proc_fill_rectangle_hl_color(flp_fill_rectangle_hl_color);
89
static dev_proc_fill_linear_color_scanline(flp_fill_linear_color_scanline);
90
static dev_proc_fill_linear_color_trapezoid(flp_fill_linear_color_trapezoid);
91
static dev_proc_fill_linear_color_triangle(flp_fill_linear_color_triangle);
92
static dev_proc_fillpage(flp_fillpage);
93
static dev_proc_push_transparency_state(flp_push_transparency_state);
94
static dev_proc_pop_transparency_state(flp_pop_transparency_state);
95
static dev_proc_put_image(flp_put_image);
96
static dev_proc_copy_planes(flp_copy_planes);
97
static dev_proc_strip_copy_rop2(flp_strip_copy_rop2);
98
static dev_proc_strip_tile_rect_devn(flp_strip_tile_rect_devn);
99
static dev_proc_copy_alpha_hl_color(flp_copy_alpha_hl_color);
100
static dev_proc_process_page(flp_process_page);
101
static dev_proc_transform_pixel_region(flp_transform_pixel_region);
102
static dev_proc_fill_stroke_path(flp_fill_stroke_path);
103
static dev_proc_initialize_device_procs(flp_initialize_device_procs);
104
105
/* The device prototype */
106
#define MAX_COORD (max_int_in_fixed - 1000)
107
#define MAX_RESOLUTION 4000
108
109
#define public_st_flp_device()  /* in gsdevice.c */\
110
  gs_public_st_complex_only(st_flp_device, gx_device, "first_lastpage",\
111
    0, flp_enum_ptrs, flp_reloc_ptrs, default_subclass_finalize)
112
113
static
114
0
ENUM_PTRS_WITH(flp_enum_ptrs, gx_device *dev);
115
0
return 0; /* default case */
116
0
case 0:ENUM_RETURN(gx_device_enum_ptr(dev->parent));
117
0
case 1:ENUM_RETURN(gx_device_enum_ptr(dev->child));
118
0
ENUM_PTRS_END
119
0
static RELOC_PTRS_WITH(flp_reloc_ptrs, gx_device *dev)
120
0
{
121
0
    dev->parent = gx_device_reloc_ptr(dev->parent, gcst);
122
0
    dev->child = gx_device_reloc_ptr(dev->child, gcst);
123
0
}RELOC_PTRS_END
124
125
public_st_flp_device();
126
127
const
128
gx_device_flp gs_flp_device =
129
{
130
    std_device_dci_type_body_sc(gx_device_flp, flp_initialize_device_procs,
131
                        "first_lastpage", &st_flp_device,
132
                        MAX_COORD, MAX_COORD,
133
                        MAX_RESOLUTION, MAX_RESOLUTION,
134
                        1, 8, 255, 0, 256, 1, NULL, NULL, NULL)
135
};
136
137
#undef MAX_COORD
138
#undef MAX_RESOLUTION
139
140
static int ParsePageList(gx_device *dev, first_last_subclass_data *psubclass_data, char *PageList)
141
0
{
142
0
    return pagelist_parse_to_array(PageList, dev->memory->non_gc_memory, 0x7fffffff,
143
0
                                   &(psubclass_data->page_range_array));
144
0
}
145
146
static int SkipPage(gx_device *dev)
147
0
{
148
0
    first_last_subclass_data *psubclass_data = dev->subclass_data;
149
0
    int code;
150
151
    /* If we're disabled, don't skip any pages, and don't bother parsing the PageList */
152
0
    if (dev->DisablePageHandler)
153
0
        return 0;
154
155
    /* If we haven't parsed any extant PageList, do it now */
156
0
    if (dev->PageList && psubclass_data->page_range_array == NULL) {
157
0
        code = ParsePageList(dev, psubclass_data, dev->PageList->Pages);
158
0
        if (code < 0) {
159
0
            emprintf1(dev->memory, "*** Invalid PageList=%s ***\n", dev->PageList->Pages);
160
0
            return code;
161
0
        }
162
0
    }
163
164
    /* SkipPage can only handle PageList that moves forward */
165
0
    if (psubclass_data->page_range_array != NULL &&
166
0
        pagelist_test_ordered(psubclass_data->page_range_array) == false) {
167
0
        emprintf(dev->memory, "*** Bad PageList: Must be increasing order. ***\n");
168
0
        return gs_error_rangecheck;
169
0
    }
170
171
0
    if (psubclass_data->page_range_array != NULL) {
172
        /* PageCount is 0 based, page_range_array starts at page 1 */
173
0
        return pagelist_test_printed(psubclass_data->page_range_array, psubclass_data->PageCount + 1) == false;
174
0
    } else {
175
0
        if (psubclass_data->PageCount >= dev->FirstPage - 1)
176
0
            if (!dev->LastPage || psubclass_data->PageCount <= dev->LastPage - 1)
177
0
                return 0;
178
0
    }
179
0
    return 1;
180
0
}
181
182
int flp_output_page(gx_device *dev, int num_copies, int flush)
183
0
{
184
0
    int code = 0;
185
186
0
    first_last_subclass_data *psubclass_data = dev->subclass_data;
187
188
0
    if (!SkipPage(dev))
189
0
        code =  default_subclass_output_page(dev, num_copies, flush);
190
191
0
    psubclass_data->PageCount++;
192
193
0
    return code;
194
0
}
195
196
int flp_close_device(gx_device *dev)
197
0
{
198
0
    first_last_subclass_data *psubclass_data = dev->subclass_data;
199
200
0
    if (psubclass_data->page_range_array != NULL)
201
0
    {
202
0
        pagelist_free_range_array(dev->memory->non_gc_memory, psubclass_data->page_range_array);
203
0
        psubclass_data->page_range_array = NULL;
204
0
    }
205
206
0
    return default_subclass_close_device(dev);
207
0
}
208
209
int flp_fill_rectangle(gx_device *dev, int x, int y, int width, int height, gx_color_index color)
210
0
{
211
0
    int code = SkipPage(dev);
212
213
0
    if (code < 0)
214
0
        return code;
215
0
    if (!code)
216
0
        return default_subclass_fill_rectangle(dev, x, y, width, height, color);
217
218
0
    return 0;
219
0
}
220
221
int flp_copy_mono(gx_device *dev, const byte *data, int data_x, int raster, gx_bitmap_id id,
222
    int x, int y, int width, int height,
223
    gx_color_index color0, gx_color_index color1)
224
0
{
225
0
    int code = SkipPage(dev);
226
227
0
    if (code < 0)
228
0
        return code;
229
0
    if (!code)
230
0
        return default_subclass_copy_mono(dev, data, data_x, raster, id, x, y, width, height, color0, color1);
231
232
0
    return 0;
233
0
}
234
235
int flp_copy_color(gx_device *dev, const byte *data, int data_x, int raster, gx_bitmap_id id,\
236
    int x, int y, int width, int height)
237
0
{
238
0
    int code = SkipPage(dev);
239
240
0
    if (code < 0)
241
0
        return code;
242
0
    if (!code)
243
0
        return default_subclass_copy_color(dev, data, data_x, raster, id, x, y, width, height);
244
245
0
    return 0;
246
0
}
247
248
static void
249
flp_rc_free_pages_list(gs_memory_t * mem, void *ptr_in, client_name_t cname)
250
0
{
251
0
    gdev_pagelist *PageList = (gdev_pagelist *)ptr_in;
252
253
0
    if (PageList->rc.ref_count <= 1) {
254
0
        gs_free(mem->non_gc_memory, PageList->Pages, 1, strlen(PageList->Pages), "free page list");
255
0
        gs_free(mem->non_gc_memory, PageList, 1, sizeof(gdev_pagelist), "free structure to hold page list");
256
0
    }
257
0
}
258
259
int
260
flp_put_params(gx_device * dev, gs_param_list * plist)
261
0
{
262
0
    bool temp_bool = false;
263
0
    int code, ecode = 0;
264
0
    gs_param_string pagelist;
265
266
0
    code = param_read_bool(plist, "DisablePageHandler", &temp_bool);
267
0
    if (code < 0)
268
0
        ecode = code;
269
0
    if (code == 0) {
270
0
        dev->DisablePageHandler = temp_bool;
271
0
        if (dev->DisablePageHandler == false) {
272
0
            first_last_subclass_data *psubclass_data = dev->subclass_data;
273
274
0
            psubclass_data->PageCount = 0;
275
0
            psubclass_data->page_range_array = NULL;
276
0
        }
277
0
    }
278
279
0
    if (dev->DisablePageHandler == false) {
280
0
        code = param_read_int(plist, "FirstPage", &dev->FirstPage);
281
0
        if (code < 0)
282
0
            ecode = code;
283
0
        if (code == 0) {
284
0
            first_last_subclass_data *psubclass_data = dev->subclass_data;
285
286
0
            dev->DisablePageHandler = false;
287
0
            psubclass_data->PageCount = 0;
288
0
            psubclass_data->page_range_array = NULL;
289
0
            if (dev->PageList) {
290
0
                rc_decrement(dev->PageList, "flp_put_params");
291
0
                dev->PageList = NULL;
292
0
            }
293
0
            if (psubclass_data->page_range_array != NULL) {
294
0
                pagelist_free_range_array(dev->memory->non_gc_memory, psubclass_data->page_range_array);
295
0
                psubclass_data->page_range_array = NULL;
296
0
            }
297
0
        }
298
299
0
        code = param_read_int(plist,  "LastPage", &dev->LastPage);
300
0
        if (code < 0)
301
0
            ecode = code;
302
0
        if (code == 0) {
303
0
            first_last_subclass_data *psubclass_data = dev->subclass_data;
304
305
0
            dev->DisablePageHandler = false;
306
0
            psubclass_data->PageCount = 0;
307
0
            psubclass_data->page_range_array = NULL;
308
0
            if (dev->PageList) {
309
0
                rc_decrement(dev->PageList, "flp_put_params");
310
0
                dev->PageList = NULL;
311
0
            }
312
0
            if (psubclass_data->page_range_array != NULL) {
313
0
                pagelist_free_range_array(dev->memory->non_gc_memory, psubclass_data->page_range_array);
314
0
                psubclass_data->page_range_array = NULL;
315
0
            }
316
0
        }
317
318
0
        code = param_read_string(plist, "PageList", &pagelist);
319
0
        if (code < 0)
320
0
            ecode = code;
321
322
0
        if (code == 0 && pagelist.size > 0) {
323
0
            first_last_subclass_data *psubclass_data = dev->subclass_data;
324
325
0
            if (dev->PageList)
326
0
                rc_decrement(dev->PageList, "flp_put_params");
327
328
0
            if (psubclass_data->page_range_array != NULL) {
329
0
                pagelist_free_range_array(dev->memory->non_gc_memory, psubclass_data->page_range_array);
330
0
                psubclass_data->page_range_array = NULL;
331
0
            }
332
333
0
            dev->PageList = (gdev_pagelist *)gs_alloc_bytes(dev->memory->non_gc_memory, sizeof(gdev_pagelist), "structure to hold page list");
334
0
            if (!dev->PageList)
335
0
                return gs_note_error(gs_error_VMerror);
336
0
            dev->PageList->Pages = (void *)gs_alloc_bytes(dev->memory->non_gc_memory, pagelist.size + 1, "String to hold page list");
337
0
            if (!dev->PageList->Pages){
338
0
                gs_free(dev->memory->non_gc_memory, dev->PageList, 1, sizeof(gdev_pagelist), "free structure to hold page list");
339
0
                dev->PageList = 0;
340
0
                return gs_note_error(gs_error_VMerror);
341
0
            }
342
0
            memset(dev->PageList->Pages, 0x00, pagelist.size + 1);
343
0
            memcpy(dev->PageList->Pages, pagelist.data, pagelist.size);
344
0
            rc_init_free(dev->PageList, dev->memory->non_gc_memory, 1, flp_rc_free_pages_list);
345
0
            psubclass_data->page_range_array = NULL;
346
0
            dev->DisablePageHandler = false;
347
0
            psubclass_data->PageCount = 0;
348
0
            psubclass_data->page_range_array = NULL;
349
0
        }
350
0
    }
351
0
    code = default_subclass_put_params(dev, plist);
352
353
0
    if (code < 0)
354
0
        return code;
355
356
0
    if (ecode < 0)
357
0
        code = ecode;
358
359
0
    return code;
360
0
}
361
362
int flp_get_alpha_bits(gx_device *dev, graphics_object_type type)
363
0
{
364
0
    int code = SkipPage(dev);
365
366
0
    if (code < 0)
367
0
        return code;
368
0
    if (!code)
369
0
        return default_subclass_get_alpha_bits(dev, type);
370
371
0
    return 0;
372
0
}
373
374
int flp_copy_alpha(gx_device *dev, const byte *data, int data_x,
375
    int raster, gx_bitmap_id id, int x, int y, int width, int height,
376
    gx_color_index color, int depth)
377
0
{
378
0
    int code = SkipPage(dev);
379
380
0
    if (code < 0)
381
0
        return code;
382
0
    if (!code)
383
0
        return default_subclass_copy_alpha(dev, data, data_x, raster, id, x, y, width, height, color, depth);
384
385
0
    return 0;
386
0
}
387
388
int flp_fill_path(gx_device *dev, const gs_gstate *pgs, gx_path *ppath,
389
    const gx_fill_params *params,
390
    const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
391
0
{
392
0
    int code = SkipPage(dev);
393
394
0
    if (code < 0)
395
0
        return code;
396
0
    if (!code)
397
0
        return default_subclass_fill_path(dev, pgs, ppath, params, pdcolor, pcpath);
398
399
0
    return 0;
400
0
}
401
402
int flp_stroke_path(gx_device *dev, const gs_gstate *pgs, gx_path *ppath,
403
    const gx_stroke_params *params,
404
    const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
405
0
{
406
0
    int code = SkipPage(dev);
407
408
0
    if (code < 0)
409
0
        return code;
410
0
    if (!code)
411
0
        return default_subclass_stroke_path(dev, pgs, ppath, params, pdcolor, pcpath);
412
413
0
    return 0;
414
0
}
415
416
int flp_fill_mask(gx_device *dev, const byte *data, int data_x, int raster, gx_bitmap_id id,
417
    int x, int y, int width, int height,
418
    const gx_drawing_color *pdcolor, int depth,
419
    gs_logical_operation_t lop, const gx_clip_path *pcpath)
420
0
{
421
0
    int code = SkipPage(dev);
422
423
0
    if (code < 0)
424
0
        return code;
425
0
    if (!code)
426
0
        return default_subclass_fill_mask(dev, data, data_x, raster, id, x, y, width, height, pdcolor, depth, lop, pcpath);
427
428
0
    return 0;
429
0
}
430
431
int flp_fill_trapezoid(gx_device *dev, const gs_fixed_edge *left, const gs_fixed_edge *right,
432
    fixed ybot, fixed ytop, bool swap_axes,
433
    const gx_drawing_color *pdcolor, gs_logical_operation_t lop)
434
0
{
435
0
    int code = SkipPage(dev);
436
437
0
    if (code < 0)
438
0
        return code;
439
0
    if (!code)
440
0
        return default_subclass_fill_trapezoid(dev, left, right, ybot, ytop, swap_axes, pdcolor, lop);
441
442
0
    return 0;
443
0
}
444
445
int flp_fill_parallelogram(gx_device *dev, fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
446
    const gx_drawing_color *pdcolor, gs_logical_operation_t lop)
447
0
{
448
0
    int code = SkipPage(dev);
449
450
0
    if (code < 0)
451
0
        return code;
452
0
    if (!code)
453
0
        return default_subclass_fill_parallelogram(dev, px, py, ax, ay, bx, by, pdcolor, lop);
454
455
0
    return 0;
456
0
}
457
458
int flp_fill_triangle(gx_device *dev, fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
459
    const gx_drawing_color *pdcolor, gs_logical_operation_t lop)
460
0
{
461
0
    int code = SkipPage(dev);
462
463
0
    if (code < 0)
464
0
        return code;
465
0
    if (!code)
466
0
        return default_subclass_fill_triangle(dev, px, py, ax, ay, bx, by, pdcolor, lop);
467
468
0
    return 0;
469
0
}
470
471
int flp_draw_thin_line(gx_device *dev, fixed fx0, fixed fy0, fixed fx1, fixed fy1,
472
    const gx_drawing_color *pdcolor, gs_logical_operation_t lop,
473
    fixed adjustx, fixed adjusty)
474
0
{
475
0
    int code = SkipPage(dev);
476
477
0
    if (code < 0)
478
0
        return code;
479
0
    if (!code)
480
0
        return default_subclass_draw_thin_line(dev, fx0, fy0, fx1, fy1, pdcolor, lop, adjustx, adjusty);
481
482
0
    return 0;
483
0
}
484
485
int flp_strip_tile_rectangle(gx_device *dev, const gx_strip_bitmap *tiles, int x, int y, int width, int height,
486
    gx_color_index color0, gx_color_index color1,
487
    int phase_x, int phase_y)
488
0
{
489
0
    int code = SkipPage(dev);
490
491
0
    if (code < 0)
492
0
        return code;
493
0
    if (!code)
494
0
        return default_subclass_strip_tile_rectangle(dev, tiles, x, y, width, height, color0, color1, phase_x, phase_y);
495
496
0
    return 0;
497
0
}
498
499
typedef struct flp_image_enum_s {
500
    gx_image_enum_common;
501
    int y;
502
    int height;
503
} flp_image_enum;
504
gs_private_st_composite(st_flp_image_enum, flp_image_enum, "flp_image_enum",
505
flp_image_enum_enum_ptrs, flp_image_enum_reloc_ptrs);
506
507
0
static ENUM_PTRS_WITH(flp_image_enum_enum_ptrs, flp_image_enum *pie)
508
0
    (void)pie; /* Silence unused var warning */
509
0
    return ENUM_USING_PREFIX(st_gx_image_enum_common, 0);
510
0
ENUM_PTRS_END
511
0
static RELOC_PTRS_WITH(flp_image_enum_reloc_ptrs, flp_image_enum *pie)
512
0
{
513
0
    (void)pie; /* Silence unused var warning */
514
0
    RELOC_USING(st_gx_image_enum_common, vptr, size);
515
0
}
516
0
RELOC_PTRS_END
517
518
static int
519
flp_image_plane_data(gx_image_enum_common_t * info,
520
                     const gx_image_plane_t * planes, int height,
521
                     int *rows_used)
522
0
{
523
0
    flp_image_enum *pie = (flp_image_enum *)info;
524
525
0
    pie->y += height;
526
0
    *rows_used = height;
527
528
0
    if (pie->y < pie->height)
529
0
        return 0;
530
0
    return 1;
531
0
}
532
533
static int
534
flp_image_end_image(gx_image_enum_common_t * info, bool draw_last)
535
0
{
536
0
    gs_free_object(info->memory, info, "flp_end_image");
537
0
    return 0;
538
0
}
539
540
static const gx_image_enum_procs_t flp_image_enum_procs = {
541
    flp_image_plane_data,
542
    flp_image_end_image
543
};
544
545
int flp_begin_typed_image(gx_device *dev, const gs_gstate *pgs, const gs_matrix *pmat,
546
    const gs_image_common_t *pic, const gs_int_rect *prect,
547
    const gx_drawing_color *pdcolor, const gx_clip_path *pcpath,
548
    gs_memory_t *memory, gx_image_enum_common_t **pinfo)
549
0
{
550
0
    flp_image_enum *pie;
551
0
    const gs_pixel_image_t *pim = (const gs_pixel_image_t *)pic;
552
0
    int num_components;
553
0
    int code = SkipPage(dev);
554
555
0
    if (code < 0)
556
0
        return code;
557
0
    if (!code)
558
0
        return default_subclass_begin_typed_image(dev, pgs, pmat, pic, prect, pdcolor, pcpath, memory, pinfo);
559
560
0
    if (pic->type->index == 1) {
561
0
        const gs_image_t *pim1 = (const gs_image_t *)pic;
562
563
0
        if (pim1->ImageMask)
564
0
            num_components = 1;
565
0
        else
566
0
            num_components = gs_color_space_num_components(pim->ColorSpace);
567
0
    } else {
568
0
        num_components = gs_color_space_num_components(pim->ColorSpace);
569
0
    }
570
571
0
    pie = gs_alloc_struct(memory, flp_image_enum, &st_flp_image_enum,
572
0
                        "flp_begin_image");
573
0
    if (pie == 0)
574
0
        return_error(gs_error_VMerror);
575
0
    memset(pie, 0, sizeof(*pie)); /* cleanup entirely for GC to work in all cases. */
576
0
    *pinfo = (gx_image_enum_common_t *) pie;
577
0
    gx_image_enum_common_init(*pinfo, (const gs_data_image_t *) pim, &flp_image_enum_procs,
578
0
                        (gx_device *)dev, num_components, pim->format);
579
0
    pie->memory = memory;
580
0
    pie->skipping = true;
581
0
    pie->height = pim->Height;
582
0
    pie->y = 0;
583
584
0
    return 0;
585
0
}
586
587
int flp_get_bits_rectangle(gx_device *dev, const gs_int_rect *prect,
588
    gs_get_bits_params_t *params)
589
0
{
590
0
    int code = SkipPage(dev);
591
592
0
    if (code < 0)
593
0
        return code;
594
0
    if (!code)
595
0
        return default_subclass_get_bits_rectangle(dev, prect, params);
596
597
0
    return gx_default_get_bits_rectangle(dev->child, prect, params);
598
0
}
599
600
int flp_composite(gx_device *dev, gx_device **pcdev, const gs_composite_t *pcte,
601
    gs_gstate *pgs, gs_memory_t *memory, gx_device *cdev)
602
0
{
603
0
    int code = SkipPage(dev);
604
605
    /* The returned pointer 'pcdev' is a signal to the caller, if its not the same as the current
606
     * device in the graphics state, then it gets set as the current device (basically if its not the
607
     * same its a signal that we want to push a new compositor device to the head). So here we start
608
     * by making sure that its set to the one in the graphics state. If the child device wants a
609
     * compositor it will overwrite this value.
610
     */
611
0
    *pcdev = pgs->device;
612
613
0
    if (code < 0)
614
0
        return code;
615
0
    if (!code)
616
0
        return default_subclass_composite(dev, pcdev, pcte, pgs, memory, cdev);
617
618
0
    return 0;
619
0
}
620
621
/* Text processing (like images) works differently to other device
622
 * methods. Instead of the interpreter calling a device method, only
623
 * the 'begin' method is called, this creates a text enumerator which
624
 * it fills in (in part with the routines for processing text) and returns
625
 * to the interpreter. The interpreter then calls the methods defined in
626
 * the text enumerator to process the text.
627
 * Mad as a fish.....
628
 */
629
630
/* For our purposes if we are handling the text its because we are not
631
 * printing the page, so we cna afford to ignore all the text processing.
632
 * A more complex device might need to define real handlers for these, and
633
 * pass them on to the subclassed device.
634
 */
635
static text_enum_proc_process(flp_text_process);
636
static int
637
flp_text_resync(gs_text_enum_t *pte, const gs_text_enum_t *pfrom)
638
0
{
639
0
    return 0;
640
0
}
641
int
642
flp_text_process(gs_text_enum_t *pte)
643
0
{
644
0
    return 0;
645
0
}
646
static bool
647
flp_text_is_width_only(const gs_text_enum_t *pte)
648
0
{
649
0
    return false;
650
0
}
651
static int
652
flp_text_current_width(const gs_text_enum_t *pte, gs_point *pwidth)
653
0
{
654
0
    return 0;
655
0
}
656
static int
657
flp_text_set_cache(gs_text_enum_t *pte, const double *pw,
658
                   gs_text_cache_control_t control)
659
0
{
660
0
    return 0;
661
0
}
662
static int
663
flp_text_retry(gs_text_enum_t *pte)
664
0
{
665
0
    return 0;
666
0
}
667
static void
668
flp_text_release(gs_text_enum_t *pte, client_name_t cname)
669
0
{
670
0
    gx_default_text_release(pte, cname);
671
0
}
672
673
static const gs_text_enum_procs_t flp_text_procs = {
674
    flp_text_resync, flp_text_process,
675
    flp_text_is_width_only, flp_text_current_width,
676
    flp_text_set_cache, flp_text_retry,
677
    flp_text_release
678
};
679
680
/* The device method which we do actually need to define. Either we are skipping the page,
681
 * in which case we create a text enumerator with our dummy procedures, or we are leaving it
682
 * up to the device, in which case we simply pass on the 'begin' method to the device.
683
 */
684
int flp_text_begin(gx_device *dev, gs_gstate *pgs, const gs_text_params_t *text,
685
    gs_font *font, const gx_clip_path *pcpath,
686
    gs_text_enum_t **ppte)
687
0
{
688
0
    flp_text_enum_t *penum;
689
0
    int code;
690
0
    gs_memory_t *memory = pgs->memory;
691
692
    /* We don't want to simply ignore stringwidth for 2 reasons;
693
     * firstly because following elelments may be positioned based on the value returned
694
     * secondly  because op_show_restore executes an unconditional grestore, assuming
695
     * that a gsave has been done simply *because* its a tringwidth operation !
696
     */
697
0
    if (dev->DisablePageHandler || ((text->operation & TEXT_DO_NONE) && (text->operation & TEXT_RETURN_WIDTH) && pgs->text_rendering_mode != 3))
698
        /* Note that the high level devices *must* be given the opportunity to 'see' the
699
         * stringwidth operation, or they won;t be able to cache the glyphs properly.
700
         * So always pass stringwidth operations to the child.
701
         */
702
0
        return default_subclass_text_begin(dev, pgs, text, font, pcpath, ppte);
703
704
0
    code = SkipPage(dev);
705
0
    if (code < 0)
706
0
        return code;
707
0
    if (!code)
708
0
        return default_subclass_text_begin(dev, pgs, text, font, pcpath, ppte);
709
710
0
    rc_alloc_struct_1(penum, flp_text_enum_t, &st_flp_text_enum, memory,
711
0
                  return_error(gs_error_VMerror), "gdev_flp_text_begin");
712
0
    penum->rc.free = rc_free_text_enum;
713
0
    code = gs_text_enum_init((gs_text_enum_t *)penum, &flp_text_procs,
714
0
                         dev, pgs, text, font, pcpath, memory);
715
0
    if (code < 0) {
716
0
        gs_free_object(memory, penum, "gdev_flp_text_begin");
717
0
        return code;
718
0
    }
719
0
    *ppte = (gs_text_enum_t *)penum;
720
721
0
    return 0;
722
0
}
723
724
int flp_begin_transparency_group(gx_device *dev, const gs_transparency_group_params_t *ptgp,
725
    const gs_rect *pbbox, gs_gstate *pgs, gs_memory_t *mem)
726
0
{
727
0
    int code = SkipPage(dev);
728
729
0
    if (code < 0)
730
0
        return code;
731
0
    if (!code)
732
0
        return default_subclass_begin_transparency_group(dev, ptgp, pbbox, pgs, mem);
733
734
0
    return 0;
735
0
}
736
737
int flp_end_transparency_group(gx_device *dev, gs_gstate *pgs)
738
0
{
739
0
    int code = SkipPage(dev);
740
741
0
    if (code < 0)
742
0
        return code;
743
0
    if (!code)
744
0
        return default_subclass_end_transparency_group(dev, pgs);
745
746
0
    return 0;
747
0
}
748
749
int flp_begin_transparency_mask(gx_device *dev, const gx_transparency_mask_params_t *ptmp,
750
    const gs_rect *pbbox, gs_gstate *pgs, gs_memory_t *mem)
751
0
{
752
0
    int code = SkipPage(dev);
753
754
0
    if (code < 0)
755
0
        return code;
756
0
    if (!code)
757
0
        return default_subclass_begin_transparency_mask(dev, ptmp, pbbox, pgs, mem);
758
759
0
    return 0;
760
0
}
761
762
int flp_end_transparency_mask(gx_device *dev, gs_gstate *pgs)
763
0
{
764
0
    int code = SkipPage(dev);
765
766
0
    if (code < 0)
767
0
        return code;
768
0
    if (!code)
769
0
        return default_subclass_end_transparency_mask(dev, pgs);
770
771
0
    return 0;
772
0
}
773
774
int flp_discard_transparency_layer(gx_device *dev, gs_gstate *pgs)
775
0
{
776
0
    int code = SkipPage(dev);
777
778
0
    if (code < 0)
779
0
        return code;
780
0
    if (!code)
781
0
        return default_subclass_discard_transparency_layer(dev, pgs);
782
783
0
    return 0;
784
0
}
785
786
int flp_fill_rectangle_hl_color(gx_device *dev, const gs_fixed_rect *rect,
787
        const gs_gstate *pgs, const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
788
0
{
789
0
    int code = SkipPage(dev);
790
791
0
    if (code < 0)
792
0
        return code;
793
0
    if (!code)
794
0
        return default_subclass_fill_rectangle_hl_color(dev, rect, pgs, pdcolor, pcpath);
795
796
0
    return 0;
797
0
}
798
799
int flp_fill_linear_color_scanline(gx_device *dev, const gs_fill_attributes *fa,
800
        int i, int j, int w, const frac31 *c0, const int32_t *c0_f, const int32_t *cg_num,
801
        int32_t cg_den)
802
0
{
803
0
    int code = SkipPage(dev);
804
805
0
    if (code < 0)
806
0
        return code;
807
0
    if (!code)
808
0
        return default_subclass_fill_linear_color_scanline(dev, fa, i, j, w, c0, c0_f, cg_num, cg_den);
809
810
0
    return 0;
811
0
}
812
813
int flp_fill_linear_color_trapezoid(gx_device *dev, const gs_fill_attributes *fa,
814
        const gs_fixed_point *p0, const gs_fixed_point *p1,
815
        const gs_fixed_point *p2, const gs_fixed_point *p3,
816
        const frac31 *c0, const frac31 *c1,
817
        const frac31 *c2, const frac31 *c3)
818
0
{
819
0
    int code = SkipPage(dev);
820
821
0
    if (code < 0)
822
0
        return code;
823
0
    if (!code)
824
0
        return default_subclass_fill_linear_color_trapezoid(dev, fa, p0, p1, p2, p3, c0, c1, c2, c3);
825
826
0
    return 0;
827
0
}
828
829
int flp_fill_linear_color_triangle(gx_device *dev, const gs_fill_attributes *fa,
830
        const gs_fixed_point *p0, const gs_fixed_point *p1,
831
        const gs_fixed_point *p2, const frac31 *c0, const frac31 *c1, const frac31 *c2)
832
0
{
833
0
    int code = SkipPage(dev);
834
835
0
    if (code < 0)
836
0
        return code;
837
0
    if (!code)
838
0
        return default_subclass_fill_linear_color_triangle(dev, fa, p0, p1, p2, c0, c1, c2);
839
840
0
    return 0;
841
0
}
842
843
int flp_fillpage(gx_device *dev, gs_gstate * pgs, gx_device_color *pdevc)
844
0
{
845
0
    first_last_subclass_data *psubclass_data = dev->subclass_data;
846
0
    int code = SkipPage(dev);
847
848
0
    if (code < 0)
849
0
        return code;
850
851
    /* allow fillpage to be processed at the first page */
852
    /* This is needed to allow all parsers to start with non-ordered PageList */
853
0
    if (!code || psubclass_data->PageCount == 0)
854
0
        return default_subclass_fillpage(dev, pgs, pdevc);
855
856
0
    return 0;
857
0
}
858
859
int flp_push_transparency_state(gx_device *dev, gs_gstate *pgs)
860
0
{
861
0
    int code = SkipPage(dev);
862
863
0
    if (code < 0)
864
0
        return code;
865
0
    if (!code)
866
0
        return default_subclass_push_transparency_state(dev, pgs);
867
868
0
    return 0;
869
0
}
870
871
int flp_pop_transparency_state(gx_device *dev, gs_gstate *pgs)
872
0
{
873
0
    int code = SkipPage(dev);
874
875
0
    if (code < 0)
876
0
        return code;
877
0
    if (!code)
878
0
        return default_subclass_pop_transparency_state(dev, pgs);
879
880
0
    return 0;
881
0
}
882
883
int flp_put_image(gx_device *dev, gx_device *mdev, const byte **buffers, int num_chan, int x, int y,
884
            int width, int height, int row_stride,
885
            int alpha_plane_index, int tag_plane_index)
886
0
{
887
0
    int code = SkipPage(dev);
888
889
0
    if (code < 0)
890
0
        return code;
891
0
    if (!code)
892
0
        return default_subclass_put_image(dev, mdev, buffers, num_chan, x, y, width, height, row_stride, alpha_plane_index, tag_plane_index);
893
894
0
    return 0;
895
0
}
896
897
int flp_copy_planes(gx_device *dev, const byte *data, int data_x, int raster, gx_bitmap_id id,
898
    int x, int y, int width, int height, int plane_height)
899
0
{
900
0
    int code = SkipPage(dev);
901
902
0
    if (code < 0)
903
0
        return code;
904
0
    if (!code)
905
0
        return default_subclass_copy_planes(dev, data, data_x, raster, id, x, y, width, height, plane_height);
906
907
0
    return 0;
908
0
}
909
910
int flp_strip_copy_rop2(gx_device *dev, const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
911
    const gx_color_index *scolors, const gx_strip_bitmap *textures, const gx_color_index *tcolors,
912
    int x, int y, int width, int height, int phase_x, int phase_y, gs_logical_operation_t lop, uint planar_height)
913
0
{
914
0
    int code = SkipPage(dev);
915
916
0
    if (code < 0)
917
0
        return code;
918
0
    if (!code)
919
0
        return default_subclass_strip_copy_rop2(dev, sdata, sourcex, sraster, id, scolors, textures, tcolors, x, y, width, height, phase_x, phase_y, lop, planar_height);
920
921
0
    return 0;
922
0
}
923
924
int flp_strip_tile_rect_devn(gx_device *dev, const gx_strip_bitmap *tiles, int x, int y, int width, int height,
925
    const gx_drawing_color *pdcolor0, const gx_drawing_color *pdcolor1, int phase_x, int phase_y)
926
0
{
927
0
    int code = SkipPage(dev);
928
929
0
    if (code < 0)
930
0
        return code;
931
0
    if (!code)
932
0
        return default_subclass_strip_tile_rect_devn(dev, tiles, x, y, width, height, pdcolor0, pdcolor1, phase_x, phase_y);
933
934
0
    return 0;
935
0
}
936
937
int flp_copy_alpha_hl_color(gx_device *dev, const byte *data, int data_x,
938
    int raster, gx_bitmap_id id, int x, int y, int width, int height,
939
    const gx_drawing_color *pdcolor, int depth)
940
0
{
941
0
    int code = SkipPage(dev);
942
943
0
    if (code < 0)
944
0
        return code;
945
0
    if (!code)
946
0
        return default_subclass_copy_alpha_hl_color(dev, data, data_x, raster, id, x, y, width, height, pdcolor, depth);
947
948
0
    return 0;
949
0
}
950
951
int flp_process_page(gx_device *dev, gx_process_page_options_t *options)
952
0
{
953
0
    int code = SkipPage(dev);
954
955
0
    if (code < 0)
956
0
        return code;
957
0
    if (!code)
958
0
        return default_subclass_process_page(dev, options);
959
960
0
    return 0;
961
0
}
962
963
int flp_fill_stroke_path(gx_device *dev, const gs_gstate *pgs, gx_path *ppath,
964
    const gx_fill_params *fill_params, const gx_drawing_color *pdcolor_fill,
965
    const gx_stroke_params *stroke_params, const gx_drawing_color *pdcolor_stroke,
966
    const gx_clip_path *pcpath)
967
0
{
968
0
    int code = SkipPage(dev);
969
970
0
    if (code < 0)
971
0
        return code;
972
0
    if (!code)
973
0
        return default_subclass_fill_stroke_path(dev, pgs, ppath, fill_params, pdcolor_fill,
974
0
                                                 stroke_params, pdcolor_stroke, pcpath);
975
0
    return 0;
976
0
}
977
978
int flp_transform_pixel_region(gx_device *dev, transform_pixel_region_reason reason, transform_pixel_region_data *data)
979
0
{
980
0
    int code = SkipPage(dev);
981
982
0
    if (code < 0)
983
0
        return code;
984
0
    if (!code)
985
0
        return default_subclass_transform_pixel_region(dev, reason, data);
986
987
0
    return 0;
988
0
}
989
990
static void
991
flp_initialize_device_procs(gx_device *dev)
992
0
{
993
0
    default_subclass_initialize_device_procs(dev);
994
995
0
    set_dev_proc(dev, output_page, flp_output_page);
996
0
    set_dev_proc(dev, close_device, flp_close_device);
997
0
    set_dev_proc(dev, fill_rectangle, flp_fill_rectangle);
998
0
    set_dev_proc(dev, copy_mono, flp_copy_mono);
999
0
    set_dev_proc(dev, copy_color, flp_copy_color);
1000
0
    set_dev_proc(dev, put_params, flp_put_params);
1001
0
    set_dev_proc(dev, get_alpha_bits, flp_get_alpha_bits);
1002
0
    set_dev_proc(dev, copy_alpha, flp_copy_alpha);
1003
0
    set_dev_proc(dev, fill_path, flp_fill_path);
1004
0
    set_dev_proc(dev, stroke_path, flp_stroke_path);
1005
0
    set_dev_proc(dev, fill_mask, flp_fill_mask);
1006
0
    set_dev_proc(dev, fill_trapezoid, flp_fill_trapezoid);
1007
0
    set_dev_proc(dev, fill_parallelogram, flp_fill_parallelogram);
1008
0
    set_dev_proc(dev, fill_triangle, flp_fill_triangle);
1009
0
    set_dev_proc(dev, draw_thin_line, flp_draw_thin_line);
1010
0
    set_dev_proc(dev, strip_tile_rectangle, flp_strip_tile_rectangle);
1011
0
    set_dev_proc(dev, begin_typed_image, flp_begin_typed_image);
1012
0
    set_dev_proc(dev, get_bits_rectangle, flp_get_bits_rectangle);
1013
0
    set_dev_proc(dev, composite, flp_composite);
1014
0
    set_dev_proc(dev, text_begin, flp_text_begin);
1015
0
    set_dev_proc(dev, begin_transparency_group, flp_begin_transparency_group);
1016
0
    set_dev_proc(dev, end_transparency_group, flp_end_transparency_group);
1017
0
    set_dev_proc(dev, begin_transparency_mask, flp_begin_transparency_mask);
1018
0
    set_dev_proc(dev, end_transparency_mask, flp_end_transparency_mask);
1019
0
    set_dev_proc(dev, discard_transparency_layer, flp_discard_transparency_layer);
1020
0
    set_dev_proc(dev, fill_rectangle_hl_color, flp_fill_rectangle_hl_color);
1021
0
    set_dev_proc(dev, fill_linear_color_scanline, flp_fill_linear_color_scanline);
1022
0
    set_dev_proc(dev, fill_linear_color_trapezoid, flp_fill_linear_color_trapezoid);
1023
0
    set_dev_proc(dev, fill_linear_color_triangle, flp_fill_linear_color_triangle);
1024
0
    set_dev_proc(dev, fillpage, flp_fillpage);
1025
0
    set_dev_proc(dev, push_transparency_state, flp_push_transparency_state);
1026
0
    set_dev_proc(dev, pop_transparency_state, flp_pop_transparency_state);
1027
0
    set_dev_proc(dev, put_image, flp_put_image);
1028
0
    set_dev_proc(dev, copy_planes, flp_copy_planes);
1029
0
    set_dev_proc(dev, strip_copy_rop2, flp_strip_copy_rop2);
1030
0
    set_dev_proc(dev, strip_tile_rect_devn, flp_strip_tile_rect_devn);
1031
0
    set_dev_proc(dev, copy_alpha_hl_color, flp_copy_alpha_hl_color);
1032
0
    set_dev_proc(dev, process_page, flp_process_page);
1033
0
    set_dev_proc(dev, transform_pixel_region, flp_transform_pixel_region);
1034
0
    set_dev_proc(dev, fill_stroke_path, flp_fill_stroke_path);
1035
0
}