art_blend_pixel_16_inline(uint16_t *gs_restrict dst, const uint16_t *gs_restrict backdrop,
                  const uint16_t *gs_restrict src, int n_chan, gs_blend_mode_t blend_mode,
                  const pdf14_nonseparable_blending_procs_t * pblend_procs,
                  pdf14_device *p14dev)
{
    int i;
    int b, s;
    bits32 t;

    switch (blend_mode) {
        case BLEND_MODE_Normal:
        case BLEND_MODE_Compatible:	/* todo */
            memcpy(dst, src, n_chan*2);
            break;
        case BLEND_MODE_Multiply:
            for (i = 0; i < n_chan; i++) {
                t = backdrop[i];
                t += t >> 15;
                t = t * src[i] + 0x8000;
                dst[i] = t >> 16;
            }
            break;
        case BLEND_MODE_Screen:
            for (i = 0; i < n_chan; i++) {
                t = backdrop[i];
                t += t >> 15;
                t = (0x10000-t) * (0xffff - src[i]) + 0x8000;
                dst[i] = 0xffff - (t >> 16);
            }
            break;
        case BLEND_MODE_Overlay:
            for (i = 0; i < n_chan; i++) {
                b = backdrop[i];
                b += b >> 15;
                s = src[i];
                if (b < 0x8000)
                    t = (2 * b * s);
                else
                    t = 0xffff0000 -
                        2 * (0x10000 - b) * (0xffff - s);
                t = (t+0x8000)>>16;
                dst[i] = t;
            }
            break;
        case BLEND_MODE_SoftLight:
            for (i = 0; i < n_chan; i++) {
                b = backdrop[i];
                s = src[i];
                if (s < 0x8000) {
                    unsigned int b2 = ((unsigned int)(b * (b + (b>>15))))>>16;
                    b2 = b - b2;
                    b2 += b2>>15;
                    t = ((0xffff - (s << 1)) * b2) + 0x8000;
                    dst[i] = b - (t >> 16);
                } else {
#define art_blend_soft_light_16(B) (art_blend_soft_light_8[(B)>>8]*0x101)
                    t = ((s << 1) - 0xffff) * art_blend_soft_light_16(b) + 0x8000;
                    dst[i] = b + (t >> 16);
                }
            }
            break;
        case BLEND_MODE_HardLight:
            for (i = 0; i < n_chan; i++) {
                b = backdrop[i];
                b += b>>15;
                s = src[i];
                if (s < 0x8000)
                    t = 2 * b * s;
                else
                    t = 0xffff0000 - 2 * (0x10000 - b) * (0xffff - s);
                t += 0x8000;
                dst[i] = t >> 16;
            }
            break;
        case BLEND_MODE_ColorDodge:
            for (i = 0; i < n_chan; i++) {
                b = backdrop[i];
                s = 0xffff - src[i];
                if (b == 0)
                    dst[i] = 0;
                else if (b >= s)
                    dst[i] = 0xffff;
                else
                    dst[i] = ((unsigned int)(0xffff * b + (s>>1))) / s;
            }
            break;
        case BLEND_MODE_ColorBurn:
            for (i = 0; i < n_chan; i++) {
                b = 0xffff - backdrop[i];
                s = src[i];
                if (b == 0)
                    dst[i] = 0xffff;
                else if (b >= s)
                    dst[i] = 0;
                else
                    dst[i] = 0xffff - ((unsigned int)(0xffff * b + (s>>1))) / s;
            }
            break;
        case BLEND_MODE_Darken:
            for (i = 0; i < n_chan; i++) {
                b = backdrop[i];
                s = src[i];
                dst[i] = b < s ? b : s;
            }
            break;
        case BLEND_MODE_Lighten:
            for (i = 0; i < n_chan; i++) {
                b = backdrop[i];
                s = src[i];
                dst[i] = b > s ? b : s;
            }
            break;
        case BLEND_MODE_Difference:
            for (i = 0; i < n_chan; i++) {
                art_s32 tmp;

                tmp = ((art_s32) backdrop[i]) - ((art_s32) src[i]);
                dst[i] = tmp < 0 ? -tmp : tmp;
            }
            break;
        case BLEND_MODE_Exclusion:
            for (i = 0; i < n_chan; i++) {
                b = backdrop[i];
                b += b>>15;
                s = src[i];
                t = (0x10000 - b) * s + b * (0xffff - s) + 0x8000;
                dst[i] = t >> 16;
            }
            break;
        case BLEND_MODE_Luminosity:
            pblend_procs->blend_luminosity16(n_chan, dst, backdrop, src);
            break;
        case BLEND_MODE_Color:
            pblend_procs->blend_luminosity16(n_chan, dst, src, backdrop);
            break;
        case BLEND_MODE_Saturation:
            pblend_procs->blend_saturation16(n_chan, dst, backdrop, src);
            break;
        case BLEND_MODE_Hue:
            {
                uint16_t tmp[4];

                pblend_procs->blend_luminosity16(n_chan, tmp, src, backdrop);
                pblend_procs->blend_saturation16(n_chan, dst, tmp, backdrop);
            }
            break;
            /* This mode requires information about the color space as
             * well as the overprint mode.  See Section 7.6.3 of
             * PDF specification */
        case BLEND_MODE_CompatibleOverprint:
            {
                gx_color_index drawn_comps = p14dev->drawn_comps;
                gx_color_index comps;
                /* If overprint mode is true and the current color space and
                 * the group color space are CMYK (or CMYK and spots), then
                 * B(cb, cs) = cs if cs is nonzero otherwise it is cb for CMYK.
                 * Spot colors are always set to cb.  The nice thing about the PDF14
                 * compositor is that it always has CMYK + spots with spots after
                 * the CMYK colorants (see gx_put_blended_image_cmykspot).
                 * that way we don't have to worry about where the process colors
                 * are. */
                if (p14dev->effective_overprint_mode && p14dev->color_info.num_components > 3
                    && !(p14dev->ctx->additive)) {
                    for (i = 0; i < 4; i++) {
                        b = backdrop[i];
                        s = src[i];
                        dst[i] = s < 0xffff ? s : b; /* Subtractive zero */
                    }
                    for (i = 4; i < n_chan; i++) {
                        dst[i] = backdrop[i];
                    }
                } else {
                    /* Otherwise we have B(cb, cs)= cs if cs is specified in
                     * the current color space all other color should get cb.
                     * Essentially the standard overprint case. */
                    for (i = 0, comps = drawn_comps; i < n_chan; ++i, comps >>= 1) {
                        if ((comps & 0x1) != 0) {
                            dst[i] = src[i];
                        } else {
                            dst[i] = backdrop[i];
                        }
                    }
                }
                break;
            }
        default:
#ifndef GS_THREADSAFE
            dlprintf1("art_blend_pixel_16: blend mode %d not implemented\n",
                      blend_mode);
#endif
            memcpy(dst, src, n_chan*2);
            break;
    }
}