summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'base/gsalphac.c')
-rw-r--r--base/gsalphac.c842
1 files changed, 0 insertions, 842 deletions
diff --git a/base/gsalphac.c b/base/gsalphac.c
deleted file mode 100644
index 4edb1936..00000000
--- a/base/gsalphac.c
+++ /dev/null
@@ -1,842 +0,0 @@
-/* Copyright (C) 2001-2019 Artifex Software, Inc.
- All Rights Reserved.
-
- This software is provided AS-IS with no warranty, either express or
- implied.
-
- This software is distributed under license and may not be copied,
- modified or distributed except as expressly authorized under the terms
- of the license contained in the file LICENSE in this distribution.
-
- Refer to licensing information at http://www.artifex.com or contact
- Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
- CA 94945, U.S.A., +1(415)492-9861, for further information.
-*/
-
-
-/* Alpha-compositing implementation */
-#include "memory_.h"
-#include "gx.h"
-#include "gserrors.h"
-#include "gsalphac.h"
-#include "gsiparam.h" /* for gs_image_alpha_t */
-#include "gsutil.h" /* for gs_next_ids */
-#include "gxalpha.h"
-#include "gxcomp.h"
-#include "gxdevice.h"
-#include "gxgetbit.h"
-#include "gxlum.h"
-#include "gsbitops.h"
-
-/* ---------------- Internal definitions ---------------- */
-
-/* Define the parameters for a compositing operation. */
-typedef struct gs_composite_params_s {
- gs_composite_op_t cop;
- float delta; /* only for dissolve */
- uint source_alpha; /* only if !psource->alpha */
- uint source_values[4]; /* only if !psource->data */
-} gs_composite_params_t;
-
-/* Define the source or destination for a compositing operation. */
-#define pixel_row_fields(elt_type)\
- elt_type *data;\
- int bits_per_value; /* 1, 2, 4, 8, 12, 16 */\
- int initial_x;\
- gs_image_alpha_t alpha
-typedef struct pixel_row_s {
- pixel_row_fields(byte);
-} pixel_row_t;
-typedef struct const_pixel_row_s {
- pixel_row_fields(const byte);
-} const_pixel_row_t;
-
-/*
- * Composite two arrays of (premultiplied) pixel values. Legal values of
- * values_per_pixel are 1-4, not including alpha. Note that if pdest->alpha
- * is "none", the alpha value for all destination pixels will be taken as
- * unity, and any operation that could generate alpha values other than
- * unity will return an error. "Could generate" means that there are
- * possible values of the source and destination alpha values for which the
- * result has non-unity alpha: the error check does not scan the actual
- * alpha data to test whether there are any actual values that would
- * generate a non-unity alpha result.
- */
-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);
-
-/* ---------------- Alpha-compositing objects ---------------- */
-
-/*
- * Define which operations can generate non-unity alpha values in 3 of the 4
- * cases of source and destination not having unity alphas. (This is always
- * possible in the fourth case, both S & D non-unity, except for CLEAR.) We
- * do this with a bit mask indexed by the operation, counting from the LSB.
- * The name indicates whether S and/or D has non-unity alphas.
- */
-#define alpha_out_notS_notD\
- (1<<composite_Dissolve)
-#define _alpha_out_either\
- (alpha_out_notS_notD|(1<<composite_Satop)|(1<<composite_Datop)|\
- (1<<composite_Xor)|(1<<composite_PlusD)|(1<<composite_PlusL))
-#define alpha_out_S_notD\
- (_alpha_out_either|(1<<composite_Copy)|(1<<composite_Sover)|\
- (1<<composite_Din)|(1<<composite_Dout))
-#define alpha_out_notS_D\
- (_alpha_out_either|(1<<composite_Sin)|(1<<composite_Sout)|\
- (1<<composite_Dover)|(1<<composite_Highlight))
-
-/* ------ Object definition and creation ------ */
-
-/* Define alpha-compositing objects. */
-static composite_create_default_compositor_proc(c_alpha_create_default_compositor);
-static composite_equal_proc(c_alpha_equal);
-static composite_write_proc(c_alpha_write);
-static composite_read_proc(c_alpha_read);
-const gs_composite_type_t gs_composite_alpha_type =
-{
- GX_COMPOSITOR_ALPHA,
- {
- c_alpha_create_default_compositor,
- c_alpha_equal,
- c_alpha_write,
- c_alpha_read,
- gx_default_composite_adjust_ctm,
- gx_default_composite_is_closing,
- gx_default_composite_is_friendly,
- gx_default_composite_clist_write_update,
- gx_default_composite_clist_read_update,
- gx_default_composite_get_cropping
- }
-};
-typedef struct gs_composite_alpha_s {
- gs_composite_common;
- gs_composite_alpha_params_t params;
-} gs_composite_alpha_t;
-
-gs_private_st_simple(st_composite_alpha, gs_composite_alpha_t,
- "gs_composite_alpha_t");
-
-/* Create an alpha-compositing object. */
-int
-gs_create_composite_alpha(gs_composite_t ** ppcte,
- const gs_composite_alpha_params_t * params, gs_memory_t * mem)
-{
- gs_composite_alpha_t *pcte;
-
- pcte = gs_alloc_struct(mem, gs_composite_alpha_t, &st_composite_alpha,
- "gs_create_composite_alpha");
- if (pcte == NULL)
- return_error(gs_error_VMerror);
- pcte->type = &gs_composite_alpha_type;
- pcte->id = gs_next_ids(mem, 1);
- pcte->params = *params;
- pcte->idle = false;
- *ppcte = (gs_composite_t *) pcte;
- return 0;
-}
-
-/* ------ Object implementation ------ */
-
-#define pacte ((const gs_composite_alpha_t *)pcte)
-
-static bool
-c_alpha_equal(const gs_composite_t * pcte, const gs_composite_t * pcte2)
-{
- return (pcte2->type == pcte->type &&
-#define pacte2 ((const gs_composite_alpha_t *)pcte2)
- pacte2->params.op == pacte->params.op &&
- (pacte->params.op != composite_Dissolve ||
- pacte2->params.delta == pacte->params.delta));
-#undef pacte2
-}
-
-static int
-c_alpha_write(const gs_composite_t * pcte, byte * data, uint * psize, gx_device_clist_writer *cdev)
-{
- uint size = *psize;
- uint used;
-
- if_debug1m('v', ((gx_device *)cdev)->memory, "[v]c_alpha_write(%d)\n", pacte->params.op);
- if (pacte->params.op == composite_Dissolve) {
- used = 1 + sizeof(pacte->params.delta);
- if (size < used) {
- *psize = used;
- return_error(gs_error_rangecheck);
- }
- memcpy(data + 1, &pacte->params.delta, sizeof(pacte->params.delta));
- } else {
- used = 1;
- if (size < used) {
- *psize = used;
- return_error(gs_error_rangecheck);
- }
- }
- *data = (byte) pacte->params.op;
- *psize = used;
- return 0;
-}
-
-static int
-c_alpha_read(gs_composite_t ** ppcte, const byte * data, uint size,
- gs_memory_t * mem)
-{
- gs_composite_alpha_params_t params = {composite_Clear, 0};
- int code, nbytes = 1;
-
- if (size < 1 || *data > composite_op_last)
- return_error(gs_error_rangecheck);
- params.op = *data;
- if_debug1m('v', mem, "[v]c_alpha_read(%d)\n", params.op);
- if (params.op == composite_Dissolve) {
- if (size < 1 + sizeof(params.delta))
- return_error(gs_error_rangecheck);
- memcpy(&params.delta, data + 1, sizeof(params.delta));
- nbytes += sizeof(params.delta);
- }
- code = gs_create_composite_alpha(ppcte, &params, mem);
- return code < 0 ? code : nbytes;
-}
-
-/* ---------------- Alpha-compositing device ---------------- */
-
-/* Define the default alpha-compositing device. */
-typedef struct gx_device_composite_alpha_s {
- gx_device_forward_common;
- gs_composite_alpha_params_t params;
-} gx_device_composite_alpha;
-
-gs_private_st_suffix_add0_final(st_device_composite_alpha,
- gx_device_composite_alpha, "gx_device_composite_alpha",
- device_c_alpha_enum_ptrs, device_c_alpha_reloc_ptrs, gx_device_finalize,
- st_device_forward);
-/* The device descriptor. */
-static dev_proc_close_device(dca_close);
-static dev_proc_fill_rectangle(dca_fill_rectangle);
-static dev_proc_map_rgb_color(dca_map_rgb_color);
-static dev_proc_map_color_rgb(dca_map_color_rgb);
-static dev_proc_copy_mono(dca_copy_mono);
-static dev_proc_copy_color(dca_copy_color);
-static dev_proc_map_rgb_alpha_color(dca_map_rgb_alpha_color);
-static dev_proc_map_color_rgb_alpha(dca_map_color_rgb_alpha);
-static dev_proc_copy_alpha(dca_copy_alpha);
-static const gx_device_composite_alpha gs_composite_alpha_device =
-{std_device_std_body_open(gx_device_composite_alpha, 0,
- "alpha compositor", 0, 0, 1, 1),
- {gx_default_open_device,
- gx_forward_get_initial_matrix,
- gx_default_sync_output,
- gx_default_output_page,
- dca_close,
- dca_map_rgb_color,
- dca_map_color_rgb,
- dca_fill_rectangle,
- gx_default_tile_rectangle,
- dca_copy_mono,
- dca_copy_color,
- gx_default_draw_line,
- gx_default_get_bits,
- gx_forward_get_params,
- gx_forward_put_params,
- gx_default_cmyk_map_cmyk_color, /* only called for CMYK */
- gx_forward_get_xfont_procs,
- gx_forward_get_xfont_device,
- dca_map_rgb_alpha_color,
- gx_forward_get_page_device,
- gx_forward_get_alpha_bits,
- dca_copy_alpha,
- gx_forward_get_band,
- gx_default_copy_rop,
- gx_default_fill_path,
- gx_default_stroke_path,
- gx_default_fill_mask,
- gx_default_fill_trapezoid,
- gx_default_fill_parallelogram,
- gx_default_fill_triangle,
- gx_default_draw_thin_line,
- gx_default_begin_image,
- gx_default_image_data,
- gx_default_end_image,
- gx_default_strip_tile_rectangle,
- gx_default_strip_copy_rop,
- gx_forward_get_clipping_box,
- gx_default_begin_typed_image,
- gx_forward_get_bits_rectangle,
- dca_map_color_rgb_alpha,
- gx_no_create_compositor
- }
-};
-
-/* Create an alpha compositor. */
-static int
-c_alpha_create_default_compositor(const gs_composite_t * pcte,
- gx_device ** pcdev, gx_device * dev, gs_gstate * pgs,
- gs_memory_t * mem)
-{
- gx_device_composite_alpha *cdev;
-
- if (pacte->params.op == composite_Copy) {
- /* Just use the original device. */
- *pcdev = dev;
- return 0;
- }
- cdev =
- gs_alloc_struct_immovable(mem, gx_device_composite_alpha,
- &st_device_composite_alpha,
- "create default alpha compositor");
- *pcdev = (gx_device *)cdev;
- if (cdev == 0)
- return_error(gs_error_VMerror);
- gx_device_init((gx_device *)cdev,
- (const gx_device *)&gs_composite_alpha_device, mem, true);
- gx_device_copy_params((gx_device *)cdev, dev);
- /*
- * Set the color_info and depth to be compatible with the target,
- * but using standard chunky color storage, including alpha.
- ****** CURRENTLY ALWAYS USE 8-BIT COLOR ******
- */
- cdev->color_info.depth =
- (dev->color_info.num_components == 4 ? 32 /* CMYK, no alpha */ :
- (dev->color_info.num_components + 1) * 8);
- cdev->color_info.max_gray = cdev->color_info.max_color = 255;
- /* No halftoning will occur, but we fill these in anyway.... */
- cdev->color_info.dither_grays = cdev->color_info.dither_colors = 256;
- /*
- * We could speed things up a little by tailoring the procedures in
- * the device to the specific num_components, but for simplicity,
- * we'll defer considering that until there is a demonstrated need.
- */
- gx_device_set_target((gx_device_forward *)cdev, dev);
- cdev->params = pacte->params;
- return 0;
-}
-
-/* Close the device and free its storage. */
-static int
-dca_close(gx_device * dev)
-{ /*
- * Finalization will call close again: avoid a recursion loop.
- */
- set_dev_proc(dev, close_device, gx_default_close_device);
- gs_free_object(dev->memory, dev, "dca_close");
- return 0;
-}
-
-/* ------ (RGB) color mapping ------ */
-
-static gx_color_index
-dca_map_rgb_color(gx_device * dev, const gx_color_value cv[])
-{
- return dca_map_rgb_alpha_color(dev, cv[0], cv[1], cv[2], gx_max_color_value);
-}
-static 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)
-{ /*
- * We work exclusively with premultiplied color values, so we
- * have to premultiply the color components by alpha here.
- */
- byte a = gx_color_value_to_byte(alpha);
-
-#define premult_(c)\
- (((c) * a + gx_max_color_value / 2) / gx_max_color_value)
-#ifdef PREMULTIPLY_TOWARDS_WHITE
- byte bias = ~a;
-
-# define premult(c) (premult_(c) + bias)
-#else
-# define premult(c) premult_(c)
-#endif
- gx_color_index color;
-
- if (dev->color_info.num_components == 1) {
- uint lum =
- (red * lum_red_weight + green * lum_green_weight +
- blue * lum_blue_weight + lum_all_weights / 2) /
- lum_all_weights;
-
- if (a == 0xff)
- color = gx_color_value_to_byte(lum);
- else /* Premultiplication is necessary. */
- color = premult(lum);
- } else {
- if (a == 0xff)
- color =
- ((uint) gx_color_value_to_byte(red) << 16) +
- ((uint) gx_color_value_to_byte(green) << 8) +
- gx_color_value_to_byte(blue);
- else /* Premultiplication is necessary. */
- color =
- (premult(red) << 16) + (premult(green) << 8) + premult(blue);
- }
-#undef premult
- return (color << 8) + a;
-}
-static int
-dca_map_color_rgb(gx_device * dev, gx_color_index color,
- gx_color_value prgb[3])
-{
- gx_color_value red = gx_color_value_from_byte((byte) (color >> 24));
- byte a = (byte) color;
-
-#define postdiv_(c)\
- (((c) * 0xff + a / 2) / a)
-#ifdef PREMULTIPLY_TOWARDS_WHITE
- byte bias = ~a;
-
-# define postdiv(c) postdiv_(c - bias)
-#else
-# define postdiv(c) postdiv_(c)
-#endif
-
- if (dev->color_info.num_components == 1) {
- if (a != 0xff) {
- /* Undo premultiplication. */
- if (a == 0)
- red = 0;
- else
- red = postdiv(red);
- }
- prgb[0] = prgb[1] = prgb[2] = red;
- } else {
- gx_color_value
- green = gx_color_value_from_byte((byte) (color >> 16)),
- blue = gx_color_value_from_byte((byte) (color >> 8));
-
- if (a != 0xff) {
- /* Undo premultiplication. */
-/****** WHAT TO DO ABOUT BIG LOSS OF PRECISION? ******/
- if (a == 0)
- red = green = blue = 0;
- else {
- red = postdiv(red);
- green = postdiv(green);
- blue = postdiv(blue);
- }
- }
- prgb[0] = red, prgb[1] = green, prgb[2] = blue;
- }
-#undef postdiv
- return 0;
-}
-static int
-dca_map_color_rgb_alpha(gx_device * dev, gx_color_index color,
- gx_color_value prgba[4])
-{
- prgba[3] = gx_color_value_from_byte((byte) color);
- return dca_map_color_rgb(dev, color, prgba);
-}
-
-/* ------ Imaging ------ */
-
-static int
-dca_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
- gx_color_index color)
-{ /* This is where all the real work gets done! */
- gx_device_composite_alpha *adev = (gx_device_composite_alpha *) dev;
- gx_device *target = adev->target;
- byte *std_row;
- byte *native_row;
- gs_int_rect rect;
- gs_get_bits_params_t std_params, native_params;
- int code = 0;
- int yi;
- gs_composite_params_t cp;
- const_pixel_row_t source;
- pixel_row_t dest;
-
- fit_fill(dev, x, y, w, h);
- std_row = gs_alloc_bytes(dev->memory,
- (dev->color_info.depth * w + 7) >> 3,
- "dca_fill_rectangle(std)");
- native_row = gs_alloc_bytes(dev->memory,
- (target->color_info.depth * w + 7) >> 3,
- "dca_fill_rectangle(native)");
- if (std_row == 0 || native_row == 0) {
- code = gs_note_error(gs_error_VMerror);
- goto out;
- }
- rect.p.x = x, rect.q.x = x + w;
- std_params.options =
- GB_COLORS_NATIVE |
- (GB_ALPHA_LAST | GB_DEPTH_8 | GB_PACKING_CHUNKY |
- GB_RETURN_COPY | GB_RETURN_POINTER | GB_ALIGN_ANY |
- GB_OFFSET_0 | GB_OFFSET_ANY | GB_RASTER_STANDARD |
- GB_RASTER_ANY);
- cp.cop = adev->params.op;
- if (cp.cop == composite_Dissolve)
- cp.delta = adev->params.delta;
- {
- gx_color_value rgba[4];
-
-/****** DOESN'T HANDLE CMYK ******/
- (*dev_proc(dev, map_color_rgb_alpha)) (dev, color, rgba);
- cp.source_values[0] = gx_color_value_to_byte(rgba[0]);
- cp.source_values[1] = gx_color_value_to_byte(rgba[1]);
- cp.source_values[2] = gx_color_value_to_byte(rgba[2]);
- cp.source_alpha = gx_color_value_to_byte(rgba[3]);
- }
- source.data = 0;
- source.bits_per_value = 8;
- source.alpha = gs_image_alpha_none;
- for (yi = y; yi < y + h; ++yi) {
- /* Read a row in standard representation. */
- rect.p.y = yi, rect.q.y = yi + 1;
- std_params.data[0] = std_row;
- code = (*dev_proc(target, get_bits_rectangle))
- (target, &rect, &std_params, NULL);
- if (code < 0)
- break;
- /* Do the work. */
- dest.data = std_params.data[0];
- dest.bits_per_value = 8;
- dest.initial_x =
- (std_params.options & GB_OFFSET_ANY ? std_params.x_offset : 0);
- dest.alpha =
- (std_params.options & GB_ALPHA_FIRST ? gs_image_alpha_first :
- std_params.options & GB_ALPHA_LAST ? gs_image_alpha_last :
- gs_image_alpha_none);
- code = composite_values(&dest, &source,
- dev->color_info.num_components, w, &cp);
- if (code < 0)
- break;
- if (std_params.data[0] == std_row) {
- /* Convert the row back to native representation. */
- /* (Otherwise, we had a direct pointer to device data.) */
- native_params.options =
- (GB_COLORS_NATIVE | GB_PACKING_CHUNKY | GB_RETURN_COPY |
- GB_OFFSET_0 | GB_RASTER_ALL | GB_ALIGN_STANDARD);
- native_params.data[0] = native_row;
- code = gx_get_bits_copy(target, 0, w, 1, &native_params,
- &std_params, std_row,
- 0 /* raster is irrelevant */ );
- if (code < 0)
- break;
- code = (*dev_proc(target, copy_color))
- (target, native_row, 0, 0 /* raster is irrelevant */ ,
- gx_no_bitmap_id, x, yi, w, 1);
- if (code < 0)
- break;
- }
- }
- out:gs_free_object(dev->memory, native_row, "dca_fill_rectangle(native)");
- gs_free_object(dev->memory, std_row, "dca_fill_rectangle(std)");
- return code;
-}
-
-static 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)
-{
-/****** TEMPORARY ******/
- return gx_default_copy_mono(dev, data, dx, raster, id, x, y, w, h,
- zero, one);
-}
-
-static 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)
-{
-/****** TEMPORARY ******/
- return gx_default_copy_color(dev, data, dx, raster, id, x, y, w, h);
-}
-
-static 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)
-{
-/****** TEMPORARY ******/
- return gx_default_copy_alpha(dev, data, data_x, raster, id, x, y,
- width, height, color, depth);
-}
-
-/*
- * Composite two arrays of (premultiplied) pixel values.
- * See gsdpnext.h for the specification.
- *
- * The current implementation is simple but inefficient. We'll speed it up
- * later if necessary.
- */
-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)
-{
- int dest_bpv = pdest->bits_per_value;
- int source_bpv = psource->bits_per_value;
-
- /*
- * source_alpha_j gives the source component index for the alpha value,
- * if the source has alpha.
- */
- int source_alpha_j =
- (psource->alpha == gs_image_alpha_last ? values_per_pixel :
- psource->alpha == gs_image_alpha_first ? 0 : -1);
-
- /* dest_alpha_j does the same for the destination. */
- int dest_alpha_j =
- (pdest->alpha == gs_image_alpha_last ? values_per_pixel :
- pdest->alpha == gs_image_alpha_first ? 0 : -1);
-
- /* dest_vpp is the number of stored destination values. */
- int dest_vpp = values_per_pixel + (dest_alpha_j >= 0);
-
- /* source_vpp is the number of stored source values. */
- int source_vpp = values_per_pixel + (source_alpha_j >= 0);
-
- bool constant_colors = psource->data == 0;
- uint highlight_value = (1 << dest_bpv) - 1;
-
- const byte *sptr;
- int sbit;
- byte *dptr;
- int dbit;
- byte dbyte;
-
- {
- uint xbit = pdest->initial_x * dest_bpv * dest_vpp;
-
- dbit = xbit & 7;
- dptr = pdest->data + (xbit >> 3);
- }
- {
- uint xbit = psource->initial_x * source_bpv * source_vpp;
-
- sbit = xbit & 7;
- sptr = psource->data + (xbit >> 3);
- }
- {
- uint source_max = (1 << source_bpv) - 1;
- uint dest_max = (1 << dest_bpv) - 1;
-
- /*
- * We could save a little work by only setting up source_delta
- * and dest_delta if the operation is Dissolve.
- */
- float source_delta = pcp->delta * dest_max / source_max;
- float dest_delta = 1.0 - pcp->delta;
- uint source_alpha = pcp->source_alpha;
- uint dest_alpha = dest_max;
-
-#ifdef PREMULTIPLY_TOWARDS_WHITE
- uint source_bias = source_max - source_alpha;
- uint dest_bias = 0;
- uint result_bias = 0;
-
-#endif
- uint x;
-
- if (!pdest->alpha) {
- uint mask =
- (psource->alpha || source_alpha != source_max ?
- alpha_out_S_notD : alpha_out_notS_notD);
-
- if ((mask >> pcp->cop) & 1) {
- /*
- * The operation could produce non-unity alpha values, but
- * the destination can't store them. Return an error.
- */
- return_error(gs_error_rangecheck);
- }
- }
- /* Preload the output byte buffer if necessary. */
- dbyte = (dbit ? (byte)(*dptr & (0xff00 >> dbit)) : 0);
-
- for (x = 0; x < num_pixels; ++x) {
- int j;
- uint result_alpha = dest_alpha;
-
- /* Get destination alpha value. */
- if (dest_alpha_j >= 0) {
- int dabit = dbit + dest_bpv * dest_alpha_j;
- const byte *daptr = dptr + (dabit >> 3);
-
- if (sample_load16(&dest_alpha, daptr, dabit & 7, dest_bpv) < 0)
- return_error(gs_error_rangecheck);
-#ifdef PREMULTIPLY_TOWARDS_WHITE
- dest_bias = dest_max - dest_alpha;
-#endif
- }
- /* Get source alpha value. */
- if (source_alpha_j >= 0) {
- int sabit = sbit;
- const byte *saptr = sptr;
-
- if (source_alpha_j == 0) {
- sbit += (source_bpv);
- sptr += sbit >> 3;
- sbit &= 7;
- }
- else {
- sabit += (source_bpv * source_alpha_j);
- saptr += sabit >> 3;
- sabit &= 7;
- }
- if (sample_load16(&dest_alpha, saptr, sabit, source_bpv) < 0)
- return_error(gs_error_rangecheck);
-#ifdef PREMULTIPLY_TOWARDS_WHITE
- source_bias = source_max - source_alpha;
-#endif
- }
-/*
- * We are always multiplying a dest value by a source value to compute a
- * dest value, so the denominator is always source_max. (Dissolve is the
- * one exception.)
- */
-#define fr(v, a) ((v) * (a) / source_max)
-#define nfr(v, a, maxv) ((v) * (maxv - (a)) / source_max)
-
- /*
- * Iterate over the components of a single pixel.
- * j = 0 for alpha, 1 .. values_per_pixel for color
- * components, regardless of the actual storage order;
- * we arrange things so that sptr/sbit and dptr/dbit
- * always point to the right place.
- */
- for (j = 0; j <= values_per_pixel; ++j) {
- uint dest_v, source_v, result;
-
-#define set_clamped(r, v)\
- BEGIN if ( (r = (v)) > dest_max ) r = dest_max; END
-
- if (j == 0) {
- source_v = source_alpha;
- dest_v = dest_alpha;
- } else {
- if (constant_colors)
- source_v = pcp->source_values[j - 1];
- else {
- if (sample_load16(&source_v, sptr, sbit, source_bpv) < 0)
- return_error(gs_error_rangecheck);
- sbit += (source_bpv);
- sptr += sbit >> 3;
- sbit &= 7;
- }
- if (sample_load16(&dest_v, dptr, dbit, dest_bpv) < 0)
- return_error(gs_error_rangecheck);
-#ifdef PREMULTIPLY_TOWARDS_WHITE
- source_v -= source_bias;
- dest_v -= dest_bias;
-#endif
- }
-
- switch (pcp->cop) {
- case composite_Clear:
- /*
- * The NeXT documentation doesn't say this, but the CLEAR
- * operation sets not only alpha but also all the color
- * values to 0.
- */
- result = 0;
- break;
- case composite_Copy:
- result = source_v;
- break;
- case composite_PlusD:
- /*
- * This is the only case where we have to worry about
- * clamping a possibly negative result.
- */
- result = source_v + dest_v;
- result = (result < dest_max ? 0 : result - dest_max);
- break;
- case composite_PlusL:
- set_clamped(result, source_v + dest_v);
- break;
- case composite_Sover:
- set_clamped(result, source_v + nfr(dest_v, source_alpha, source_max));
- break;
- case composite_Dover:
- set_clamped(result, nfr(source_v, dest_alpha, dest_max) + dest_v);
- break;
- case composite_Sin:
- result = fr(source_v, dest_alpha);
- break;
- case composite_Din:
- result = fr(dest_v, source_alpha);
- break;
- case composite_Sout:
- result = nfr(source_v, dest_alpha, dest_max);
- break;
- case composite_Dout:
- result = nfr(dest_v, source_alpha, source_max);
- break;
- case composite_Satop:
- set_clamped(result, fr(source_v, dest_alpha) +
- nfr(dest_v, source_alpha, source_max));
- break;
- case composite_Datop:
- set_clamped(result, nfr(source_v, dest_alpha, dest_max) +
- fr(dest_v, source_alpha));
- break;
- case composite_Xor:
- set_clamped(result, nfr(source_v, dest_alpha, dest_max) +
- nfr(dest_v, source_alpha, source_max));
- break;
- case composite_Highlight:
- /*
- * Bizarre but true: this operation converts white and
- * light gray into each other, and leaves all other values
- * unchanged. We only implement it properly for gray-scale
- * devices.
- */
- if (j != 0 && !((source_v ^ highlight_value) & ~1))
- result = source_v ^ 1;
- else
- result = source_v;
- break;
- case composite_Dissolve:
- /*
- * In this case, and only this case, we need to worry about
- * source and dest having different bpv values. For the
- * moment, we wimp out and do everything in floating point.
- */
- result = (uint) (source_v * source_delta + dest_v * dest_delta);
- break;
- default:
- return_error(gs_error_rangecheck);
- }
- /*
- * Store the result. We don't have to worry about
- * destinations that don't store alpha, because we don't
- * even compute an alpha value in that case.
- */
-#ifdef PREMULTIPLY_TOWARDS_WHITE
- if (j == 0) {
- result_alpha = result;
- result_bias = dest_max - result_alpha;
- if (dest_alpha_j != 0)
- continue;
- } else {
- result += result_bias;
- }
-#else
- if (j == 0 && dest_alpha_j != 0) {
- result_alpha = result;
- continue;
- }
-#endif
- if (sample_store_next16(result, &dptr, &dbit, dest_bpv, &dbyte) < 0)
- return_error(gs_error_rangecheck);
- }
- /* Skip a trailing source alpha value. */
- if (source_alpha_j > 0) {
- sbit += (source_bpv);
- sptr += sbit >> 3;
- sbit &= 7;
- }
- /* Store a trailing destination alpha value. */
- if (dest_alpha_j > 0)
- if (sample_store_next16(result_alpha, &dptr, &dbit, dest_bpv, &dbyte) < 0)
- return_error(gs_error_rangecheck);
- }
- /* Store any partial output byte. */
- sample_store_flush(dptr, dbit, dbyte);
- }
- return 0;
-}