/src/ghostpdl/base/gdevsclass.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2026 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | /* Common code for subclassing devices */ |
17 | | #include "math_.h" |
18 | | #include "memory_.h" |
19 | | #include "gx.h" |
20 | | #include "gserrors.h" |
21 | | #include "gsparam.h" |
22 | | #include "gxdevice.h" |
23 | | #include "gsdevice.h" /* requires gsmatrix.h */ |
24 | | #include "gxdcolor.h" /* for gx_device_black/white */ |
25 | | #include "gxiparam.h" /* for image source size */ |
26 | | #include "gxgstate.h" |
27 | | #include "gxpaint.h" |
28 | | #include "gxpath.h" |
29 | | #include "gxcpath.h" |
30 | | #include "gxcmap.h" /* color mapping procs */ |
31 | | #include "gsstype.h" |
32 | | #include "gdevprn.h" |
33 | | #include "gdevp14.h" /* Needed to patch up the procs after compositor creation */ |
34 | | #include "gdevsclass.h" |
35 | | #include "gxdevsop.h" |
36 | | |
37 | | /* |
38 | | * It would be nice if we could rewrite the clist handling to use this kind of device class chain |
39 | | * instead of the nasty hackery it currently utilises (stores the device procs for the existing |
40 | | * device in 'orig_procs' which is in the device structure) and overwrites the procs with its |
41 | | * own ones. The bbox forwarding device could also be rewritten this way and would probably then |
42 | | * be usable as a real forwarding device (last time I tried to do this for eps2write I was unable |
43 | | * to solve the problems with text enumerators). |
44 | | */ |
45 | | |
46 | | /* At first sight we should never have a method in a device structure which is NULL |
47 | | * because gx_device_fill_in_procs() should replace all the NULLs with default routines. |
48 | | * However, obselete routines, and a number of newer routines (especially those involving |
49 | | * transparency) don't get filled in. Its not obvious to me if this is deliberate or not, |
50 | | * but we'll be careful and check the subclassed device's method before trying to execute |
51 | | * it. Same for all the methods. NB the fill_rectangle method is deliberately not filled in |
52 | | * because that gets set up by gdev_prn_allocate_memory(). Isn't it great the way we do our |
53 | | * initialisation in lots of places? |
54 | | */ |
55 | | |
56 | | /* TODO make gx_device_fill_in_procs fill in *all* the procs, currently it doesn't. |
57 | | * this will mean declaring gx_default_ methods for the transparency methods, possibly |
58 | | * some others. Like a number of other default methods, these can simply return an error |
59 | | * which hopefuly will avoid us having to check for NULL device methods. |
60 | | * We also agreed to set the fill_rectangle method to a default as well (currently it explicitly |
61 | | * does not do this) and have gdev_prn_alloc_buffer check to see if the method is the default |
62 | | * before overwriting it, rather than the current check for NULL. |
63 | | */ |
64 | | |
65 | | /* More observations; method naems, we have text_begin, but begin_typed_image. |
66 | | * The enumerator initialiser for images gx_image_enum_common_init doesn't initialise |
67 | | * the 'memory' member variable. The text enumerator initialiser gs_text_enum_init does. |
68 | | * The default text enum init routine increments the reference count of the device, but the image enumerator |
69 | | * doesn't. |
70 | | */ |
71 | | |
72 | | /* We have a device method for 'get_profile' but we don't have one for 'set_profile' which causes some |
73 | | * problems, the 'set' simply sets the profile in the top device. This is modified in gsicc_set_device_profile |
74 | | * for now but really should have a method to itself. |
75 | | * |
76 | | * And in a delightful asymmetry, we have a set_graphics_type_tag, but no get_graphics_type_tag. Instead |
77 | | * (shudder) the code pulls the currently encoded colour and tag *directly* from the current device. |
78 | | * This means we have to copy the ENCODE_TAGS from the device we are subclassing, into the device which |
79 | | * is newly created at installation time. We also have to have our default set_graphics_type_tag method |
80 | | * update its graphics_type_tag, even though this device has no interest in it, just in case we happen |
81 | | * to be the top device in the chain...... |
82 | | */ |
83 | | |
84 | | /* |
85 | | * gsdparam.c line 272 checks for method being NULL, this is bad, we should check for a return error |
86 | | * or default method and do initialisation based on that. |
87 | | */ |
88 | | |
89 | | |
90 | | /* For printing devices the 'open' routine in gdevprn calls gdevprn_allocate_memory |
91 | | * which is responsible for creating the page buffer. This *also* fills in some of |
92 | | * the device procs, in particular fill_rectangle() so its vitally important that |
93 | | * we pass this on. |
94 | | */ |
95 | | int default_subclass_open_device(gx_device *dev) |
96 | 0 | { |
97 | 0 | int code = 0; |
98 | | |
99 | | /* observed with Bug 699794, don't set is_open = true if the open_device failed */ |
100 | | /* and make sure to propagate the return code from the child device to caller. */ |
101 | | /* Only open the child if it was closed and if child open is OK, return 1. */ |
102 | | /* (see gs_opendevice) */ |
103 | 0 | if (dev->child && dev->child->is_open == 0) { |
104 | 0 | code = dev_proc(dev->child, open_device)(dev->child); |
105 | 0 | if (code >= 0) { |
106 | 0 | dev->child->is_open = true; |
107 | 0 | code = 1; /* device had been closed, but now is open */ |
108 | 0 | } |
109 | 0 | gx_update_from_subclass(dev); /* this is probably safe to do even if the open failed */ |
110 | 0 | } |
111 | 0 | return code; |
112 | 0 | } |
113 | | |
114 | | void default_subclass_get_initial_matrix(gx_device *dev, gs_matrix *pmat) |
115 | 1.46M | { |
116 | 1.46M | if (dev->child) |
117 | 1.46M | dev_proc(dev->child, get_initial_matrix)(dev->child, pmat); |
118 | 0 | else |
119 | 0 | gx_default_get_initial_matrix(dev, pmat); |
120 | 1.46M | return; |
121 | 1.46M | } |
122 | | |
123 | | int default_subclass_sync_output(gx_device *dev) |
124 | 271k | { |
125 | 271k | if (dev->child) |
126 | 271k | return dev_proc(dev->child, sync_output)(dev->child); |
127 | | /* else */ |
128 | 0 | return gx_default_sync_output(dev); |
129 | 271k | } |
130 | | |
131 | | int default_subclass_output_page(gx_device *dev, int num_copies, int flush) |
132 | 26.3k | { |
133 | 26.3k | int code = 0; |
134 | | |
135 | 26.3k | if (dev->child) { |
136 | 26.3k | code = dev_proc(dev->child, output_page)(dev->child, num_copies, flush); |
137 | 26.3k | dev->PageCount = dev->child->PageCount; |
138 | 26.3k | return code; |
139 | 26.3k | } |
140 | 0 | dev->PageCount += num_copies; /* a minor lie */ |
141 | 0 | return 0; |
142 | 26.3k | } |
143 | | |
144 | | int default_subclass_close_device(gx_device *dev) |
145 | 34.9k | { |
146 | 34.9k | int code; |
147 | | |
148 | 34.9k | if (dev->child) { |
149 | 34.9k | code = dev_proc(dev->child, close_device)(dev->child); |
150 | 34.9k | dev->is_open = dev->child->is_open = false; |
151 | 34.9k | return code; |
152 | 34.9k | } |
153 | 0 | dev->is_open = false; |
154 | 0 | return 0; |
155 | 34.9k | } |
156 | | |
157 | | gx_color_index default_subclass_map_rgb_color(gx_device *dev, const gx_color_value cv[]) |
158 | 0 | { |
159 | 0 | if (dev->child) |
160 | 0 | return dev_proc(dev->child, map_rgb_color)(dev->child, cv); |
161 | 0 | else |
162 | 0 | gx_error_encode_color(dev, cv); |
163 | 0 | return 0; |
164 | 0 | } |
165 | | |
166 | | int default_subclass_map_color_rgb(gx_device *dev, gx_color_index color, gx_color_value rgb[3]) |
167 | 0 | { |
168 | 0 | if (dev->child) |
169 | 0 | return dev_proc(dev->child, map_color_rgb)(dev->child, color, rgb); |
170 | | /* else */ |
171 | 0 | return gx_default_map_color_rgb(dev, color, rgb); |
172 | 0 | } |
173 | | |
174 | | int default_subclass_fill_rectangle(gx_device *dev, int x, int y, int width, int height, gx_color_index color) |
175 | 817k | { |
176 | 817k | if (dev->child) |
177 | 817k | return dev_proc(dev->child, fill_rectangle)(dev->child, x, y, width, height, color); |
178 | 0 | return 0; |
179 | 817k | } |
180 | | |
181 | | int default_subclass_copy_mono(gx_device *dev, const byte *data, int data_x, int raster, gx_bitmap_id id, |
182 | | int x, int y, int width, int height, |
183 | | gx_color_index color0, gx_color_index color1) |
184 | 0 | { |
185 | 0 | if (dev->child) |
186 | 0 | return dev_proc(dev->child, copy_mono)(dev->child, data, data_x, raster, id, x, y, width, height, color0, color1); |
187 | 0 | return 0; |
188 | 0 | } |
189 | | |
190 | | int default_subclass_copy_color(gx_device *dev, const byte *data, int data_x, int raster, gx_bitmap_id id,\ |
191 | | int x, int y, int width, int height) |
192 | 0 | { |
193 | 0 | if (dev->child) |
194 | 0 | return dev_proc(dev->child, copy_color)(dev->child, data, data_x, raster, id, x, y, width, height); |
195 | 0 | return 0; |
196 | 0 | } |
197 | | |
198 | | int default_subclass_get_params(gx_device *dev, gs_param_list *plist) |
199 | 480k | { |
200 | 480k | if (dev->child) |
201 | 480k | return dev_proc(dev->child, get_params)(dev->child, plist); |
202 | | /* else */ |
203 | 0 | return gx_default_get_params(dev, plist); |
204 | 480k | } |
205 | | |
206 | | int default_subclass_put_params(gx_device *dev, gs_param_list *plist) |
207 | 192k | { |
208 | 192k | int code; |
209 | | |
210 | 192k | if (dev->child) { |
211 | 192k | code = dev_proc(dev->child, put_params)(dev->child, plist); |
212 | | /* The child device might have closed itself (yes seriously, this can happen!) */ |
213 | 192k | dev->is_open = dev->child->is_open; |
214 | 192k | gx_update_from_subclass(dev); |
215 | 192k | return code; |
216 | 192k | } |
217 | | /* else */ |
218 | 0 | return gx_default_put_params(dev, plist); |
219 | 192k | } |
220 | | |
221 | | gx_color_index default_subclass_map_cmyk_color(gx_device *dev, const gx_color_value cv[]) |
222 | 0 | { |
223 | 0 | if (dev->child) |
224 | 0 | return dev_proc(dev->child, map_cmyk_color)(dev->child, cv); |
225 | | /* else */ |
226 | 0 | return gx_default_map_cmyk_color(dev, cv); |
227 | 0 | } |
228 | | |
229 | | gx_device *default_subclass_get_page_device(gx_device *dev) |
230 | 7.20M | { |
231 | 7.20M | if (dev->child) |
232 | 7.20M | return dev_proc(dev->child, get_page_device)(dev->child); |
233 | | /* else */ |
234 | 0 | return gx_default_get_page_device(dev); |
235 | 7.20M | } |
236 | | |
237 | | int default_subclass_get_alpha_bits(gx_device *dev, graphics_object_type type) |
238 | 13.9M | { |
239 | 13.9M | if (dev->child) |
240 | 13.9M | return dev_proc(dev->child, get_alpha_bits)(dev->child, type); |
241 | 0 | return 0; |
242 | 13.9M | } |
243 | | |
244 | | int default_subclass_copy_alpha(gx_device *dev, const byte *data, int data_x, |
245 | | int raster, gx_bitmap_id id, int x, int y, int width, int height, |
246 | | gx_color_index color, int depth) |
247 | 0 | { |
248 | 0 | if (dev->child) |
249 | 0 | return dev_proc(dev->child, copy_alpha)(dev->child, data, data_x, raster, id, x, y, width, height, color, depth); |
250 | 0 | return 0; |
251 | 0 | } |
252 | | |
253 | | int default_subclass_fill_path(gx_device *dev, const gs_gstate *pgs, gx_path *ppath, |
254 | | const gx_fill_params *params, |
255 | | const gx_drawing_color *pdcolor, const gx_clip_path *pcpath) |
256 | 4.19M | { |
257 | 4.19M | if (dev->child) |
258 | 4.19M | return dev_proc(dev->child, fill_path)(dev->child, pgs, ppath, params, pdcolor, pcpath); |
259 | | /* else */ |
260 | 0 | return gx_default_fill_path(dev, pgs, ppath, params, pdcolor, pcpath); |
261 | 4.19M | } |
262 | | |
263 | | int default_subclass_stroke_path(gx_device *dev, const gs_gstate *pgs, gx_path *ppath, |
264 | | const gx_stroke_params *params, |
265 | | const gx_drawing_color *pdcolor, const gx_clip_path *pcpath) |
266 | 813k | { |
267 | 813k | if (dev->child) |
268 | 813k | return dev_proc(dev->child, stroke_path)(dev->child, pgs, ppath, params, pdcolor, pcpath); |
269 | | /* else */ |
270 | 0 | return gx_default_stroke_path(dev, pgs, ppath, params, pdcolor, pcpath); |
271 | 813k | } |
272 | | |
273 | | int default_subclass_fill_mask(gx_device *dev, const byte *data, int data_x, int raster, gx_bitmap_id id, |
274 | | int x, int y, int width, int height, |
275 | | const gx_drawing_color *pdcolor, int depth, |
276 | | gs_logical_operation_t lop, const gx_clip_path *pcpath) |
277 | 0 | { |
278 | 0 | if (dev->child) |
279 | 0 | return dev_proc(dev->child, fill_mask)(dev->child, data, data_x, raster, id, x, y, width, height, pdcolor, depth, lop, pcpath); |
280 | | /* else */ |
281 | 0 | return gx_default_fill_mask(dev, data, data_x, raster, id, x, y, width, height, pdcolor, depth, lop, pcpath); |
282 | 0 | } |
283 | | |
284 | | int default_subclass_fill_trapezoid(gx_device *dev, const gs_fixed_edge *left, const gs_fixed_edge *right, |
285 | | fixed ybot, fixed ytop, bool swap_axes, |
286 | | const gx_drawing_color *pdcolor, gs_logical_operation_t lop) |
287 | 0 | { |
288 | 0 | if (dev->child) |
289 | 0 | return dev_proc(dev->child, fill_trapezoid)(dev->child, left, right, ybot, ytop, swap_axes, pdcolor, lop); |
290 | | /* else */ |
291 | 0 | return gx_default_fill_trapezoid(dev, left, right, ybot, ytop, swap_axes, pdcolor, lop); |
292 | 0 | } |
293 | | |
294 | | int default_subclass_fill_parallelogram(gx_device *dev, fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by, |
295 | | const gx_drawing_color *pdcolor, gs_logical_operation_t lop) |
296 | 0 | { |
297 | 0 | if (dev->child) |
298 | 0 | return dev_proc(dev->child, fill_parallelogram)(dev->child, px, py, ax, ay, bx, by, pdcolor, lop); |
299 | | /* else */ |
300 | 0 | return gx_default_fill_parallelogram(dev, px, py, ax, ay, bx, by, pdcolor, lop); |
301 | 0 | } |
302 | | |
303 | | int default_subclass_fill_triangle(gx_device *dev, fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by, |
304 | | const gx_drawing_color *pdcolor, gs_logical_operation_t lop) |
305 | 0 | { |
306 | 0 | if (dev->child) |
307 | 0 | return dev_proc(dev->child, fill_triangle)(dev->child, px, py, ax, ay, bx, by, pdcolor, lop); |
308 | | /* else */ |
309 | 0 | return gx_default_fill_triangle(dev, px, py, ax, ay, bx, by, pdcolor, lop); |
310 | 0 | } |
311 | | |
312 | | int default_subclass_draw_thin_line(gx_device *dev, fixed fx0, fixed fy0, fixed fx1, fixed fy1, |
313 | | const gx_drawing_color *pdcolor, gs_logical_operation_t lop, |
314 | | fixed adjustx, fixed adjusty) |
315 | 0 | { |
316 | 0 | if (dev->child) |
317 | 0 | return dev_proc(dev->child, draw_thin_line)(dev->child, fx0, fy0, fx1, fy1, pdcolor, lop, adjustx, adjusty); |
318 | | /* else */ |
319 | 0 | return gx_default_draw_thin_line(dev, fx0, fy0, fx1, fy1, pdcolor, lop, adjustx, adjusty); |
320 | 0 | } |
321 | | |
322 | | int default_subclass_strip_tile_rectangle(gx_device *dev, const gx_strip_bitmap *tiles, int x, int y, int width, int height, |
323 | | gx_color_index color0, gx_color_index color1, |
324 | | int phase_x, int phase_y) |
325 | 0 | { |
326 | 0 | if (dev->child) |
327 | 0 | return dev_proc(dev->child, strip_tile_rectangle)(dev->child, tiles, x, y, width, height, color0, color1, phase_x, phase_y); |
328 | | /* else */ |
329 | 0 | return gx_default_strip_tile_rectangle(dev, tiles, x, y, width, height, color0, color1, phase_x, phase_y); |
330 | 0 | } |
331 | | |
332 | | void default_subclass_get_clipping_box(gx_device *dev, gs_fixed_rect *pbox) |
333 | 637 | { |
334 | 637 | if (dev->child) { |
335 | 637 | dev_proc(dev->child, get_clipping_box)(dev->child, pbox); |
336 | 637 | } else |
337 | 0 | gx_default_get_clipping_box(dev, pbox); |
338 | | |
339 | 637 | return; |
340 | 637 | } |
341 | | |
342 | | int default_subclass_begin_typed_image(gx_device *dev, const gs_gstate *pgs, const gs_matrix *pmat, |
343 | | const gs_image_common_t *pic, const gs_int_rect *prect, |
344 | | const gx_drawing_color *pdcolor, const gx_clip_path *pcpath, |
345 | | gs_memory_t *memory, gx_image_enum_common_t **pinfo) |
346 | 221k | { |
347 | 221k | if (dev->child) |
348 | 221k | return dev_proc(dev->child, begin_typed_image)(dev->child, pgs, pmat, pic, prect, pdcolor, pcpath, memory, pinfo); |
349 | | /* else */ |
350 | 0 | return gx_default_begin_typed_image(dev, pgs, pmat, pic, prect, pdcolor, pcpath, memory, pinfo); |
351 | 221k | } |
352 | | |
353 | | int default_subclass_get_bits_rectangle(gx_device *dev, const gs_int_rect *prect, |
354 | | gs_get_bits_params_t *params) |
355 | 0 | { |
356 | 0 | if (dev->child) |
357 | 0 | return dev_proc(dev->child, get_bits_rectangle)(dev->child, prect, params); |
358 | | /* else */ |
359 | 0 | return gx_default_get_bits_rectangle(dev, prect, params); |
360 | 0 | } |
361 | | |
362 | | static void subclass_composite_front_finalize(gx_device *dev) |
363 | 0 | { |
364 | 0 | generic_subclass_data *psubclass_data = (generic_subclass_data *)dev->parent->subclass_data; |
365 | |
|
366 | 0 | if (psubclass_data->pre_composite_device != NULL) |
367 | 0 | dev->parent->child = psubclass_data->pre_composite_device; |
368 | 0 | rc_increment(psubclass_data->pre_composite_device); |
369 | 0 | if (psubclass_data->saved_finalize_method != NULL) |
370 | 0 | psubclass_data->saved_finalize_method(dev); |
371 | 0 | } |
372 | | |
373 | | int default_subclass_composite_front(gx_device *dev, gx_device **pcdev, const gs_composite_t *pcte, |
374 | | gs_gstate *pgs, gs_memory_t *memory, gx_device *cdev) |
375 | 0 | { |
376 | 0 | int code = 0; |
377 | 0 | gs_pdf14trans_t *pct = (gs_pdf14trans_t *)pcte; |
378 | 0 | generic_subclass_data *psubclass_data = (generic_subclass_data *)dev->subclass_data; |
379 | 0 | gx_device *thisdev = dev; |
380 | |
|
381 | 0 | if (dev->child) { |
382 | 0 | code = dev_proc(dev->child, composite)(dev->child, pcdev, pcte, pgs, memory, cdev); |
383 | 0 | if (code < 0) |
384 | 0 | return code; |
385 | | |
386 | 0 | if (gs_is_overprint_compositor(pcte)) |
387 | 0 | { |
388 | | /* *pcdev is always returned containing a device capable of doing |
389 | | * compositing. This may mean it is a new device. If this wants |
390 | | * to be the new 'device' in the graphics state, then code will |
391 | | * return as 1. */ |
392 | 0 | if (code == 1) { |
393 | | /* We want this device to stay ahead of the compositor; the newly created compositor has |
394 | | * inserted itself in front of our child device, so basically we want to replace |
395 | | * our current child with the newly created compositor. I hope ! |
396 | | */ |
397 | 0 | psubclass_data = (generic_subclass_data *)dev->subclass_data; |
398 | 0 | if (psubclass_data == NULL) |
399 | 0 | return_error(gs_error_undefined); |
400 | 0 | psubclass_data->pre_composite_device = dev->child; |
401 | 0 | psubclass_data->saved_finalize_method = (*pcdev)->finalize; |
402 | 0 | (*pcdev)->finalize = subclass_composite_front_finalize; |
403 | |
|
404 | 0 | (*pcdev)->child = dev->child; |
405 | 0 | dev->child->parent = *pcdev; |
406 | | /* We won't be pointing to the device anymore, so decrement the reference count */ |
407 | 0 | rc_decrement(dev->child, "default_subclass_composite_front"); |
408 | |
|
409 | 0 | dev->child = *pcdev; |
410 | 0 | (*pcdev)->parent = dev; |
411 | 0 | while (dev) { |
412 | 0 | memcpy(&dev->color_info, &(*pcdev)->color_info, sizeof(gx_device_color_info)); |
413 | 0 | dev->num_planar_planes = dev->child->num_planar_planes; |
414 | 0 | dev = dev->parent; |
415 | 0 | } |
416 | 0 | } |
417 | 0 | } |
418 | 0 | else if (gs_is_pdf14trans_compositor(pcte)) { |
419 | 0 | switch(pct->params.pdf14_op) |
420 | 0 | { |
421 | 0 | case PDF14_POP_DEVICE: |
422 | 0 | if (psubclass_data->pre_composite_device != NULL) { |
423 | 0 | if (dev->child) { |
424 | 0 | dev->child->parent = NULL; |
425 | 0 | dev->child->child = NULL; |
426 | 0 | dev->child->finalize = psubclass_data->saved_finalize_method; |
427 | 0 | rc_decrement(dev->child, "default_subclass_composite_front"); |
428 | 0 | } |
429 | 0 | dev->child = psubclass_data->pre_composite_device; |
430 | 0 | psubclass_data->pre_composite_device = NULL; |
431 | 0 | psubclass_data->saved_finalize_method = NULL; |
432 | 0 | while (dev) { |
433 | 0 | memcpy(&(dev->color_info), &(dev->child->color_info), sizeof(gx_device_color_info)); |
434 | 0 | dev->num_planar_planes = dev->child->num_planar_planes; |
435 | 0 | dev = dev->parent; |
436 | 0 | } |
437 | 0 | } |
438 | 0 | break; |
439 | 0 | case PDF14_PUSH_DEVICE: |
440 | | /* *pcdev is always returned containing a device capable of doing |
441 | | * compositing. This may mean it is a new device. If this wants |
442 | | * to be the new 'device' in the graphics state, then code will |
443 | | * return as 1. */ |
444 | 0 | if (code == 1) { |
445 | | /* We want this device to stay ahead of the compositor; the newly created compositor has |
446 | | * inserted itself in front of our child device, so basically we want to replace |
447 | | * our current child with the newly created compositor. I hope ! |
448 | | */ |
449 | 0 | psubclass_data = (generic_subclass_data *)dev->subclass_data; |
450 | 0 | if (psubclass_data == NULL) |
451 | 0 | return_error(gs_error_undefined); |
452 | 0 | psubclass_data->pre_composite_device = dev->child; |
453 | 0 | psubclass_data->saved_finalize_method = (*pcdev)->finalize; |
454 | 0 | (*pcdev)->finalize = subclass_composite_front_finalize; |
455 | |
|
456 | 0 | (*pcdev)->child = dev->child; |
457 | 0 | dev->child = *pcdev; |
458 | 0 | (*pcdev)->parent = dev; |
459 | 0 | while (dev) { |
460 | 0 | memcpy(&dev->color_info, &(*pcdev)->color_info, sizeof(gx_device_color_info)); |
461 | 0 | dev->num_planar_planes = dev->child->num_planar_planes; |
462 | 0 | dev = dev->parent; |
463 | 0 | } |
464 | 0 | } |
465 | 0 | break; |
466 | 0 | default: |
467 | | /* It seems like many operations can result in the pdf14 device altering its color |
468 | | * info, presumably as we push different blending spaces. Ick. In order to stay in sync |
469 | | * any time we have inserted a compositor after this class, we must update the color info |
470 | | * of this device after every operation, in case it changes.... |
471 | | */ |
472 | 0 | if (psubclass_data->pre_composite_device != NULL) { |
473 | 0 | while (dev) { |
474 | 0 | memcpy(&(dev->color_info), &(dev->child->color_info), sizeof(gx_device_color_info)); |
475 | 0 | dev->num_planar_planes = dev->child->num_planar_planes; |
476 | 0 | dev = dev->parent; |
477 | 0 | } |
478 | 0 | } |
479 | 0 | break; |
480 | 0 | } |
481 | 0 | } |
482 | | /* We are inserting the compositor code after this device, or the compositor |
483 | | * did not create a new compositor. Either way we don't want the compositor code |
484 | | * to think we want to push a new device, so just return this device to the caller. |
485 | | */ |
486 | 0 | *pcdev = thisdev; |
487 | 0 | return 0; |
488 | 0 | } |
489 | 0 | return 0; |
490 | 0 | } |
491 | | |
492 | | int default_subclass_composite(gx_device *dev, gx_device **pcdev, const gs_composite_t *pcte, |
493 | | gs_gstate *pgs, gs_memory_t *memory, gx_device *cdev) |
494 | 123k | { |
495 | 123k | int code; |
496 | | |
497 | 123k | if (dev->child) { |
498 | | /* Some more unpleasantness here. If the child device is a clist, then it will use the first argument |
499 | | * that we pass to access its own data (not unreasonably), so we need to make sure we pass in the |
500 | | * child device. This has some follow on implications detailed below. |
501 | | */ |
502 | 123k | code = dev_proc(dev->child, composite)(dev->child, pcdev, pcte, pgs, memory, cdev); |
503 | 123k | if (code < 0) |
504 | 1 | return code; |
505 | | |
506 | | /* *pcdev is always returned containing a device capable of doing |
507 | | * compositing. This may mean it is a new device. If this wants |
508 | | * to be the new 'device' in the graphics state, then code will |
509 | | * return as 1. */ |
510 | 123k | if (code == 1) { |
511 | | /* The device chain on entry to this function was: |
512 | | * dev(the subclassing device) -> child. |
513 | | * But now we also have: |
514 | | * *pcdev -> child. |
515 | | * Or in some cases: |
516 | | * *pcdev (-> other device)* -> child |
517 | | * Most callers would be happy to make dev->child = *pcdev, |
518 | | * thus giving us: |
519 | | * dev -> *pcdev (-> other device)* ->child |
520 | | * Unfortunately, we are not happy with that. We need to |
521 | | * remain tightly bound to the child. i.e. we are aiming for: |
522 | | * *pcdev (-> other device)* -> dev -> child |
523 | | * Accordingly, we need to move ourselves within the device |
524 | | * chain. |
525 | | */ |
526 | 2.58k | gx_device *penult = *pcdev; |
527 | | |
528 | 2.58k | if (penult == NULL) { |
529 | | /* This should never happen. */ |
530 | 0 | return gs_error_unknownerror; |
531 | 0 | } |
532 | | |
533 | | /* Find the penultimate device. */ |
534 | 7.44k | while (1) { |
535 | 7.44k | gxdso_device_child_request req; |
536 | 7.44k | req.target = penult; |
537 | 7.44k | req.n = 0; |
538 | 7.44k | code = dev_proc(penult, dev_spec_op)(penult, gxdso_device_child, &req, sizeof(req)); |
539 | 7.44k | if (code < 0) |
540 | 0 | return code; |
541 | 7.44k | if (req.target == NULL) { |
542 | | /* Wooah! Where was dev->child? */ |
543 | 0 | return gs_error_unknownerror; |
544 | 0 | } |
545 | 7.44k | if (req.target == dev->child) |
546 | 2.58k | break; /* penult is the parent. */ |
547 | 4.86k | penult = req.target; |
548 | 4.86k | } |
549 | | |
550 | 2.58k | if (penult == NULL) { |
551 | | /* This should never happen. We know that we've just |
552 | | * had a compositor inserted before dev->child, so there |
553 | | * really ought to be one! */ |
554 | 0 | return gs_error_unknownerror; |
555 | 0 | } |
556 | | |
557 | | /* We already point to dev->child, and hence own a reference |
558 | | * to it. */ |
559 | | |
560 | | /* Now insert ourselves as the child of the penultimate one. */ |
561 | 2.58k | code = dev_proc(penult, dev_spec_op)(penult, gxdso_device_insert_child, dev, 0); |
562 | 2.58k | if (code < 0) |
563 | 0 | return code; |
564 | | |
565 | | /* Now we want our caller to update itself to recognise that |
566 | | * *pcdev should be its child, not dev. So we return 1. */ |
567 | 2.58k | return 1; |
568 | 2.58k | } |
569 | 121k | else { |
570 | | /* See the 2 comments above. Now, if the child did not create a new compositor (eg its a clist) |
571 | | * then it returns pcdev pointing to the passed in device (the child in our case). Now this is a |
572 | | * problem, if we return with pcdev == child->dev, and the current device is 'dev' then the |
573 | | * compositor code will think we wanted to push a new device and will select the child device. |
574 | | * so here if pcdev == dev->child we change it to be our own device, so that the calling code |
575 | | * won't redirect the device in the graphics state. |
576 | | */ |
577 | 121k | *pcdev = dev; |
578 | 121k | return code; |
579 | 121k | } |
580 | 123k | } |
581 | 0 | return 0; |
582 | 123k | } |
583 | | |
584 | | int default_subclass_get_hardware_params(gx_device *dev, gs_param_list *plist) |
585 | 0 | { |
586 | 0 | if (dev->child) |
587 | 0 | return dev_proc(dev->child, get_hardware_params)(dev->child, plist); |
588 | | /* else */ |
589 | 0 | return gx_default_get_hardware_params(dev, plist); |
590 | 0 | } |
591 | | |
592 | | int default_subclass_text_begin(gx_device *dev, gs_gstate *pgs, const gs_text_params_t *text, |
593 | | gs_font *font, const gx_clip_path *pcpath, |
594 | | gs_text_enum_t **ppte) |
595 | 1.62M | { |
596 | 1.62M | if (dev->child) |
597 | 1.62M | return dev_proc(dev->child, text_begin)(dev->child, pgs, text, font, pcpath, ppte); |
598 | | /* else */ |
599 | 0 | return gx_default_text_begin(dev, pgs, text, font, pcpath, ppte); |
600 | 1.62M | } |
601 | | |
602 | | int default_subclass_begin_transparency_group(gx_device *dev, const gs_transparency_group_params_t *ptgp, |
603 | | const gs_rect *pbbox, gs_gstate *pgs, gs_memory_t *mem) |
604 | 0 | { |
605 | 0 | if (dev->child) |
606 | 0 | return dev_proc(dev->child, begin_transparency_group)(dev->child, ptgp, pbbox, pgs, mem); |
607 | | |
608 | 0 | return 0; |
609 | 0 | } |
610 | | |
611 | | int default_subclass_end_transparency_group(gx_device *dev, gs_gstate *pgs) |
612 | 0 | { |
613 | 0 | if (dev->child) |
614 | 0 | return dev_proc(dev->child, end_transparency_group)(dev->child, pgs); |
615 | | |
616 | 0 | return 0; |
617 | 0 | } |
618 | | |
619 | | int default_subclass_begin_transparency_mask(gx_device *dev, const gx_transparency_mask_params_t *ptmp, |
620 | | const gs_rect *pbbox, gs_gstate *pgs, gs_memory_t *mem) |
621 | 0 | { |
622 | 0 | if (dev->child) |
623 | 0 | return dev_proc(dev->child, begin_transparency_mask)(dev->child, ptmp, pbbox, pgs, mem); |
624 | | |
625 | 0 | return 0; |
626 | 0 | } |
627 | | |
628 | | int default_subclass_end_transparency_mask(gx_device *dev, gs_gstate *pgs) |
629 | 0 | { |
630 | 0 | if (dev->child) |
631 | 0 | return dev_proc(dev->child, end_transparency_mask)(dev->child, pgs); |
632 | | |
633 | 0 | return 0; |
634 | 0 | } |
635 | | |
636 | | int default_subclass_discard_transparency_layer(gx_device *dev, gs_gstate *pgs) |
637 | 0 | { |
638 | 0 | if (dev->child) |
639 | 0 | return dev_proc(dev->child, discard_transparency_layer)(dev->child, pgs); |
640 | | |
641 | 0 | return 0; |
642 | 0 | } |
643 | | |
644 | | const gx_cm_color_map_procs *default_subclass_get_color_mapping_procs(const gx_device *dev, |
645 | | const gx_device **tdev) |
646 | 2.86M | { |
647 | 2.86M | if (dev->child) |
648 | 2.86M | return dev_proc(dev->child, get_color_mapping_procs)(dev->child, tdev); |
649 | | /* else */ |
650 | 0 | return gx_default_DevGray_get_color_mapping_procs(dev, tdev); |
651 | 2.86M | } |
652 | | |
653 | | int default_subclass_get_color_comp_index(gx_device *dev, const char * pname, int name_size, int component_type) |
654 | 15.4k | { |
655 | 15.4k | if (dev->child) |
656 | 15.4k | return dev_proc(dev->child, get_color_comp_index)(dev->child, pname, name_size, component_type); |
657 | | /* else */ |
658 | 0 | return gx_error_get_color_comp_index(dev, pname, name_size, component_type); |
659 | 15.4k | } |
660 | | |
661 | | gx_color_index default_subclass_encode_color(gx_device *dev, const gx_color_value colors[]) |
662 | 3.13M | { |
663 | 3.13M | if (dev->child) |
664 | 3.13M | return dev_proc(dev->child, encode_color)(dev->child, colors); |
665 | | /* else */ |
666 | 0 | return gx_error_encode_color(dev, colors); |
667 | 3.13M | } |
668 | | |
669 | | int default_subclass_decode_color(gx_device *dev, gx_color_index cindex, gx_color_value colors[]) |
670 | 0 | { |
671 | 0 | if (dev->child) |
672 | 0 | return dev_proc(dev->child, decode_color)(dev->child, cindex, colors); |
673 | 0 | else { |
674 | 0 | memset(colors, 0, sizeof(gx_color_value[GX_DEVICE_COLOR_MAX_COMPONENTS])); |
675 | 0 | } |
676 | | |
677 | 0 | return 0; |
678 | 0 | } |
679 | | |
680 | | int default_subclass_fill_rectangle_hl_color(gx_device *dev, const gs_fixed_rect *rect, |
681 | | const gs_gstate *pgs, const gx_drawing_color *pdcolor, const gx_clip_path *pcpath) |
682 | 0 | { |
683 | 0 | if (dev->child) |
684 | 0 | return dev_proc(dev->child, fill_rectangle_hl_color)(dev->child, rect, pgs, pdcolor, pcpath); |
685 | | /* else */ |
686 | 0 | return_error(gs_error_rangecheck); |
687 | 0 | } |
688 | | |
689 | | int default_subclass_include_color_space(gx_device *dev, gs_color_space *cspace, const byte *res_name, int name_length) |
690 | 0 | { |
691 | 0 | if (dev->child) |
692 | 0 | return dev_proc(dev->child, include_color_space)(dev->child, cspace, res_name, name_length); |
693 | | |
694 | 0 | return 0; |
695 | 0 | } |
696 | | |
697 | | int default_subclass_fill_linear_color_scanline(gx_device *dev, const gs_fill_attributes *fa, |
698 | | int i, int j, int w, const frac31 *c0, const int32_t *c0_f, const int32_t *cg_num, |
699 | | int32_t cg_den) |
700 | 0 | { |
701 | 0 | if (dev->child) |
702 | 0 | return dev_proc(dev->child, fill_linear_color_scanline)(dev->child, fa, i, j, w, c0, c0_f, cg_num, cg_den); |
703 | | /* else */ |
704 | 0 | return gx_default_fill_linear_color_scanline(dev, fa, i, j, w, c0, c0_f, cg_num, cg_den); |
705 | 0 | } |
706 | | |
707 | | int default_subclass_fill_linear_color_trapezoid(gx_device *dev, const gs_fill_attributes *fa, |
708 | | const gs_fixed_point *p0, const gs_fixed_point *p1, |
709 | | const gs_fixed_point *p2, const gs_fixed_point *p3, |
710 | | const frac31 *c0, const frac31 *c1, |
711 | | const frac31 *c2, const frac31 *c3) |
712 | 0 | { |
713 | 0 | if (dev->child) |
714 | 0 | return dev_proc(dev->child, fill_linear_color_trapezoid)(dev->child, fa, p0, p1, p2, p3, c0, c1, c2, c3); |
715 | | /* else */ |
716 | 0 | return gx_default_fill_linear_color_trapezoid(dev, fa, p0, p1, p2, p3, c0, c1, c2, c3); |
717 | 0 | } |
718 | | |
719 | | int default_subclass_fill_linear_color_triangle(gx_device *dev, const gs_fill_attributes *fa, |
720 | | const gs_fixed_point *p0, const gs_fixed_point *p1, |
721 | | const gs_fixed_point *p2, const frac31 *c0, const frac31 *c1, const frac31 *c2) |
722 | 0 | { |
723 | 0 | if (dev->child) |
724 | 0 | return dev_proc(dev->child, fill_linear_color_triangle)(dev->child, fa, p0, p1, p2, c0, c1, c2); |
725 | | /* else */ |
726 | 0 | return gx_default_fill_linear_color_triangle(dev, fa, p0, p1, p2, c0, c1, c2); |
727 | 0 | } |
728 | | |
729 | | int default_subclass_update_spot_equivalent_colors(gx_device *dev, const gs_gstate * pgs, const gs_color_space *pcs) |
730 | 127 | { |
731 | 127 | if (dev->child) |
732 | 127 | return dev_proc(dev->child, update_spot_equivalent_colors)(dev->child, pgs, pcs); |
733 | | |
734 | 0 | return 0; |
735 | 127 | } |
736 | | |
737 | | gs_devn_params *default_subclass_ret_devn_params(gx_device *dev) |
738 | 5.01k | { |
739 | 5.01k | if (dev->child) |
740 | 5.01k | return dev_proc(dev->child, ret_devn_params)(dev->child); |
741 | | |
742 | 0 | return 0; |
743 | 5.01k | } |
744 | | |
745 | | int default_subclass_fillpage(gx_device *dev, gs_gstate * pgs, gx_device_color *pdevc) |
746 | 0 | { |
747 | 0 | if (dev->child) |
748 | 0 | return dev_proc(dev->child, fillpage)(dev->child, pgs, pdevc); |
749 | | /* else */ |
750 | 0 | return gx_default_fillpage(dev, pgs, pdevc); |
751 | 0 | } |
752 | | |
753 | | int default_subclass_push_transparency_state(gx_device *dev, gs_gstate *pgs) |
754 | 0 | { |
755 | 0 | if (dev->child) |
756 | 0 | return dev_proc(dev->child, push_transparency_state)(dev->child, pgs); |
757 | | |
758 | 0 | return 0; |
759 | 0 | } |
760 | | |
761 | | int default_subclass_pop_transparency_state(gx_device *dev, gs_gstate *pgs) |
762 | 0 | { |
763 | 0 | if (dev->child) |
764 | 0 | return dev_proc(dev->child, pop_transparency_state)(dev->child, pgs); |
765 | | |
766 | 0 | return 0; |
767 | 0 | } |
768 | | |
769 | | int default_subclass_put_image(gx_device *dev, gx_device *mdev, const byte **buffers, int num_chan, int x, int y, |
770 | | int width, int height, int row_stride, |
771 | | int alpha_plane_index, int tag_plane_index) |
772 | 0 | { |
773 | 0 | if (dev->child) { |
774 | 0 | if (dev == mdev) { |
775 | 0 | return dev_proc(dev->child, put_image)(dev->child, dev->child, buffers, num_chan, x, y, width, height, row_stride, alpha_plane_index, tag_plane_index); |
776 | 0 | } |
777 | 0 | else { |
778 | 0 | return dev_proc(dev->child, put_image)(dev->child, mdev, buffers, num_chan, x, y, width, height, row_stride, alpha_plane_index, tag_plane_index); |
779 | 0 | } |
780 | 0 | } |
781 | 0 | return 0; |
782 | 0 | } |
783 | | |
784 | | int default_subclass_dev_spec_op(gx_device *dev, int op, void *data, int datasize) |
785 | 23.2M | { |
786 | 23.2M | if (op == gxdso_is_clist_device) |
787 | 0 | return 0; |
788 | 23.2M | if (op == gxdso_device_child) { |
789 | 0 | gxdso_device_child_request *d = (gxdso_device_child_request *)data; |
790 | 0 | if (d->target == dev) { |
791 | 0 | d->target = dev->child; |
792 | 0 | return 1; |
793 | 0 | } |
794 | 0 | } |
795 | 23.2M | if (dev->child) |
796 | 23.2M | return dev_proc(dev->child, dev_spec_op)(dev->child, op, data, datasize); |
797 | | |
798 | 0 | return 0; |
799 | 23.2M | } |
800 | | |
801 | | int default_subclass_copy_planes(gx_device *dev, const byte *data, int data_x, int raster, gx_bitmap_id id, |
802 | | int x, int y, int width, int height, int plane_height) |
803 | 0 | { |
804 | 0 | if (dev->child) |
805 | 0 | return dev_proc(dev->child, copy_planes)(dev->child, data, data_x, raster, id, x, y, width, height, plane_height); |
806 | | |
807 | 0 | return 0; |
808 | 0 | } |
809 | | |
810 | | int default_subclass_get_profile(const gx_device *dev, cmm_dev_profile_t **dev_profile) |
811 | 13.5M | { |
812 | 13.5M | if (dev->child) { |
813 | 13.5M | return dev_proc(dev->child, get_profile)(dev->child, dev_profile); |
814 | 13.5M | } |
815 | | /* else */ |
816 | 0 | return gx_default_get_profile(dev, dev_profile); |
817 | 13.5M | } |
818 | | |
819 | | /* In a delightful asymmetry, we have a set_graphics_type_tag, but no get_graphics_type_tag. Instead |
820 | | * (shudder) the code pulls the currently encoded colour and tag *directly* from the current device. |
821 | | * This means we have to copy the ENCODE_TAGS from the device we are subclassing, into the device which |
822 | | * is newly created at installation time. We also have to have our default set_graphics_type_tag method |
823 | | * update its graphics_type_tag, even though this device has no interest in it, just in case we happen |
824 | | * to be the top device in the chain...... |
825 | | */ |
826 | | |
827 | | void default_subclass_set_graphics_type_tag(gx_device *dev, gs_graphics_type_tag_t tag) |
828 | 807k | { |
829 | | /* |
830 | | * AIUI we should not be calling this method *unless* the ENCODE_TAGS bit is set, so we don't need |
831 | | * to do any checking. Just set the supplied tag in the current device, and pass it on to the underlying |
832 | | * device(s). This line is a direct copy from gx_default_set_graphics_type_tag. |
833 | | */ |
834 | 807k | dev->graphics_type_tag = (dev->graphics_type_tag & GS_DEVICE_ENCODES_TAGS) | tag; |
835 | | |
836 | 807k | if (dev->child) |
837 | 807k | dev_proc(dev->child, set_graphics_type_tag)(dev->child, tag); |
838 | | |
839 | 807k | return; |
840 | 807k | } |
841 | | |
842 | | int default_subclass_strip_copy_rop2(gx_device *dev, const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id, |
843 | | const gx_color_index *scolors, const gx_strip_bitmap *textures, const gx_color_index *tcolors, |
844 | | int x, int y, int width, int height, int phase_x, int phase_y, gs_logical_operation_t lop, uint planar_height) |
845 | 0 | { |
846 | 0 | if (!dev->child) |
847 | 0 | return 0; |
848 | | |
849 | 0 | return dev_proc(dev->child, strip_copy_rop2)(dev->child, sdata, sourcex, sraster, id, scolors, textures, tcolors, x, y, width, height, phase_x, phase_y, lop, planar_height); |
850 | 0 | } |
851 | | |
852 | | int default_subclass_strip_tile_rect_devn(gx_device *dev, const gx_strip_bitmap *tiles, int x, int y, int width, int height, |
853 | | const gx_drawing_color *pdcolor0, const gx_drawing_color *pdcolor1, int phase_x, int phase_y) |
854 | 0 | { |
855 | 0 | if (dev->child) |
856 | 0 | return dev_proc(dev->child, strip_tile_rect_devn)(dev->child, tiles, x, y, width, height, pdcolor0, pdcolor1, phase_x, phase_y); |
857 | | /* else */ |
858 | 0 | return gx_default_strip_tile_rect_devn(dev, tiles, x, y, width, height, pdcolor0, pdcolor1, phase_x, phase_y); |
859 | 0 | } |
860 | | |
861 | | int default_subclass_copy_alpha_hl_color(gx_device *dev, const byte *data, int data_x, |
862 | | int raster, gx_bitmap_id id, int x, int y, int width, int height, |
863 | | const gx_drawing_color *pdcolor, int depth) |
864 | 0 | { |
865 | 0 | if (dev->child) |
866 | 0 | return dev_proc(dev->child, copy_alpha_hl_color)(dev->child, data, data_x, raster, id, x, y, width, height, pdcolor, depth); |
867 | | /* else */ |
868 | 0 | return_error(gs_error_rangecheck); |
869 | 0 | } |
870 | | |
871 | | int default_subclass_process_page(gx_device *dev, gx_process_page_options_t *options) |
872 | 0 | { |
873 | 0 | if (dev->child) |
874 | 0 | return dev_proc(dev->child, process_page)(dev->child, options); |
875 | | |
876 | 0 | return 0; |
877 | 0 | } |
878 | | |
879 | | int default_subclass_fill_stroke_path(gx_device *dev, const gs_gstate *pgs, gx_path *ppath, |
880 | | const gx_fill_params *fill_params, const gx_drawing_color *pdcolor_fill, |
881 | | const gx_stroke_params *stroke_params, const gx_drawing_color *pdcolor_stroke, |
882 | | const gx_clip_path *pcpath) |
883 | 17.8k | { |
884 | 17.8k | if (dev->child) |
885 | 17.8k | return dev_proc(dev->child, fill_stroke_path)(dev->child, pgs, ppath, fill_params, pdcolor_fill, |
886 | 17.8k | stroke_params, pdcolor_stroke, pcpath); |
887 | 0 | return 0; |
888 | 17.8k | } |
889 | | |
890 | | int default_subclass_lock_pattern(gx_device *dev, gs_gstate *pgs, gs_id pattern_id, int lock) |
891 | 188 | { |
892 | 188 | if (dev->child) |
893 | 188 | return dev_proc(dev->child, lock_pattern)(dev->child, pgs, pattern_id, lock); |
894 | 0 | return 0; |
895 | 188 | } |
896 | | |
897 | | int default_subclass_transform_pixel_region(gx_device *dev, transform_pixel_region_reason reason, transform_pixel_region_data *data) |
898 | 0 | { |
899 | 0 | if (dev->child) |
900 | 0 | return dev_proc(dev->child, transform_pixel_region)(dev->child, reason, data); |
901 | | |
902 | 0 | return gs_error_unknownerror; |
903 | 0 | } |
904 | | |
905 | | void default_subclass_finalize(const gs_memory_t *cmem, void *vptr) |
906 | 34.9k | { |
907 | 34.9k | gx_device * const dev = (gx_device *)vptr; |
908 | 34.9k | generic_subclass_data *psubclass_data = (generic_subclass_data *)dev->subclass_data; |
909 | 34.9k | (void)cmem; /* unused */ |
910 | | |
911 | 34.9k | discard(gs_closedevice(dev)); |
912 | | |
913 | 34.9k | if (dev->finalize) |
914 | 0 | dev->finalize(dev); |
915 | | |
916 | | /* The only way we should get here is when the original device |
917 | | * should be freed (because the subclassing device is pretending |
918 | | * to be the original device). That being the case, all the child |
919 | | * devices should have a reference count of 1 (referenced only by |
920 | | * their parent). Anything else is an error. |
921 | | */ |
922 | 34.9k | if (dev->child != NULL) { |
923 | 34.9k | if (dev->child->rc.ref_count != 1) { |
924 | 0 | dmprintf(dev->memory, "Error: finalizing subclassing device while child refcount > 1\n"); |
925 | 0 | while (dev->child->rc.ref_count != 1) |
926 | 0 | rc_decrement_only(dev->child, "de-reference child device"); |
927 | 0 | } |
928 | 34.9k | rc_decrement(dev->child, "de-reference child device"); |
929 | 34.9k | } |
930 | | |
931 | 34.9k | if (psubclass_data) { |
932 | 34.9k | gs_free_object(dev->memory->non_gc_memory, psubclass_data, "gx_epo_finalize(suclass data)"); |
933 | 34.9k | dev->subclass_data = NULL; |
934 | 34.9k | } |
935 | 34.9k | if (dev->stype_is_dynamic) |
936 | 34.9k | gs_free_const_object(dev->memory->non_gc_memory, dev->stype, |
937 | 34.9k | "default_subclass_finalize"); |
938 | 34.9k | if (dev->icc_struct) |
939 | 34.9k | rc_decrement(dev->icc_struct, "finalize subclass device"); |
940 | 34.9k | if (dev->PageList) |
941 | 34.9k | rc_decrement(dev->PageList, "finalize subclass device"); |
942 | 34.9k | if (dev->NupControl) |
943 | 34.9k | rc_decrement(dev->NupControl, "finalize subclass device"); |
944 | 34.9k | } |
945 | | |
946 | | void default_subclass_initialize_device_procs(gx_device *dev) |
947 | 34.9k | { |
948 | 34.9k | set_dev_proc(dev, open_device, default_subclass_open_device); |
949 | 34.9k | set_dev_proc(dev, get_initial_matrix, default_subclass_get_initial_matrix); |
950 | 34.9k | set_dev_proc(dev, sync_output, default_subclass_sync_output); |
951 | 34.9k | set_dev_proc(dev, output_page, default_subclass_output_page); |
952 | 34.9k | set_dev_proc(dev, close_device, default_subclass_close_device); |
953 | 34.9k | set_dev_proc(dev, map_rgb_color, default_subclass_map_rgb_color); |
954 | 34.9k | set_dev_proc(dev, map_color_rgb, default_subclass_map_color_rgb); |
955 | 34.9k | set_dev_proc(dev, fill_rectangle, default_subclass_fill_rectangle); |
956 | 34.9k | set_dev_proc(dev, copy_mono, default_subclass_copy_mono); |
957 | 34.9k | set_dev_proc(dev, copy_color, default_subclass_copy_color); |
958 | 34.9k | set_dev_proc(dev, get_params, default_subclass_get_params); |
959 | 34.9k | set_dev_proc(dev, put_params, default_subclass_put_params); |
960 | 34.9k | set_dev_proc(dev, map_cmyk_color, default_subclass_map_cmyk_color); |
961 | 34.9k | set_dev_proc(dev, get_page_device, default_subclass_get_page_device); |
962 | 34.9k | set_dev_proc(dev, get_alpha_bits, default_subclass_get_alpha_bits); |
963 | 34.9k | set_dev_proc(dev, copy_alpha, default_subclass_copy_alpha); |
964 | 34.9k | set_dev_proc(dev, fill_path, default_subclass_fill_path); |
965 | 34.9k | set_dev_proc(dev, stroke_path, default_subclass_stroke_path); |
966 | 34.9k | set_dev_proc(dev, fill_mask, default_subclass_fill_mask); |
967 | 34.9k | set_dev_proc(dev, fill_trapezoid, default_subclass_fill_trapezoid); |
968 | 34.9k | set_dev_proc(dev, fill_parallelogram, default_subclass_fill_parallelogram); |
969 | 34.9k | set_dev_proc(dev, fill_triangle, default_subclass_fill_triangle); |
970 | 34.9k | set_dev_proc(dev, draw_thin_line, default_subclass_draw_thin_line); |
971 | 34.9k | set_dev_proc(dev, strip_tile_rectangle, default_subclass_strip_tile_rectangle); |
972 | 34.9k | set_dev_proc(dev, get_clipping_box, default_subclass_get_clipping_box); |
973 | 34.9k | set_dev_proc(dev, begin_typed_image, default_subclass_begin_typed_image); |
974 | 34.9k | set_dev_proc(dev, get_bits_rectangle, default_subclass_get_bits_rectangle); |
975 | 34.9k | set_dev_proc(dev, composite, default_subclass_composite); |
976 | 34.9k | set_dev_proc(dev, get_hardware_params, default_subclass_get_hardware_params); |
977 | 34.9k | set_dev_proc(dev, text_begin, default_subclass_text_begin); |
978 | 34.9k | set_dev_proc(dev, begin_transparency_group, default_subclass_begin_transparency_group); |
979 | 34.9k | set_dev_proc(dev, end_transparency_group, default_subclass_end_transparency_group); |
980 | 34.9k | set_dev_proc(dev, begin_transparency_mask, default_subclass_begin_transparency_mask); |
981 | 34.9k | set_dev_proc(dev, end_transparency_mask, default_subclass_end_transparency_mask); |
982 | 34.9k | set_dev_proc(dev, discard_transparency_layer, default_subclass_discard_transparency_layer); |
983 | 34.9k | set_dev_proc(dev, get_color_mapping_procs, default_subclass_get_color_mapping_procs); |
984 | 34.9k | set_dev_proc(dev, get_color_comp_index, default_subclass_get_color_comp_index); |
985 | 34.9k | set_dev_proc(dev, encode_color, default_subclass_encode_color); |
986 | 34.9k | set_dev_proc(dev, decode_color, default_subclass_decode_color); |
987 | 34.9k | set_dev_proc(dev, fill_rectangle_hl_color, default_subclass_fill_rectangle_hl_color); |
988 | 34.9k | set_dev_proc(dev, include_color_space, default_subclass_include_color_space); |
989 | 34.9k | set_dev_proc(dev, fill_linear_color_scanline, default_subclass_fill_linear_color_scanline); |
990 | 34.9k | set_dev_proc(dev, fill_linear_color_trapezoid, default_subclass_fill_linear_color_trapezoid); |
991 | 34.9k | set_dev_proc(dev, fill_linear_color_triangle, default_subclass_fill_linear_color_triangle); |
992 | 34.9k | set_dev_proc(dev, update_spot_equivalent_colors, default_subclass_update_spot_equivalent_colors); |
993 | 34.9k | set_dev_proc(dev, ret_devn_params, default_subclass_ret_devn_params); |
994 | 34.9k | set_dev_proc(dev, fillpage, default_subclass_fillpage); |
995 | 34.9k | set_dev_proc(dev, push_transparency_state, default_subclass_push_transparency_state); |
996 | 34.9k | set_dev_proc(dev, pop_transparency_state, default_subclass_pop_transparency_state); |
997 | 34.9k | set_dev_proc(dev, put_image, default_subclass_put_image); |
998 | 34.9k | set_dev_proc(dev, dev_spec_op, default_subclass_dev_spec_op); |
999 | 34.9k | set_dev_proc(dev, copy_planes, default_subclass_copy_planes); |
1000 | 34.9k | set_dev_proc(dev, get_profile, default_subclass_get_profile); |
1001 | 34.9k | set_dev_proc(dev, set_graphics_type_tag, default_subclass_set_graphics_type_tag); |
1002 | 34.9k | set_dev_proc(dev, strip_copy_rop2, default_subclass_strip_copy_rop2); |
1003 | 34.9k | set_dev_proc(dev, strip_tile_rect_devn, default_subclass_strip_tile_rect_devn); |
1004 | 34.9k | set_dev_proc(dev, copy_alpha_hl_color, default_subclass_copy_alpha_hl_color); |
1005 | 34.9k | set_dev_proc(dev, process_page, default_subclass_process_page); |
1006 | 34.9k | set_dev_proc(dev, transform_pixel_region, default_subclass_transform_pixel_region); |
1007 | 34.9k | set_dev_proc(dev, fill_stroke_path, default_subclass_fill_stroke_path); |
1008 | 34.9k | set_dev_proc(dev, lock_pattern, default_subclass_lock_pattern); |
1009 | 34.9k | } |
1010 | | |
1011 | | int |
1012 | | default_subclass_install(gx_device *dev, gs_gstate *pgs) |
1013 | 0 | { |
1014 | 0 | dev = dev->child; |
1015 | 0 | return dev->page_procs.install(dev, pgs); |
1016 | 0 | } |
1017 | | |
1018 | | int |
1019 | | default_subclass_begin_page(gx_device *dev, gs_gstate *pgs) |
1020 | 0 | { |
1021 | 0 | dev = dev->child; |
1022 | 0 | return dev->page_procs.begin_page(dev, pgs); |
1023 | 0 | } |
1024 | | |
1025 | | int |
1026 | | default_subclass_end_page(gx_device *dev, int reason, gs_gstate *pgs) |
1027 | 0 | { |
1028 | 0 | dev = dev->child; |
1029 | 0 | return dev->page_procs.end_page(dev, reason, pgs); |
1030 | 0 | } |
1031 | | |
1032 | | void gx_subclass_fill_in_page_procs(gx_device *dev) |
1033 | 34.9k | { |
1034 | 34.9k | if (dev->page_procs.install == NULL) |
1035 | 34.9k | dev->page_procs.install = default_subclass_install; |
1036 | 34.9k | if (dev->page_procs.begin_page == NULL) |
1037 | 34.9k | dev->page_procs.begin_page = default_subclass_begin_page; |
1038 | 34.9k | if (dev->page_procs.end_page == NULL) |
1039 | 34.9k | dev->page_procs.end_page = default_subclass_end_page; |
1040 | 34.9k | } |