1 /* Copyright (C) 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gsalphac.c,v 1.8 2005/03/14 18:08:36 dan Exp $ */
18 /* Alpha-compositing implementation */
19 #include "memory_.h"
20 #include "gx.h"
21 #include "gserrors.h"
22 #include "gsalphac.h"
23 #include "gsiparam.h" /* for gs_image_alpha_t */
24 #include "gsutil.h" /* for gs_next_ids */
25 #include "gxalpha.h"
26 #include "gxcomp.h"
27 #include "gxdevice.h"
28 #include "gxgetbit.h"
29 #include "gxlum.h"
30
31 /* ---------------- Internal definitions ---------------- */
32
33 /* Define the parameters for a compositing operation. */
34 typedef struct gs_composite_params_s {
35 gs_composite_op_t cop;
36 float delta; /* only for dissolve */
37 uint source_alpha; /* only if !psource->alpha */
38 uint source_values[4]; /* only if !psource->data */
39 } gs_composite_params_t;
40
41 /* Define the source or destination for a compositing operation. */
42 #define pixel_row_fields(elt_type)\
43 elt_type *data;\
44 int bits_per_value; /* 1, 2, 4, 8, 12, 16 */\
45 int initial_x;\
46 gs_image_alpha_t alpha
47 typedef struct pixel_row_s {
48 pixel_row_fields(byte);
49 } pixel_row_t;
50 typedef struct const_pixel_row_s {
51 pixel_row_fields(const byte);
52 } const_pixel_row_t;
53
54 /*
55 * Composite two arrays of (premultiplied) pixel values. Legal values of
56 * values_per_pixel are 1-4, not including alpha. Note that if pdest->alpha
57 * is "none", the alpha value for all destination pixels will be taken as
58 * unity, and any operation that could generate alpha values other than
59 * unity will return an error. "Could generate" means that there are
60 * possible values of the source and destination alpha values for which the
61 * result has non-unity alpha: the error check does not scan the actual
62 * alpha data to test whether there are any actual values that would
63 * generate a non-unity alpha result.
64 */
65 int composite_values(const pixel_row_t * pdest,
66 const const_pixel_row_t * psource,
67 int values_per_pixel, uint num_pixels,
68 const gs_composite_params_t * pcp);
69
70 /* ---------------- Alpha-compositing objects ---------------- */
71
72 /*
73 * Define which operations can generate non-unity alpha values in 3 of the 4
74 * cases of source and destination not having unity alphas. (This is always
75 * possible in the fourth case, both S & D non-unity, except for CLEAR.) We
76 * do this with a bit mask indexed by the operation, counting from the LSB.
77 * The name indicates whether S and/or D has non-unity alphas.
78 */
79 #define alpha_out_notS_notD\
80 (1<<composite_Dissolve)
81 #define _alpha_out_either\
82 (alpha_out_notS_notD|(1<<composite_Satop)|(1<<composite_Datop)|\
83 (1<<composite_Xor)|(1<<composite_PlusD)|(1<<composite_PlusL))
84 #define alpha_out_S_notD\
85 (_alpha_out_either|(1<<composite_Copy)|(1<<composite_Sover)|\
86 (1<<composite_Din)|(1<<composite_Dout))
87 #define alpha_out_notS_D\
88 (_alpha_out_either|(1<<composite_Sin)|(1<<composite_Sout)|\
89 (1<<composite_Dover)|(1<<composite_Highlight))
90
91 /* ------ Object definition and creation ------ */
92
93 /* Define alpha-compositing objects. */
94 private composite_create_default_compositor_proc(c_alpha_create_default_compositor);
95 private composite_equal_proc(c_alpha_equal);
96 private composite_write_proc(c_alpha_write);
97 private composite_read_proc(c_alpha_read);
98 const gs_composite_type_t gs_composite_alpha_type =
99 {
100 GX_COMPOSITOR_ALPHA,
101 {
102 c_alpha_create_default_compositor,
103 c_alpha_equal,
104 c_alpha_write,
105 c_alpha_read,
106 gx_default_composite_clist_write_update,
107 gx_default_composite_clist_read_update
108 }
109 };
110 typedef struct gs_composite_alpha_s {
111 gs_composite_common;
112 gs_composite_alpha_params_t params;
113 } gs_composite_alpha_t;
114
115 gs_private_st_simple(st_composite_alpha, gs_composite_alpha_t,
116 "gs_composite_alpha_t");
117
118 /* Create an alpha-compositing object. */
119 int
gs_create_composite_alpha(gs_composite_t ** ppcte,const gs_composite_alpha_params_t * params,gs_memory_t * mem)120 gs_create_composite_alpha(gs_composite_t ** ppcte,
121 const gs_composite_alpha_params_t * params, gs_memory_t * mem)
122 {
123 gs_composite_alpha_t *pcte;
124
125 rc_alloc_struct_0(pcte, gs_composite_alpha_t, &st_composite_alpha,
126 mem, return_error(gs_error_VMerror),
127 "gs_create_composite_alpha");
128 pcte->type = &gs_composite_alpha_type;
129 pcte->id = gs_next_ids(mem, 1);
130 pcte->params = *params;
131 *ppcte = (gs_composite_t *) pcte;
132 return 0;
133 }
134
135 /* ------ Object implementation ------ */
136
137 #define pacte ((const gs_composite_alpha_t *)pcte)
138
139 private bool
c_alpha_equal(const gs_composite_t * pcte,const gs_composite_t * pcte2)140 c_alpha_equal(const gs_composite_t * pcte, const gs_composite_t * pcte2)
141 {
142 return (pcte2->type == pcte->type &&
143 #define pacte2 ((const gs_composite_alpha_t *)pcte2)
144 pacte2->params.op == pacte->params.op &&
145 (pacte->params.op != composite_Dissolve ||
146 pacte2->params.delta == pacte->params.delta));
147 #undef pacte2
148 }
149
150 private int
c_alpha_write(const gs_composite_t * pcte,byte * data,uint * psize)151 c_alpha_write(const gs_composite_t * pcte, byte * data, uint * psize)
152 {
153 uint size = *psize;
154 uint used;
155
156 if (pacte->params.op == composite_Dissolve) {
157 used = 1 + sizeof(pacte->params.delta);
158 if (size < used) {
159 *psize = used;
160 return_error(gs_error_rangecheck);
161 }
162 memcpy(data + 1, &pacte->params.delta, sizeof(pacte->params.delta));
163 } else {
164 used = 1;
165 if (size < used) {
166 *psize = used;
167 return_error(gs_error_rangecheck);
168 }
169 }
170 *data = (byte) pacte->params.op;
171 *psize = used;
172 return 0;
173 }
174
175 private int
c_alpha_read(gs_composite_t ** ppcte,const byte * data,uint size,gs_memory_t * mem)176 c_alpha_read(gs_composite_t ** ppcte, const byte * data, uint size,
177 gs_memory_t * mem)
178 {
179 gs_composite_alpha_params_t params;
180 int code, nbytes = 1;
181
182 if (size < 1 || *data > composite_op_last)
183 return_error(gs_error_rangecheck);
184 params.op = *data;
185 if (params.op == composite_Dissolve) {
186 if (size < 1 + sizeof(params.delta))
187 return_error(gs_error_rangecheck);
188 memcpy(¶ms.delta, data + 1, sizeof(params.delta));
189 nbytes += sizeof(params.delta);
190 }
191 code = gs_create_composite_alpha(ppcte, ¶ms, mem);
192 return code < 0 ? code : nbytes;
193 }
194
195 /* ---------------- Alpha-compositing device ---------------- */
196
197 /* Define the default alpha-compositing device. */
198 typedef struct gx_device_composite_alpha_s {
199 gx_device_forward_common;
200 gs_composite_alpha_params_t params;
201 } gx_device_composite_alpha;
202
203 gs_private_st_suffix_add0_final(st_device_composite_alpha,
204 gx_device_composite_alpha, "gx_device_composite_alpha",
205 device_c_alpha_enum_ptrs, device_c_alpha_reloc_ptrs, gx_device_finalize,
206 st_device_forward);
207 /* The device descriptor. */
208 private dev_proc_close_device(dca_close);
209 private dev_proc_fill_rectangle(dca_fill_rectangle);
210 private dev_proc_map_rgb_color(dca_map_rgb_color);
211 private dev_proc_map_color_rgb(dca_map_color_rgb);
212 private dev_proc_copy_mono(dca_copy_mono);
213 private dev_proc_copy_color(dca_copy_color);
214 private dev_proc_map_rgb_alpha_color(dca_map_rgb_alpha_color);
215 private dev_proc_map_color_rgb_alpha(dca_map_color_rgb_alpha);
216 private dev_proc_copy_alpha(dca_copy_alpha);
217 private const gx_device_composite_alpha gs_composite_alpha_device =
218 {std_device_std_body_open(gx_device_composite_alpha, 0,
219 "alpha compositor", 0, 0, 1, 1),
220 {gx_default_open_device,
221 gx_forward_get_initial_matrix,
222 gx_default_sync_output,
223 gx_default_output_page,
224 dca_close,
225 dca_map_rgb_color,
226 dca_map_color_rgb,
227 dca_fill_rectangle,
228 gx_default_tile_rectangle,
229 dca_copy_mono,
230 dca_copy_color,
231 gx_default_draw_line,
232 gx_default_get_bits,
233 gx_forward_get_params,
234 gx_forward_put_params,
235 gx_default_cmyk_map_cmyk_color, /* only called for CMYK */
236 gx_forward_get_xfont_procs,
237 gx_forward_get_xfont_device,
238 dca_map_rgb_alpha_color,
239 gx_forward_get_page_device,
240 gx_forward_get_alpha_bits,
241 dca_copy_alpha,
242 gx_forward_get_band,
243 gx_default_copy_rop,
244 gx_default_fill_path,
245 gx_default_stroke_path,
246 gx_default_fill_mask,
247 gx_default_fill_trapezoid,
248 gx_default_fill_parallelogram,
249 gx_default_fill_triangle,
250 gx_default_draw_thin_line,
251 gx_default_begin_image,
252 gx_default_image_data,
253 gx_default_end_image,
254 gx_default_strip_tile_rectangle,
255 gx_default_strip_copy_rop,
256 gx_forward_get_clipping_box,
257 gx_default_begin_typed_image,
258 gx_forward_get_bits_rectangle,
259 dca_map_color_rgb_alpha,
260 gx_no_create_compositor
261 }
262 };
263
264 /* Create an alpha compositor. */
265 private int
c_alpha_create_default_compositor(const gs_composite_t * pcte,gx_device ** pcdev,gx_device * dev,gs_imager_state * pis,gs_memory_t * mem)266 c_alpha_create_default_compositor(const gs_composite_t * pcte,
267 gx_device ** pcdev, gx_device * dev, gs_imager_state * pis,
268 gs_memory_t * mem)
269 {
270 gx_device_composite_alpha *cdev;
271
272 if (pacte->params.op == composite_Copy) {
273 /* Just use the original device. */
274 *pcdev = dev;
275 return 0;
276 }
277 cdev =
278 gs_alloc_struct_immovable(mem, gx_device_composite_alpha,
279 &st_device_composite_alpha,
280 "create default alpha compositor");
281 *pcdev = (gx_device *)cdev;
282 if (cdev == 0)
283 return_error(gs_error_VMerror);
284 gx_device_init((gx_device *)cdev,
285 (const gx_device *)&gs_composite_alpha_device, mem, true);
286 gx_device_copy_params((gx_device *)cdev, dev);
287 /*
288 * Set the color_info and depth to be compatible with the target,
289 * but using standard chunky color storage, including alpha.
290 ****** CURRENTLY ALWAYS USE 8-BIT COLOR ******
291 */
292 cdev->color_info.depth =
293 (dev->color_info.num_components == 4 ? 32 /* CMYK, no alpha */ :
294 (dev->color_info.num_components + 1) * 8);
295 cdev->color_info.max_gray = cdev->color_info.max_color = 255;
296 /* No halftoning will occur, but we fill these in anyway.... */
297 cdev->color_info.dither_grays = cdev->color_info.dither_colors = 256;
298 /*
299 * We could speed things up a little by tailoring the procedures in
300 * the device to the specific num_components, but for simplicity,
301 * we'll defer considering that until there is a demonstrated need.
302 */
303 gx_device_set_target((gx_device_forward *)cdev, dev);
304 cdev->params = pacte->params;
305 return 0;
306 }
307
308 /* Close the device and free its storage. */
309 private int
dca_close(gx_device * dev)310 dca_close(gx_device * dev)
311 { /*
312 * Finalization will call close again: avoid a recursion loop.
313 */
314 set_dev_proc(dev, close_device, gx_default_close_device);
315 gs_free_object(dev->memory, dev, "dca_close");
316 return 0;
317 }
318
319 /* ------ (RGB) color mapping ------ */
320
321 private gx_color_index
dca_map_rgb_color(gx_device * dev,const gx_color_value cv[])322 dca_map_rgb_color(gx_device * dev, const gx_color_value cv[])
323 {
324 return dca_map_rgb_alpha_color(dev, cv[0], cv[1], cv[2], gx_max_color_value);
325 }
326 private gx_color_index
dca_map_rgb_alpha_color(gx_device * dev,gx_color_value red,gx_color_value green,gx_color_value blue,gx_color_value alpha)327 dca_map_rgb_alpha_color(gx_device * dev,
328 gx_color_value red, gx_color_value green, gx_color_value blue,
329 gx_color_value alpha)
330 { /*
331 * We work exclusively with premultiplied color values, so we
332 * have to premultiply the color components by alpha here.
333 */
334 byte a = gx_color_value_to_byte(alpha);
335
336 #define premult_(c)\
337 (((c) * a + gx_max_color_value / 2) / gx_max_color_value)
338 #ifdef PREMULTIPLY_TOWARDS_WHITE
339 byte bias = ~a;
340
341 # define premult(c) (premult_(c) + bias)
342 #else
343 # define premult(c) premult_(c)
344 #endif
345 gx_color_index color;
346
347 if (dev->color_info.num_components == 1) {
348 uint lum =
349 (red * lum_red_weight + green * lum_green_weight +
350 blue * lum_blue_weight + lum_all_weights / 2) /
351 lum_all_weights;
352
353 if (a == 0xff)
354 color = gx_color_value_to_byte(lum);
355 else /* Premultiplication is necessary. */
356 color = premult(lum);
357 } else {
358 if (a == 0xff)
359 color =
360 ((uint) gx_color_value_to_byte(red) << 16) +
361 ((uint) gx_color_value_to_byte(green) << 8) +
362 gx_color_value_to_byte(blue);
363 else /* Premultiplication is necessary. */
364 color =
365 (premult(red) << 16) + (premult(green) << 8) + premult(blue);
366 }
367 #undef premult
368 return (color << 8) + a;
369 }
370 private int
dca_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])371 dca_map_color_rgb(gx_device * dev, gx_color_index color,
372 gx_color_value prgb[3])
373 {
374 gx_color_value red = gx_color_value_from_byte((byte) (color >> 24));
375 byte a = (byte) color;
376
377 #define postdiv_(c)\
378 (((c) * 0xff + a / 2) / a)
379 #ifdef PREMULTIPLY_TOWARDS_WHITE
380 byte bias = ~a;
381
382 # define postdiv(c) postdiv_(c - bias)
383 #else
384 # define postdiv(c) postdiv_(c)
385 #endif
386
387 if (dev->color_info.num_components == 1) {
388 if (a != 0xff) {
389 /* Undo premultiplication. */
390 if (a == 0)
391 red = 0;
392 else
393 red = postdiv(red);
394 }
395 prgb[0] = prgb[1] = prgb[2] = red;
396 } else {
397 gx_color_value
398 green = gx_color_value_from_byte((byte) (color >> 16)),
399 blue = gx_color_value_from_byte((byte) (color >> 8));
400
401 if (a != 0xff) {
402 /* Undo premultiplication. */
403 /****** WHAT TO DO ABOUT BIG LOSS OF PRECISION? ******/
404 if (a == 0)
405 red = green = blue = 0;
406 else {
407 red = postdiv(red);
408 green = postdiv(green);
409 blue = postdiv(blue);
410 }
411 }
412 prgb[0] = red, prgb[1] = green, prgb[2] = blue;
413 }
414 #undef postdiv
415 return 0;
416 }
417 private int
dca_map_color_rgb_alpha(gx_device * dev,gx_color_index color,gx_color_value prgba[4])418 dca_map_color_rgb_alpha(gx_device * dev, gx_color_index color,
419 gx_color_value prgba[4])
420 {
421 prgba[3] = gx_color_value_from_byte((byte) color);
422 return dca_map_color_rgb(dev, color, prgba);
423 }
424
425 /* ------ Imaging ------ */
426
427 private int
dca_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)428 dca_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
429 gx_color_index color)
430 { /* This is where all the real work gets done! */
431 gx_device_composite_alpha *adev = (gx_device_composite_alpha *) dev;
432 gx_device *target = adev->target;
433 byte *std_row;
434 byte *native_row;
435 gs_int_rect rect;
436 gs_get_bits_params_t std_params, native_params;
437 int code = 0;
438 int yi;
439 gs_composite_params_t cp;
440 const_pixel_row_t source;
441 pixel_row_t dest;
442
443 fit_fill(dev, x, y, w, h);
444 std_row = gs_alloc_bytes(dev->memory,
445 (dev->color_info.depth * w + 7) >> 3,
446 "dca_fill_rectangle(std)");
447 native_row = gs_alloc_bytes(dev->memory,
448 (target->color_info.depth * w + 7) >> 3,
449 "dca_fill_rectangle(native)");
450 if (std_row == 0 || native_row == 0) {
451 code = gs_note_error(gs_error_VMerror);
452 goto out;
453 }
454 rect.p.x = x, rect.q.x = x + w;
455 std_params.options =
456 GB_COLORS_NATIVE |
457 (GB_ALPHA_LAST | GB_DEPTH_8 | GB_PACKING_CHUNKY |
458 GB_RETURN_COPY | GB_RETURN_POINTER | GB_ALIGN_ANY |
459 GB_OFFSET_0 | GB_OFFSET_ANY | GB_RASTER_STANDARD |
460 GB_RASTER_ANY);
461 cp.cop = adev->params.op;
462 if (cp.cop == composite_Dissolve)
463 cp.delta = adev->params.delta;
464 {
465 gx_color_value rgba[4];
466
467 /****** DOESN'T HANDLE CMYK ******/
468 (*dev_proc(dev, map_color_rgb_alpha)) (dev, color, rgba);
469 cp.source_values[0] = gx_color_value_to_byte(rgba[0]);
470 cp.source_values[1] = gx_color_value_to_byte(rgba[1]);
471 cp.source_values[2] = gx_color_value_to_byte(rgba[2]);
472 cp.source_alpha = gx_color_value_to_byte(rgba[3]);
473 }
474 source.data = 0;
475 source.bits_per_value = 8;
476 source.alpha = gs_image_alpha_none;
477 for (yi = y; yi < y + h; ++yi) {
478 /* Read a row in standard representation. */
479 rect.p.y = yi, rect.q.y = yi + 1;
480 std_params.data[0] = std_row;
481 code = (*dev_proc(target, get_bits_rectangle))
482 (target, &rect, &std_params, NULL);
483 if (code < 0)
484 break;
485 /* Do the work. */
486 dest.data = std_params.data[0];
487 dest.bits_per_value = 8;
488 dest.initial_x =
489 (std_params.options & GB_OFFSET_ANY ? std_params.x_offset : 0);
490 dest.alpha =
491 (std_params.options & GB_ALPHA_FIRST ? gs_image_alpha_first :
492 std_params.options & GB_ALPHA_LAST ? gs_image_alpha_last :
493 gs_image_alpha_none);
494 code = composite_values(&dest, &source,
495 dev->color_info.num_components, w, &cp);
496 if (code < 0)
497 break;
498 if (std_params.data[0] == std_row) {
499 /* Convert the row back to native representation. */
500 /* (Otherwise, we had a direct pointer to device data.) */
501 native_params.options =
502 (GB_COLORS_NATIVE | GB_PACKING_CHUNKY | GB_RETURN_COPY |
503 GB_OFFSET_0 | GB_RASTER_ALL | GB_ALIGN_STANDARD);
504 native_params.data[0] = native_row;
505 code = gx_get_bits_copy(target, 0, w, 1, &native_params,
506 &std_params, std_row,
507 0 /* raster is irrelevant */ );
508 if (code < 0)
509 break;
510 code = (*dev_proc(target, copy_color))
511 (target, native_row, 0, 0 /* raster is irrelevant */ ,
512 gx_no_bitmap_id, x, yi, w, 1);
513 if (code < 0)
514 break;
515 }
516 }
517 out:gs_free_object(dev->memory, native_row, "dca_fill_rectangle(native)");
518 gs_free_object(dev->memory, std_row, "dca_fill_rectangle(std)");
519 return code;
520 }
521
522 private int
dca_copy_mono(gx_device * dev,const byte * data,int dx,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)523 dca_copy_mono(gx_device * dev, const byte * data,
524 int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h,
525 gx_color_index zero, gx_color_index one)
526 {
527 /****** TEMPORARY ******/
528 return gx_default_copy_mono(dev, data, dx, raster, id, x, y, w, h,
529 zero, one);
530 }
531
532 private int
dca_copy_color(gx_device * dev,const byte * data,int dx,int raster,gx_bitmap_id id,int x,int y,int w,int h)533 dca_copy_color(gx_device * dev, const byte * data,
534 int dx, int raster, gx_bitmap_id id,
535 int x, int y, int w, int h)
536 {
537 /****** TEMPORARY ******/
538 return gx_default_copy_color(dev, data, dx, raster, id, x, y, w, h);
539 }
540
541 private int
dca_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)542 dca_copy_alpha(gx_device * dev, const byte * data, int data_x,
543 int raster, gx_bitmap_id id, int x, int y, int width, int height,
544 gx_color_index color, int depth)
545 {
546 /****** TEMPORARY ******/
547 return gx_default_copy_alpha(dev, data, data_x, raster, id, x, y,
548 width, height, color, depth);
549 }
550
551 /*
552 * Composite two arrays of (premultiplied) pixel values.
553 * See gsdpnext.h for the specification.
554 *
555 * The current implementation is simple but inefficient. We'll speed it up
556 * later if necessary.
557 */
558 int
composite_values(const pixel_row_t * pdest,const const_pixel_row_t * psource,int values_per_pixel,uint num_pixels,const gs_composite_params_t * pcp)559 composite_values(const pixel_row_t * pdest, const const_pixel_row_t * psource,
560 int values_per_pixel, uint num_pixels, const gs_composite_params_t * pcp)
561 {
562 int dest_bpv = pdest->bits_per_value;
563 int source_bpv = psource->bits_per_value;
564
565 /*
566 * source_alpha_j gives the source component index for the alpha value,
567 * if the source has alpha.
568 */
569 int source_alpha_j =
570 (psource->alpha == gs_image_alpha_last ? values_per_pixel :
571 psource->alpha == gs_image_alpha_first ? 0 : -1);
572
573 /* dest_alpha_j does the same for the destination. */
574 int dest_alpha_j =
575 (pdest->alpha == gs_image_alpha_last ? values_per_pixel :
576 pdest->alpha == gs_image_alpha_first ? 0 : -1);
577
578 /* dest_vpp is the number of stored destination values. */
579 int dest_vpp = values_per_pixel + (dest_alpha_j >= 0);
580
581 /* source_vpp is the number of stored source values. */
582 int source_vpp = values_per_pixel + (source_alpha_j >= 0);
583
584 bool constant_colors = psource->data == 0;
585 uint highlight_value = (1 << dest_bpv) - 1;
586
587 sample_load_declare(sptr, sbit);
588 sample_store_declare(dptr, dbit, dbyte);
589
590 {
591 uint xbit = pdest->initial_x * dest_bpv * dest_vpp;
592
593 sample_store_setup(dbit, xbit & 7, dest_bpv);
594 dptr = pdest->data + (xbit >> 3);
595 }
596 {
597 uint xbit = psource->initial_x * source_bpv * source_vpp;
598
599 sbit = xbit & 7;
600 sptr = psource->data + (xbit >> 3);
601 }
602 {
603 uint source_max = (1 << source_bpv) - 1;
604 uint dest_max = (1 << dest_bpv) - 1;
605
606 /*
607 * We could save a little work by only setting up source_delta
608 * and dest_delta if the operation is Dissolve.
609 */
610 float source_delta = pcp->delta * dest_max / source_max;
611 float dest_delta = 1.0 - pcp->delta;
612 uint source_alpha = pcp->source_alpha;
613 uint dest_alpha = dest_max;
614
615 #ifdef PREMULTIPLY_TOWARDS_WHITE
616 uint source_bias = source_max - source_alpha;
617 uint dest_bias = 0;
618 uint result_bias = 0;
619
620 #endif
621 uint x;
622
623 if (!pdest->alpha) {
624 uint mask =
625 (psource->alpha || source_alpha != source_max ?
626 alpha_out_S_notD : alpha_out_notS_notD);
627
628 if ((mask >> pcp->cop) & 1) {
629 /*
630 * The operation could produce non-unity alpha values, but
631 * the destination can't store them. Return an error.
632 */
633 return_error(gs_error_rangecheck);
634 }
635 }
636 /* Preload the output byte buffer if necessary. */
637 sample_store_preload(dbyte, dptr, dbit, dest_bpv);
638
639 for (x = 0; x < num_pixels; ++x) {
640 int j;
641 uint result_alpha = dest_alpha;
642
643 /* get_value does not increment the source pointer. */
644 #define get_value(v, ptr, bit, bpv, vmax)\
645 sample_load16(v, ptr, bit, bpv)
646
647 /* put_value increments the destination pointer. */
648 #define put_value(v, ptr, bit, bpv, bbyte)\
649 sample_store_next16(v, ptr, bit, bpv, bbyte)
650
651 #define advance(ptr, bit, bpv)\
652 sample_next(ptr, bit, bpv)
653
654 /* Get destination alpha value. */
655 if (dest_alpha_j >= 0) {
656 int dabit = dbit + dest_bpv * dest_alpha_j;
657 const byte *daptr = dptr + (dabit >> 3);
658
659 get_value(dest_alpha, daptr, dabit & 7, dest_bpv, dest_max);
660 #ifdef PREMULTIPLY_TOWARDS_WHITE
661 dest_bias = dest_max - dest_alpha;
662 #endif
663 }
664 /* Get source alpha value. */
665 if (source_alpha_j >= 0) {
666 int sabit = sbit;
667 const byte *saptr = sptr;
668
669 if (source_alpha_j == 0)
670 advance(sptr, sbit, source_bpv);
671 else
672 advance(saptr, sabit, source_bpv * source_alpha_j);
673 get_value(source_alpha, saptr, sabit, source_bpv, source_max);
674 #ifdef PREMULTIPLY_TOWARDS_WHITE
675 source_bias = source_max - source_alpha;
676 #endif
677 }
678 /*
679 * We are always multiplying a dest value by a source value to compute a
680 * dest value, so the denominator is always source_max. (Dissolve is the
681 * one exception.)
682 */
683 #define fr(v, a) ((v) * (a) / source_max)
684 #define nfr(v, a, maxv) ((v) * (maxv - (a)) / source_max)
685
686 /*
687 * Iterate over the components of a single pixel.
688 * j = 0 for alpha, 1 .. values_per_pixel for color
689 * components, regardless of the actual storage order;
690 * we arrange things so that sptr/sbit and dptr/dbit
691 * always point to the right place.
692 */
693 for (j = 0; j <= values_per_pixel; ++j) {
694 uint dest_v, source_v, result;
695
696 #define set_clamped(r, v)\
697 BEGIN if ( (r = (v)) > dest_max ) r = dest_max; END
698
699 if (j == 0) {
700 source_v = source_alpha;
701 dest_v = dest_alpha;
702 } else {
703 if (constant_colors)
704 source_v = pcp->source_values[j - 1];
705 else {
706 get_value(source_v, sptr, sbit, source_bpv, source_max);
707 advance(sptr, sbit, source_bpv);
708 }
709 get_value(dest_v, dptr, dbit, dest_bpv, dest_max);
710 #ifdef PREMULTIPLY_TOWARDS_WHITE
711 source_v -= source_bias;
712 dest_v -= dest_bias;
713 #endif
714 }
715
716 switch (pcp->cop) {
717 case composite_Clear:
718 /*
719 * The NeXT documentation doesn't say this, but the CLEAR
720 * operation sets not only alpha but also all the color
721 * values to 0.
722 */
723 result = 0;
724 break;
725 case composite_Copy:
726 result = source_v;
727 break;
728 case composite_PlusD:
729 /*
730 * This is the only case where we have to worry about
731 * clamping a possibly negative result.
732 */
733 result = source_v + dest_v;
734 result = (result < dest_max ? 0 : result - dest_max);
735 break;
736 case composite_PlusL:
737 set_clamped(result, source_v + dest_v);
738 break;
739 case composite_Sover:
740 set_clamped(result, source_v + nfr(dest_v, source_alpha, source_max));
741 break;
742 case composite_Dover:
743 set_clamped(result, nfr(source_v, dest_alpha, dest_max) + dest_v);
744 break;
745 case composite_Sin:
746 result = fr(source_v, dest_alpha);
747 break;
748 case composite_Din:
749 result = fr(dest_v, source_alpha);
750 break;
751 case composite_Sout:
752 result = nfr(source_v, dest_alpha, dest_max);
753 break;
754 case composite_Dout:
755 result = nfr(dest_v, source_alpha, source_max);
756 break;
757 case composite_Satop:
758 set_clamped(result, fr(source_v, dest_alpha) +
759 nfr(dest_v, source_alpha, source_max));
760 break;
761 case composite_Datop:
762 set_clamped(result, nfr(source_v, dest_alpha, dest_max) +
763 fr(dest_v, source_alpha));
764 break;
765 case composite_Xor:
766 set_clamped(result, nfr(source_v, dest_alpha, dest_max) +
767 nfr(dest_v, source_alpha, source_max));
768 break;
769 case composite_Highlight:
770 /*
771 * Bizarre but true: this operation converts white and
772 * light gray into each other, and leaves all other values
773 * unchanged. We only implement it properly for gray-scale
774 * devices.
775 */
776 if (j != 0 && !((source_v ^ highlight_value) & ~1))
777 result = source_v ^ 1;
778 else
779 result = source_v;
780 break;
781 case composite_Dissolve:
782 /*
783 * In this case, and only this case, we need to worry about
784 * source and dest having different bpv values. For the
785 * moment, we wimp out and do everything in floating point.
786 */
787 result = (uint) (source_v * source_delta + dest_v * dest_delta);
788 break;
789 default:
790 return_error(gs_error_rangecheck);
791 }
792 /*
793 * Store the result. We don't have to worry about
794 * destinations that don't store alpha, because we don't
795 * even compute an alpha value in that case.
796 */
797 #ifdef PREMULTIPLY_TOWARDS_WHITE
798 if (j == 0) {
799 result_alpha = result;
800 result_bias = dest_max - result_alpha;
801 if (dest_alpha_j != 0)
802 continue;
803 } else {
804 result += result_bias;
805 }
806 #else
807 if (j == 0 && dest_alpha_j != 0) {
808 result_alpha = result;
809 continue;
810 }
811 #endif
812 put_value(result, dptr, dbit, dest_bpv, dbyte);
813 }
814 /* Skip a trailing source alpha value. */
815 if (source_alpha_j > 0)
816 advance(sptr, sbit, source_bpv);
817 /* Store a trailing destination alpha value. */
818 if (dest_alpha_j > 0)
819 put_value(result_alpha, dptr, dbit, dest_bpv, dbyte);
820 #undef get_value
821 #undef put_value
822 #undef advance
823 }
824 /* Store any partial output byte. */
825 sample_store_flush(dptr, dbit, dest_bpv, dbyte);
826 }
827 return 0;
828 }
829