xref: /plan9/sys/src/cmd/gs/src/gsalphac.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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(&params.delta, data + 1, sizeof(params.delta));
189 	nbytes += sizeof(params.delta);
190     }
191     code = gs_create_composite_alpha(ppcte, &params, 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