1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13    CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 /* Device for erasepage optimization subclass device */
17 
18 #include "math_.h"
19 #include "memory_.h"
20 #include "gx.h"
21 #include "gserrors.h"
22 #include "gsparam.h"
23 #include "gxdevice.h"
24 #include "gsdevice.h"		/* requires gsmatrix.h */
25 #include "gxdcolor.h"		/* for gx_device_black/white */
26 #include "gxiparam.h"		/* for image source size */
27 #include "gxgstate.h"
28 #include "gxpaint.h"
29 #include "gxpath.h"
30 #include "gxcpath.h"
31 #include "gxcmap.h"         /* color mapping procs */
32 #include "gsstype.h"
33 #include "gdevprn.h"
34 #include "gdevp14.h"        /* Needed to patch up the procs after compositor creation */
35 #include "gximage.h"        /* For gx_image_enum */
36 #include "gdevsclass.h"
37 #include "gsstate.h"
38 #include "gxdevsop.h"
39 #include "gdevepo.h"
40 #include <stdlib.h>
41 
42 /* Shorter macros for sanity's sake */
43 #define DPRINTF(m,f) if_debug0m(gs_debug_flag_epo_details, m,f)
44 #define DPRINTF1(m,f,a1) if_debug1m(gs_debug_flag_epo_details, m,f, a1)
45 
46 /* This is only called for debugging */
47 extern void epo_disable(int flag);
48 
49 /* Device procedures, we need quite a lot of them */
50 static dev_proc_output_page(epo_output_page);
51 static dev_proc_fill_rectangle(epo_fill_rectangle);
52 static dev_proc_draw_line(epo_draw_line);
53 static dev_proc_fill_path(epo_fill_path);
54 static dev_proc_fill_mask(epo_fill_mask);
55 static dev_proc_fill_trapezoid(epo_fill_trapezoid);
56 static dev_proc_fill_parallelogram(epo_fill_parallelogram);
57 static dev_proc_fill_triangle(epo_fill_triangle);
58 static dev_proc_draw_thin_line(epo_draw_thin_line);
59 static dev_proc_fill_rectangle_hl_color(epo_fill_rectangle_hl_color);
60 static dev_proc_fill_linear_color_scanline(epo_fill_linear_color_scanline);
61 static dev_proc_fill_linear_color_trapezoid(epo_fill_linear_color_trapezoid);
62 static dev_proc_fill_linear_color_triangle(epo_fill_linear_color_triangle);
63 static dev_proc_put_image(epo_put_image);
64 static dev_proc_fillpage(epo_fillpage);
65 static dev_proc_create_compositor(epo_create_compositor);
66 static dev_proc_text_begin(epo_text_begin);
67 static dev_proc_finish_copydevice(epo_finish_copydevice);
68 static dev_proc_begin_image(epo_begin_image);
69 static dev_proc_begin_typed_image(epo_begin_typed_image);
70 static dev_proc_stroke_path(epo_stroke_path);
71 static dev_proc_tile_rectangle(epo_tile_rectangle);
72 static dev_proc_copy_mono(epo_copy_mono);
73 static dev_proc_copy_color(epo_copy_color);
74 static dev_proc_get_bits(epo_get_bits);
75 static dev_proc_copy_alpha(epo_copy_alpha);
76 static dev_proc_copy_rop(epo_copy_rop);
77 static dev_proc_strip_tile_rectangle(epo_strip_tile_rectangle);
78 static dev_proc_strip_copy_rop(epo_strip_copy_rop);
79 static dev_proc_strip_copy_rop2(epo_strip_copy_rop2);
80 static dev_proc_copy_planes(epo_copy_planes);
81 static dev_proc_copy_alpha_hl_color(epo_copy_alpha_hl_color);
82 static dev_proc_process_page(epo_process_page);
83 static dev_proc_transform_pixel_region(epo_transform_pixel_region);
84 static dev_proc_fill_stroke_path(epo_fill_stroke_path);
85 
86 /* The device prototype */
87 #define MAX_COORD (max_int_in_fixed - 1000)
88 #define MAX_RESOLUTION 4000
89 
90 #define public_st_epo_device()	/* in gsdevice.c */\
91   gs_public_st_complex_only(st_epo_device, gx_device, EPO_DEVICENAME,\
92     0, epo_enum_ptrs, epo_reloc_ptrs, default_subclass_finalize)
93 
94 static
95 ENUM_PTRS_WITH(epo_enum_ptrs, gx_device *dev);
96 return 0; /* default case */
97 case 0:ENUM_RETURN(gx_device_enum_ptr(dev->parent));
98 case 1:ENUM_RETURN(gx_device_enum_ptr(dev->child));
99 ENUM_PTRS_END
RELOC_PTRS_WITH(epo_reloc_ptrs,gx_device * dev)100 static RELOC_PTRS_WITH(epo_reloc_ptrs, gx_device *dev)
101 {
102     dev->parent = gx_device_reloc_ptr(dev->parent, gcst);
103     dev->child = gx_device_reloc_ptr(dev->child, gcst);
104 }RELOC_PTRS_END
105 
106 public_st_epo_device();
107 
108 const
109 gx_device_epo gs_epo_device =
110 {
111     std_device_dci_type_body(gx_device_epo, 0, EPO_DEVICENAME, &st_epo_device,
112                         MAX_COORD, MAX_COORD,
113                         MAX_RESOLUTION, MAX_RESOLUTION,
114                         1, 8, 255, 0, 256, 1),
115     {default_subclass_open_device,
116      default_subclass_get_initial_matrix,
117      default_subclass_sync_output,			/* sync_output */
118      epo_output_page,
119      default_subclass_close_device,
120      default_subclass_map_rgb_color,
121      default_subclass_map_color_rgb,
122      epo_fill_rectangle,
123      epo_tile_rectangle,			/* tile_rectangle */
124      epo_copy_mono,
125      epo_copy_color,
126      epo_draw_line,			/* draw_line */
127      epo_get_bits,			/* get_bits */
128      default_subclass_get_params,
129      default_subclass_put_params,
130      default_subclass_map_cmyk_color,
131      default_subclass_get_xfont_procs,			/* get_xfont_procs */
132      default_subclass_get_xfont_device,			/* get_xfont_device */
133      default_subclass_map_rgb_alpha_color,
134      default_subclass_get_page_device,
135      default_subclass_get_alpha_bits,			/* get_alpha_bits */
136      epo_copy_alpha,
137      default_subclass_get_band,			/* get_band */
138      epo_copy_rop,			/* copy_rop */
139      epo_fill_path,
140      epo_stroke_path,
141      epo_fill_mask,
142      epo_fill_trapezoid,
143      epo_fill_parallelogram,
144      epo_fill_triangle,
145      epo_draw_thin_line,
146      epo_begin_image,
147      default_subclass_image_data,			/* image_data */
148      default_subclass_end_image,			/* end_image */
149      epo_strip_tile_rectangle,
150      epo_strip_copy_rop,
151      default_subclass_get_clipping_box,			/* get_clipping_box */
152      epo_begin_typed_image,
153      default_subclass_get_bits_rectangle,			/* get_bits_rectangle */
154      default_subclass_map_color_rgb_alpha,
155      epo_create_compositor,
156      default_subclass_get_hardware_params,			/* get_hardware_params */
157      epo_text_begin,
158      epo_finish_copydevice,                                     /* finish_copydevice */
159      default_subclass_begin_transparency_group,			/* begin_transparency_group */
160      default_subclass_end_transparency_group,			/* end_transparency_group */
161      default_subclass_begin_transparency_mask,			/* begin_transparency_mask */
162      default_subclass_end_transparency_mask,			/* end_transparency_mask */
163      default_subclass_discard_transparency_layer,			/* discard_transparency_layer */
164      default_subclass_get_color_mapping_procs,			/* get_color_mapping_procs */
165      default_subclass_get_color_comp_index,			/* get_color_comp_index */
166      default_subclass_encode_color,			/* encode_color */
167      default_subclass_decode_color,			/* decode_color */
168      default_subclass_pattern_manage,			/* pattern_manage */
169      epo_fill_rectangle_hl_color,			/* fill_rectangle_hl_color */
170      default_subclass_include_color_space,			/* include_color_space */
171      epo_fill_linear_color_scanline,			/* fill_linear_color_scanline */
172      epo_fill_linear_color_trapezoid,			/* fill_linear_color_trapezoid */
173      epo_fill_linear_color_triangle,			/* fill_linear_color_triangle */
174      default_subclass_update_spot_equivalent_colors,			/* update_spot_equivalent_colors */
175      default_subclass_ret_devn_params,			/* ret_devn_params */
176      epo_fillpage,		/* fillpage */
177      default_subclass_push_transparency_state,                      /* push_transparency_state */
178      default_subclass_pop_transparency_state,                      /* pop_transparency_state */
179      epo_put_image,                      /* put_image */
180      default_subclass_dev_spec_op,                      /* dev_spec_op */
181      epo_copy_planes,                      /* copy_planes */
182      default_subclass_get_profile,                      /* get_profile */
183      default_subclass_set_graphics_type_tag,        /* set_graphics_type_tag */
184      epo_strip_copy_rop2,
185      default_subclass_strip_tile_rect_devn,
186      epo_copy_alpha_hl_color,
187      epo_process_page,
188      epo_transform_pixel_region,
189      epo_fill_stroke_path,
190     }
191 };
192 
193 #undef MAX_COORD
194 #undef MAX_RESOLUTION
195 
196 static bool
is_device_installed(gx_device * dev,const char * name)197 is_device_installed(gx_device *dev, const char *name)
198 {
199     while (dev) {
200         if (!strcmp(dev->dname, name)) {
201             return true;
202         }
203         dev = dev->child;
204     }
205     return false;
206 }
207 
208 /* See if this is a device we can optimize
209  * (currently only the ones that use gx_default_fillpage, which
210  * automatically excludes clist and pdfwrite, etc)
211  */
212 static bool
device_wants_optimization(gx_device * dev)213 device_wants_optimization(gx_device *dev)
214 {
215     return (!gs_is_null_device(dev) && dev_proc(dev, fillpage) == gx_default_fillpage);
216 }
217 
218 /* Use this when debugging to enable/disable epo
219  * (1 - disable, 0 - enable)
220  */
221 void
epo_disable(int flag)222 epo_disable(int flag)
223 {
224     gs_debug[gs_debug_flag_epo_disable] = flag;
225 }
226 
227 int
epo_check_and_install(gx_device * dev)228 epo_check_and_install(gx_device *dev)
229 {
230     int code = 0;
231     bool is_installed;
232     bool can_optimize = false;
233 
234     /* Debugging mode to totally disable this */
235     if (gs_debug_c(gs_debug_flag_epo_disable)) {
236         return code;
237     }
238 
239     DPRINTF1(dev->memory, "current device is %s\n", dev->dname);
240 
241     is_installed = is_device_installed(dev, EPO_DEVICENAME);
242 
243     if (is_installed) {
244         DPRINTF1(dev->memory, "device %s already installed\n", EPO_DEVICENAME);
245         /* This is looking for the case where the device
246          * changed into something we can't optimize, after it was already installed
247          * (could be clist or some other weird thing)
248          */
249         if (dev->child) {
250             can_optimize = device_wants_optimization(dev->child);
251         }
252         if (!can_optimize) {
253             DPRINTF1(dev->memory, "child %s can't be optimized, uninstalling\n", dev->child->dname);
254             /* Not doing any pending fillpages because we are about to do
255              * a fillpage anyway
256              */
257             gx_device_unsubclass(dev);
258             return code;
259         }
260     } else {
261         can_optimize = device_wants_optimization(dev);
262     }
263 
264     /* Already installed, nothing to do */
265     if (is_installed) {
266         return code;
267     }
268 
269     /* See if we can optimize */
270     if (!can_optimize) {
271         DPRINTF(dev->memory, "device doesn't want optimization, not installing\n");
272         return code;
273     }
274 
275     /* Install subclass for optimization */
276     code = gx_device_subclass(dev, (gx_device *)&gs_epo_device, sizeof(erasepage_subclass_data));
277     if (code < 0) {
278         DPRINTF1(dev->memory, "ERROR installing device %s\n", EPO_DEVICENAME);
279         return code;
280     }
281 
282     DPRINTF1(dev->memory, "SUCCESS installed device %s\n", dev->dname);
283     return code;
284 }
285 
286 static int
epo_handle_erase_page(gx_device * dev)287 epo_handle_erase_page(gx_device *dev)
288 {
289     erasepage_subclass_data *data = (erasepage_subclass_data *)dev->subclass_data;
290     int code = 0;
291 
292     if (gs_debug_c(gs_debug_flag_epo_install_only)) {
293         gx_device_unsubclass(dev);
294         DPRINTF1(dev->memory, "Uninstall erasepage, device=%s\n", dev->dname);
295         return code;
296     }
297 
298     DPRINTF1(dev->memory, "Do fillpage, Uninstall erasepage, device %s\n", dev->dname);
299 
300     /* Just do a fill_rectangle (using saved color) */
301     if (dev->child) {
302         code = dev_proc(dev->child, fill_rectangle)(dev->child,
303                                                     0, 0,
304                                                     dev->child->width,
305                                                     dev->child->height,
306                                                     data->last_color);
307     }
308     /* Remove the epo device */
309     gx_device_unsubclass(dev);
310 
311     return code;
312 }
313 
epo_fillpage(gx_device * dev,gs_gstate * pgs,gx_device_color * pdevc)314 int epo_fillpage(gx_device *dev, gs_gstate * pgs, gx_device_color *pdevc)
315 {
316     erasepage_subclass_data *data = (erasepage_subclass_data *)dev->subclass_data;
317 
318     if (gs_debug_c(gs_debug_flag_epo_install_only)) {
319         return default_subclass_fillpage(dev, pgs, pdevc);
320     }
321 
322     /* If color is not pure, don't defer this, uninstall and do it now */
323     if (!color_is_pure(pdevc)) {
324         DPRINTF(dev->memory, "epo_fillpage(), color is not pure, uninstalling\n");
325         gx_device_unsubclass(dev);
326         return dev_proc(dev, fillpage)(dev, pgs, pdevc);
327     }
328 
329     /* Save the color being requested, and swallow the fillpage */
330     data->last_color = pdevc->colors.pure;
331 
332     DPRINTF(dev->memory, "Swallowing fillpage\n");
333     return 0;
334 }
335 
epo_output_page(gx_device * dev,int num_copies,int flush)336 int epo_output_page(gx_device *dev, int num_copies, int flush)
337 {
338     int code = epo_handle_erase_page(dev);
339 
340     if (code != 0)
341         return code;
342     return dev_proc(dev, output_page)(dev, num_copies, flush);
343 }
344 
epo_fill_rectangle(gx_device * dev,int x,int y,int width,int height,gx_color_index color)345 int epo_fill_rectangle(gx_device *dev, int x, int y, int width, int height, gx_color_index color)
346 {
347     int code = epo_handle_erase_page(dev);
348 
349     if (code != 0)
350         return code;
351     return dev_proc(dev, fill_rectangle)(dev, x, y, width, height, color);
352 }
353 
epo_draw_line(gx_device * dev,int x0,int y0,int x1,int y1,gx_color_index color)354 int epo_draw_line(gx_device *dev, int x0, int y0, int x1, int y1, gx_color_index color)
355 {
356     int code = epo_handle_erase_page(dev);
357 
358     if (code != 0)
359         return code;
360     return dev_proc(dev, obsolete_draw_line)(dev, x0, y0, x1, y1, color);
361 }
362 
epo_fill_path(gx_device * dev,const gs_gstate * pgs,gx_path * ppath,const gx_fill_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)363 int epo_fill_path(gx_device *dev, const gs_gstate *pgs, gx_path *ppath,
364     const gx_fill_params *params,
365     const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
366 {
367     int code = epo_handle_erase_page(dev);
368 
369     if (code != 0)
370         return code;
371     return dev_proc(dev, fill_path)(dev, pgs, ppath, params, pdcolor, pcpath);
372 }
373 
epo_fill_mask(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int width,int height,const gx_drawing_color * pdcolor,int depth,gs_logical_operation_t lop,const gx_clip_path * pcpath)374 int epo_fill_mask(gx_device *dev, const byte *data, int data_x, int raster, gx_bitmap_id id,
375     int x, int y, int width, int height,
376     const gx_drawing_color *pdcolor, int depth,
377     gs_logical_operation_t lop, const gx_clip_path *pcpath)
378 {
379     int code = epo_handle_erase_page(dev);
380 
381     if (code != 0)
382         return code;
383     return dev_proc(dev, fill_mask)(dev, data, data_x, raster, id, x, y, width, height, pdcolor, depth, lop, pcpath);
384 }
385 
epo_fill_trapezoid(gx_device * dev,const gs_fixed_edge * left,const gs_fixed_edge * right,fixed ybot,fixed ytop,bool swap_axes,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)386 int epo_fill_trapezoid(gx_device *dev, const gs_fixed_edge *left, const gs_fixed_edge *right,
387     fixed ybot, fixed ytop, bool swap_axes,
388     const gx_drawing_color *pdcolor, gs_logical_operation_t lop)
389 {
390     int code = epo_handle_erase_page(dev);
391 
392     if (code != 0)
393         return code;
394     return dev_proc(dev, fill_trapezoid)(dev, left, right, ybot, ytop, swap_axes, pdcolor, lop);
395 }
396 
epo_fill_parallelogram(gx_device * dev,fixed px,fixed py,fixed ax,fixed ay,fixed bx,fixed by,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)397 int epo_fill_parallelogram(gx_device *dev, fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
398     const gx_drawing_color *pdcolor, gs_logical_operation_t lop)
399 {
400     int code = epo_handle_erase_page(dev);
401 
402     if (code != 0)
403         return code;
404     return dev_proc(dev, fill_parallelogram)(dev, px, py, ax, ay, bx, by, pdcolor, lop);
405 }
406 
epo_fill_triangle(gx_device * dev,fixed px,fixed py,fixed ax,fixed ay,fixed bx,fixed by,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)407 int epo_fill_triangle(gx_device *dev, fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
408     const gx_drawing_color *pdcolor, gs_logical_operation_t lop)
409 {
410     int code = epo_handle_erase_page(dev);
411 
412     if (code != 0)
413         return code;
414     return dev_proc(dev, fill_triangle)(dev, px, py, ax, ay, bx, by, pdcolor, lop);
415 }
416 
epo_draw_thin_line(gx_device * dev,fixed fx0,fixed fy0,fixed fx1,fixed fy1,const gx_drawing_color * pdcolor,gs_logical_operation_t lop,fixed adjustx,fixed adjusty)417 int epo_draw_thin_line(gx_device *dev, fixed fx0, fixed fy0, fixed fx1, fixed fy1,
418     const gx_drawing_color *pdcolor, gs_logical_operation_t lop,
419     fixed adjustx, fixed adjusty)
420 {
421     int code = epo_handle_erase_page(dev);
422 
423     if (code != 0)
424         return code;
425     return dev_proc(dev, draw_thin_line)(dev, fx0, fy0, fx1, fy1, pdcolor, lop, adjustx, adjusty);
426 }
427 
epo_fill_rectangle_hl_color(gx_device * dev,const gs_fixed_rect * rect,const gs_gstate * pgs,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)428 int epo_fill_rectangle_hl_color(gx_device *dev, const gs_fixed_rect *rect,
429         const gs_gstate *pgs, const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
430 {
431     int code = epo_handle_erase_page(dev);
432 
433     if (code != 0)
434         return code;
435     return dev_proc(dev, fill_rectangle_hl_color)(dev, rect, pgs, pdcolor, pcpath);
436 }
437 
epo_fill_linear_color_scanline(gx_device * dev,const gs_fill_attributes * fa,int i,int j,int w,const frac31 * c0,const int32_t * c0_f,const int32_t * cg_num,int32_t cg_den)438 int epo_fill_linear_color_scanline(gx_device *dev, const gs_fill_attributes *fa,
439         int i, int j, int w, const frac31 *c0, const int32_t *c0_f, const int32_t *cg_num,
440         int32_t cg_den)
441 {
442     int code = epo_handle_erase_page(dev);
443 
444     if (code != 0)
445         return code;
446     return dev_proc(dev, fill_linear_color_scanline)(dev, fa, i, j, w, c0, c0_f, cg_num, cg_den);
447 }
448 
epo_fill_linear_color_trapezoid(gx_device * dev,const gs_fill_attributes * fa,const gs_fixed_point * p0,const gs_fixed_point * p1,const gs_fixed_point * p2,const gs_fixed_point * p3,const frac31 * c0,const frac31 * c1,const frac31 * c2,const frac31 * c3)449 int epo_fill_linear_color_trapezoid(gx_device *dev, const gs_fill_attributes *fa,
450         const gs_fixed_point *p0, const gs_fixed_point *p1,
451         const gs_fixed_point *p2, const gs_fixed_point *p3,
452         const frac31 *c0, const frac31 *c1,
453         const frac31 *c2, const frac31 *c3)
454 {
455     int code = epo_handle_erase_page(dev);
456 
457     if (code != 0)
458         return code;
459     return dev_proc(dev, fill_linear_color_trapezoid)(dev, fa, p0, p1, p2, p3, c0, c1, c2, c3);
460 }
461 
epo_fill_linear_color_triangle(gx_device * dev,const gs_fill_attributes * fa,const gs_fixed_point * p0,const gs_fixed_point * p1,const gs_fixed_point * p2,const frac31 * c0,const frac31 * c1,const frac31 * c2)462 int epo_fill_linear_color_triangle(gx_device *dev, const gs_fill_attributes *fa,
463         const gs_fixed_point *p0, const gs_fixed_point *p1,
464         const gs_fixed_point *p2, const frac31 *c0, const frac31 *c1, const frac31 *c2)
465 {
466     int code = epo_handle_erase_page(dev);
467 
468     if (code != 0)
469         return code;
470     return dev_proc(dev, fill_linear_color_triangle)(dev, fa, p0, p1, p2, c0, c1, c2);
471 }
472 
epo_put_image(gx_device * dev,gx_device * mdev,const byte ** buffers,int num_chan,int x,int y,int width,int height,int row_stride,int alpha_plane_index,int tag_plane_index)473 int epo_put_image(gx_device *dev, gx_device *mdev, const byte **buffers, int num_chan, int x, int y,
474             int width, int height, int row_stride,
475             int alpha_plane_index, int tag_plane_index)
476 {
477     int code = epo_handle_erase_page(dev);
478 
479     if (code != 0)
480         return code;
481     return dev_proc(dev, put_image)(dev, mdev, buffers, num_chan, x, y, width, height, row_stride, alpha_plane_index, tag_plane_index);
482 }
483 
epo_create_compositor(gx_device * dev,gx_device ** pcdev,const gs_composite_t * pcte,gs_gstate * pgs,gs_memory_t * memory,gx_device * cdev)484 int epo_create_compositor(gx_device *dev, gx_device **pcdev, const gs_composite_t *pcte,
485     gs_gstate *pgs, gs_memory_t *memory, gx_device *cdev)
486 {
487     int code = epo_handle_erase_page(dev);
488 
489     if (code != 0)
490         return code;
491     return dev_proc(dev, create_compositor)(dev, pcdev, pcte, pgs, memory, cdev);
492 }
493 
epo_text_begin(gx_device * dev,gs_gstate * pgs,const gs_text_params_t * text,gs_font * font,gx_path * path,const gx_device_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * memory,gs_text_enum_t ** ppte)494 int epo_text_begin(gx_device *dev, gs_gstate *pgs, const gs_text_params_t *text,
495     gs_font *font, gx_path *path, const gx_device_color *pdcolor, const gx_clip_path *pcpath,
496     gs_memory_t *memory, gs_text_enum_t **ppte)
497 {
498     int code = epo_handle_erase_page(dev);
499 
500     if (code != 0)
501         return code;
502     return dev_proc(dev, text_begin)(dev, pgs, text, font, path, pdcolor, pcpath, memory, ppte);
503 }
504 
epo_finish_copydevice(gx_device * dev,const gx_device * from_dev)505 int epo_finish_copydevice(gx_device *dev, const gx_device *from_dev)
506 {
507     /* We musn't allow the following pointers to remain shared with the from_dev
508        because we're about to tell the caller it's only allowed to copy the prototype
509        and free the attempted copy of a non-prototype. If from_dev is the prototype
510        these pointers won't be set, anyway.
511      */
512     dev->child = NULL;
513     dev->parent = NULL;
514     dev->subclass_data = NULL;
515     /* Only allow copying the prototype. */
516     return (from_dev->memory ? gs_note_error(gs_error_rangecheck) : 0);
517 }
518 
epo_begin_image(gx_device * dev,const gs_gstate * pgs,const gs_image_t * pim,gs_image_format_t format,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * memory,gx_image_enum_common_t ** pinfo)519 int epo_begin_image(gx_device *dev, const gs_gstate *pgs, const gs_image_t *pim,
520     gs_image_format_t format, const gs_int_rect *prect,
521     const gx_drawing_color *pdcolor, const gx_clip_path *pcpath,
522     gs_memory_t *memory, gx_image_enum_common_t **pinfo)
523 {
524     int code = epo_handle_erase_page(dev);
525 
526     if (code != 0)
527         return code;
528     return dev_proc(dev, begin_image)(dev, pgs, pim, format, prect, pdcolor, pcpath, memory, pinfo);
529 }
530 
epo_begin_typed_image(gx_device * dev,const gs_gstate * pgs,const gs_matrix * pmat,const gs_image_common_t * pic,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * memory,gx_image_enum_common_t ** pinfo)531 int epo_begin_typed_image(gx_device *dev, const gs_gstate *pgs, const gs_matrix *pmat,
532     const gs_image_common_t *pic, const gs_int_rect *prect,
533     const gx_drawing_color *pdcolor, const gx_clip_path *pcpath,
534     gs_memory_t *memory, gx_image_enum_common_t **pinfo)
535 {
536     int code = epo_handle_erase_page(dev);
537 
538     if (code != 0)
539         return code;
540     return dev_proc(dev, begin_typed_image)(dev, pgs, pmat, pic, prect, pdcolor, pcpath, memory, pinfo);
541 }
542 
epo_stroke_path(gx_device * dev,const gs_gstate * pgs,gx_path * ppath,const gx_stroke_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)543 int epo_stroke_path(gx_device *dev, const gs_gstate *pgs, gx_path *ppath,
544     const gx_stroke_params *params,
545     const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
546 {
547     int code = epo_handle_erase_page(dev);
548 
549     if (code != 0)
550         return code;
551     return dev_proc(dev, stroke_path)(dev, pgs, ppath, params, pdcolor, pcpath);
552 }
553 
epo_tile_rectangle(gx_device * dev,const gx_tile_bitmap * tile,int x,int y,int width,int height,gx_color_index color0,gx_color_index color1,int phase_x,int phase_y)554 int epo_tile_rectangle(gx_device *dev, const gx_tile_bitmap *tile, int x, int y, int width, int height,
555     gx_color_index color0, gx_color_index color1,
556     int phase_x, int phase_y)
557 {
558     int code = epo_handle_erase_page(dev);
559 
560     if (code != 0)
561         return code;
562     return dev_proc(dev, tile_rectangle)(dev, tile, x, y, width, height, color0, color1, phase_x, phase_y);
563 }
564 
epo_copy_mono(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int width,int height,gx_color_index color0,gx_color_index color1)565 int epo_copy_mono(gx_device *dev, const byte *data, int data_x, int raster, gx_bitmap_id id,
566     int x, int y, int width, int height,
567     gx_color_index color0, gx_color_index color1)
568 {
569     int code = epo_handle_erase_page(dev);
570 
571     if (code != 0)
572         return code;
573     return dev_proc(dev, copy_mono)(dev, data, data_x, raster, id, x, y, width, height, color0, color1);
574 }
575 
epo_copy_color(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int width,int height)576 int epo_copy_color(gx_device *dev, const byte *data, int data_x, int raster, gx_bitmap_id id,\
577     int x, int y, int width, int height)
578 {
579     int code = epo_handle_erase_page(dev);
580 
581     if (code != 0)
582         return code;
583     return dev_proc(dev, copy_color)(dev, data, data_x, raster, id, x, y, width, height);
584 }
585 
epo_get_bits(gx_device * dev,int y,byte * data,byte ** actual_data)586 int epo_get_bits(gx_device *dev, int y, byte *data, byte **actual_data)
587 {
588     int code = epo_handle_erase_page(dev);
589 
590     if (code != 0)
591         return code;
592     return dev_proc(dev, get_bits)(dev, y, data, actual_data);
593 }
594 
epo_copy_alpha(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int width,int height,gx_color_index color,int depth)595 int epo_copy_alpha(gx_device *dev, const byte *data, int data_x,
596     int raster, gx_bitmap_id id, int x, int y, int width, int height,
597     gx_color_index color, int depth)
598 {
599     int code = epo_handle_erase_page(dev);
600 
601     if (code != 0)
602         return code;
603     return dev_proc(dev, copy_alpha)(dev, data, data_x, raster, id, x, y, width, height, color, depth);
604 }
605 
epo_copy_rop(gx_device * dev,const byte * sdata,int sourcex,uint sraster,gx_bitmap_id id,const gx_color_index * scolors,const gx_tile_bitmap * texture,const gx_color_index * tcolors,int x,int y,int width,int height,int phase_x,int phase_y,gs_logical_operation_t lop)606 int epo_copy_rop(gx_device *dev, const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
607     const gx_color_index *scolors,
608     const gx_tile_bitmap *texture, const gx_color_index *tcolors,
609     int x, int y, int width, int height,
610     int phase_x, int phase_y, gs_logical_operation_t lop)
611 {
612     int code = epo_handle_erase_page(dev);
613 
614     if (code != 0)
615         return code;
616     return dev_proc(dev, copy_rop)(dev, sdata, sourcex, sraster, id, scolors, texture, tcolors, x, y, width, height, phase_x, phase_y, lop);
617 }
618 
epo_strip_tile_rectangle(gx_device * dev,const gx_strip_bitmap * tiles,int x,int y,int width,int height,gx_color_index color0,gx_color_index color1,int phase_x,int phase_y)619 int epo_strip_tile_rectangle(gx_device *dev, const gx_strip_bitmap *tiles, int x, int y, int width, int height,
620     gx_color_index color0, gx_color_index color1,
621     int phase_x, int phase_y)
622 {
623     int code = epo_handle_erase_page(dev);
624 
625     if (code != 0)
626         return code;
627     return dev_proc(dev, strip_tile_rectangle)(dev, tiles, x, y, width, height, color0, color1, phase_x, phase_y);
628 }
629 
epo_strip_copy_rop(gx_device * dev,const byte * sdata,int sourcex,uint sraster,gx_bitmap_id id,const gx_color_index * scolors,const gx_strip_bitmap * textures,const gx_color_index * tcolors,int x,int y,int width,int height,int phase_x,int phase_y,gs_logical_operation_t lop)630 int epo_strip_copy_rop(gx_device *dev, const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
631     const gx_color_index *scolors,
632     const gx_strip_bitmap *textures, const gx_color_index *tcolors,
633     int x, int y, int width, int height,
634     int phase_x, int phase_y, gs_logical_operation_t lop)
635 {
636     int code = epo_handle_erase_page(dev);
637 
638     if (code != 0)
639         return code;
640     return dev_proc(dev, strip_copy_rop)(dev, sdata, sourcex, sraster, id, scolors, textures, tcolors, x, y, width, height, phase_x, phase_y, lop);
641 }
642 
epo_strip_copy_rop2(gx_device * dev,const byte * sdata,int sourcex,uint sraster,gx_bitmap_id id,const gx_color_index * scolors,const gx_strip_bitmap * textures,const gx_color_index * tcolors,int x,int y,int width,int height,int phase_x,int phase_y,gs_logical_operation_t lop,uint planar_height)643 int epo_strip_copy_rop2(gx_device *dev, const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
644     const gx_color_index *scolors, const gx_strip_bitmap *textures, const gx_color_index *tcolors,
645     int x, int y, int width, int height, int phase_x, int phase_y, gs_logical_operation_t lop, uint planar_height)
646 {
647     int code = epo_handle_erase_page(dev);
648 
649     if (code != 0)
650         return code;
651     return dev_proc(dev, strip_copy_rop2)(dev, sdata, sourcex, sraster, id, scolors, textures, tcolors, x, y, width, height, phase_x, phase_y, lop, planar_height);
652 }
653 
epo_copy_planes(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int width,int height,int plane_height)654 int epo_copy_planes(gx_device *dev, const byte *data, int data_x, int raster, gx_bitmap_id id,
655     int x, int y, int width, int height, int plane_height)
656 {
657     int code = epo_handle_erase_page(dev);
658 
659     if (code != 0)
660         return code;
661     return dev_proc(dev, copy_planes)(dev, data, data_x, raster, id, x, y, width, height, plane_height);
662 }
663 
epo_copy_alpha_hl_color(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int width,int height,const gx_drawing_color * pdcolor,int depth)664 int epo_copy_alpha_hl_color(gx_device *dev, const byte *data, int data_x,
665     int raster, gx_bitmap_id id, int x, int y, int width, int height,
666     const gx_drawing_color *pdcolor, int depth)
667 {
668     int code = epo_handle_erase_page(dev);
669 
670     if (code != 0)
671         return code;
672     return dev_proc(dev, copy_alpha_hl_color)(dev, data, data_x, raster, id, x, y, width, height, pdcolor, depth);
673 }
674 
epo_process_page(gx_device * dev,gx_process_page_options_t * options)675 int epo_process_page(gx_device *dev, gx_process_page_options_t *options)
676 {
677     int code = epo_handle_erase_page(dev);
678 
679     if (code != 0)
680         return code;
681     return dev_proc(dev, process_page)(dev, options);
682 }
683 
epo_fill_stroke_path(gx_device * dev,const gs_gstate * pgs,gx_path * ppath,const gx_fill_params * fill_params,const gx_drawing_color * pdcolor_fill,const gx_stroke_params * stroke_params,const gx_drawing_color * pdcolor_stroke,const gx_clip_path * pcpath)684 int epo_fill_stroke_path(gx_device *dev, const gs_gstate *pgs, gx_path *ppath,
685     const gx_fill_params *fill_params, const gx_drawing_color *pdcolor_fill,
686     const gx_stroke_params *stroke_params, const gx_drawing_color *pdcolor_stroke,
687     const gx_clip_path *pcpath)
688 {
689     int code = epo_handle_erase_page(dev);
690 
691     if (code != 0)
692         return code;
693     return dev_proc(dev, fill_stroke_path)(dev, pgs, ppath, fill_params, pdcolor_fill,
694                                            stroke_params, pdcolor_stroke, pcpath);
695 }
696 
epo_transform_pixel_region(gx_device * dev,transform_pixel_region_reason reason,transform_pixel_region_data * data)697 int epo_transform_pixel_region(gx_device *dev, transform_pixel_region_reason reason, transform_pixel_region_data *data)
698 {
699     int code = epo_handle_erase_page(dev);
700 
701     if (code != 0)
702         return code;
703     return dev_proc(dev, transform_pixel_region)(dev, reason, data);
704 }
705