diff options
author | Robin Watts <robin.watts@artifex.com> | 2017-10-05 14:37:37 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2017-10-05 19:43:57 +0100 |
commit | 882e0bfed09e839d53287164ebf4aa99ca5f116a (patch) | |
tree | 239cc94724cbcc8125c6e4e557e0a19a6beacb98 /base/gxblend.c | |
parent | 77cdf72595643da5d17e84fb72d8f58ccfe3d038 (diff) | |
download | ghostpdl-882e0bfed09e839d53287164ebf4aa99ca5f116a.tar.gz |
Optimise pdf14_mark_fill_rectangle using inlining.
Same tricks as used for pdf14_compose_group.
Diffstat (limited to 'base/gxblend.c')
-rw-r--r-- | base/gxblend.c | 389 |
1 files changed, 331 insertions, 58 deletions
diff --git a/base/gxblend.c b/base/gxblend.c index 6bd06dbfe..1bf119448 100644 --- a/base/gxblend.c +++ b/base/gxblend.c @@ -25,6 +25,7 @@ #include "gsicc_manage.h" #include "gdevp14.h" #include "gsrect.h" /* for rect_merge */ +#include "math_.h" /* for ceil, floor */ typedef int art_s32; @@ -1025,64 +1026,6 @@ art_pdf_composite_pixel_alpha_8_inline(byte *dst, byte *src, int n_chan, } void -art_pdf_composite_pixel_alpha_8_fast(byte *dst, const byte *src, int n_chan, - gs_blend_mode_t blend_mode, - const pdf14_nonseparable_blending_procs_t * pblend_procs, - int stride, pdf14_device *p14dev) -{ - byte a_b, a_s; - unsigned int a_r; - int tmp; - int src_scale; - int c_b, c_s; - int i; - - a_s = src[n_chan]; - - a_b = dst[n_chan * stride]; - - /* Result alpha is Union of backdrop and source alpha */ - tmp = (0xff - a_b) * (0xff - a_s) + 0x80; - a_r = 0xff - (((tmp >> 8) + tmp) >> 8); - /* todo: verify that a_r is nonzero in all cases */ - - /* Compute a_s / a_r in 16.16 format */ - src_scale = ((a_s << 16) + (a_r >> 1)) / a_r; - - if (blend_mode == BLEND_MODE_Normal) { - /* Do simple compositing of source over backdrop */ - for (i = 0; i < n_chan; i++) { - c_s = src[i]; - c_b = dst[i * stride]; - tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000; - dst[i * stride] = tmp >> 16; - } - } else { - /* Do compositing with blending */ - byte blend[ART_MAX_CHAN]; - byte dst_tmp[ART_MAX_CHAN]; - - for (i = 0; i < n_chan; i++) { - dst_tmp[i] = dst[i * stride]; - } - art_blend_pixel_8(blend, dst_tmp, src, n_chan, blend_mode, pblend_procs, p14dev); - for (i = 0; i < n_chan; i++) { - int c_bl; /* Result of blend function */ - int c_mix; /* Blend result mixed with source color */ - - c_s = src[i]; - c_b = dst_tmp[i]; - c_bl = blend[i]; - tmp = a_b * (c_bl - ((int)c_s)) + 0x80; - c_mix = c_s + (((tmp >> 8) + tmp) >> 8); - tmp = (c_b << 16) + src_scale * (c_mix - c_b) + 0x8000; - dst[i * stride] = tmp >> 16; - } - } - dst[n_chan * stride] = a_r; -} - -void art_pdf_composite_pixel_alpha_8_fast_mono(byte *dst, const byte *src, gs_blend_mode_t blend_mode, const pdf14_nonseparable_blending_procs_t * pblend_procs, @@ -2028,3 +1971,333 @@ pdf14_compose_group(pdf14_buf *tos, pdf14_buf *nos, pdf14_buf *maskbuf, global_index++; #endif } + +typedef void (*pdf14_mark_fill_rect_fn)(int w, int h, byte *dst_ptr, byte *src, int num_comp, int num_spots, int first_blend_spot, + byte src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode, + bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag, + int alpha_g_off, int shape_off, byte shape); + +static forceinline void +template_mark_fill_rect(int w, int h, byte *dst_ptr, byte *src, int num_comp, int num_spots, int first_blend_spot, + byte src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode, + bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag, + int alpha_g_off, int shape_off, byte shape) +{ + int i, j, k; + gx_color_index comps; + byte dst[PDF14_MAX_PLANES] = { 0 }; + + for (j = h; j > 0; --j) { + for (i = w; i > 0; --i) { + /* If source alpha is zero avoid all of this */ + if (src[num_comp] != 0) { + if (dst_ptr[num_comp * planestride] == 0) { + /* dest alpha is zero just use source. */ + if (additive) { + /* Hybrid case */ + for (k = 0; k < (num_comp - num_spots); k++) { + dst_ptr[k * planestride] = src[k]; + } + for (k = 0; k < num_spots; k++) { + dst_ptr[(k + num_comp - num_spots) * planestride] = + 255 - src[k + num_comp - num_spots]; + } + } else { + /* Pure subtractive */ + for (k = 0; k < num_comp; k++) { + dst_ptr[k * planestride] = 255 - src[k]; + } + } + /* alpha */ + dst_ptr[num_comp * planestride] = src[num_comp]; + } else { + byte *pdst; + /* Complement subtractive planes */ + if (!additive) { + /* Pure subtractive */ + for (k = 0; k < num_comp; ++k) + dst[k] = 255 - dst_ptr[k * planestride]; + } else { + /* Hybrid case, additive with subtractive spots */ + for (k = 0; k < (num_comp - num_spots); k++) { + dst[k] = dst_ptr[k * planestride]; + } + for (k = 0; k < num_spots; k++) { + dst[k + num_comp - num_spots] = + 255 - dst_ptr[(k + num_comp - num_spots) * planestride]; + } + } + dst[num_comp] = dst_ptr[num_comp * planestride]; + pdst = art_pdf_composite_pixel_alpha_8_inline(dst, src, num_comp, blend_mode, first_blend_spot, + pdev->blend_procs, pdev); + /* Until I see otherwise in AR or the spec, do not fool + with spot overprinting while we are in an RGB or Gray + blend color space. */ + if (!additive && overprint) { + for (k = 0, comps = drawn_comps; comps != 0; ++k, comps >>= 1) { + if ((comps & 0x1) != 0) { + dst_ptr[k * planestride] = 255 - pdst[k]; + } + } + } else { + /* Post blend complement for subtractive */ + if (!additive) { + /* Pure subtractive */ + for (k = 0; k < num_comp; ++k) + dst_ptr[k * planestride] = 255 - pdst[k]; + + } else { + /* Hybrid case, additive with subtractive spots */ + for (k = 0; k < (num_comp - num_spots); k++) { + dst_ptr[k * planestride] = pdst[k]; + } + for (k = 0; k < num_spots; k++) { + dst_ptr[(k + num_comp - num_spots) * planestride] = + 255 - pdst[k + num_comp - num_spots]; + } + } + } + /* The alpha channel */ + dst_ptr[num_comp * planestride] = pdst[num_comp]; + } + if (tag_off) { + /* If src alpha is 100% then set to curr_tag, else or */ + /* other than Normal BM, we always OR */ + if (src[num_comp] == 255 && blend_mode == BLEND_MODE_Normal) { + dst_ptr[tag_off] = curr_tag; + } else { + dst_ptr[tag_off] |= curr_tag; + } + } + } + if (alpha_g_off) { + int tmp = (255 - dst_ptr[alpha_g_off]) * src_alpha + 0x80; + dst_ptr[alpha_g_off] = 255 - ((tmp + (tmp >> 8)) >> 8); + } + if (shape_off) { + int tmp = (255 - dst_ptr[shape_off]) * shape + 0x80; + dst_ptr[shape_off] = 255 - ((tmp + (tmp >> 8)) >> 8); + } + ++dst_ptr; + } + dst_ptr += rowstride; + } +} + +static void +mark_fill_rect(int w, int h, byte *dst_ptr, byte *src, int num_comp, int num_spots, int first_blend_spot, + byte src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode, + bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag, + int alpha_g_off, int shape_off, byte shape) +{ + template_mark_fill_rect(w, h, dst_ptr, src, num_comp, num_spots, first_blend_spot, + src_alpha, rowstride, planestride, additive, pdev, blend_mode, + overprint, drawn_comps, tag_off, curr_tag, + alpha_g_off, shape_off, shape); +} + +static void +mark_fill_rect_additive_nospots(int w, int h, byte *dst_ptr, byte *src, int num_comp, int num_spots, int first_blend_spot, + byte src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode, + bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag, + int alpha_g_off, int shape_off, byte shape) +{ + template_mark_fill_rect(w, h, dst_ptr, src, num_comp, /*num_spots*/0, first_blend_spot, + src_alpha, rowstride, planestride, /*additive*/1, pdev, blend_mode, + /*overprint*/0, /*drawn_comps*/0, tag_off, curr_tag, + alpha_g_off, shape_off, shape); +} + +static void +mark_fill_rect_additive_nospots_common(int w, int h, byte *dst_ptr, byte *src, int num_comp, int num_spots, int first_blend_spot, + byte src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode, + bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag, + int alpha_g_off, int shape_off, byte shape) +{ + template_mark_fill_rect(w, h, dst_ptr, src, num_comp, /*num_spots*/0, first_blend_spot, + src_alpha, rowstride, planestride, /*additive*/1, pdev, /*blend_mode*/BLEND_MODE_Normal, + /*overprint*/0, /*drawn_comps*/0, /*tag_off*/0, curr_tag, + alpha_g_off, /*shape_off*/0, shape); +} + + +static void +mark_fill_rect_1comp_additive_no_spots(int w, int h, byte *dst_ptr, byte *src, int num_comp, int num_spots, int first_blend_spot, + byte src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode, + bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag, + int alpha_g_off, int shape_off, byte shape) +{ + int i, j; + + for (j = h; j > 0; --j) { + for (i = w; i > 0; --i) { + if (src[1] != 0) { + /* background empty, nothing to change */ + if (dst_ptr[planestride] == 0) { + dst_ptr[0] = src[0]; + dst_ptr[planestride] = src[1]; + } else { + art_pdf_composite_pixel_alpha_8_fast_mono(dst_ptr, src, + blend_mode, pdev->blend_procs, + planestride, pdev); + } + if (tag_off) { + /* If src alpha is 100% then set to curr_tag, else or */ + /* other than Normal BM, we always OR */ + if (src[1] == 255 && blend_mode == BLEND_MODE_Normal) { + dst_ptr[tag_off] = curr_tag; + } else { + dst_ptr[tag_off] |= curr_tag; + } + } + } + if (alpha_g_off) { + int tmp = (255 - dst_ptr[alpha_g_off]) * src_alpha + 0x80; + dst_ptr[alpha_g_off] = 255 - ((tmp + (tmp >> 8)) >> 8); + } + if (shape_off) { + int tmp = (255 - dst_ptr[shape_off]) * shape + 0x80; + dst_ptr[shape_off] = 255 - ((tmp + (tmp >> 8)) >> 8); + } + ++dst_ptr; + } + dst_ptr += rowstride; + } +} + +int +pdf14_mark_fill_rectangle(gx_device * dev, int x, int y, int w, int h, + gx_color_index color, const gx_device_color *pdc, + bool devn) +{ + pdf14_device *pdev = (pdf14_device *)dev; + pdf14_buf *buf = pdev->ctx->stack; + int j; + byte *dst_ptr; + byte src[PDF14_MAX_PLANES]; + gs_blend_mode_t blend_mode = pdev->blend_mode; + bool additive = pdev->ctx->additive; + int rowstride = buf->rowstride; + int planestride = buf->planestride; + gs_graphics_type_tag_t curr_tag = GS_UNKNOWN_TAG; /* Quite compiler */ + bool has_alpha_g = buf->has_alpha_g; + bool has_shape = buf->has_shape; + bool has_tags = buf->has_tags; + int num_chan = buf->n_chan; + int num_comp = num_chan - 1; + int shape_off = num_chan * planestride; + int alpha_g_off = shape_off + (has_shape ? planestride : 0); + int tag_off = alpha_g_off + (has_alpha_g ? planestride : 0); + bool overprint = pdev->overprint; + gx_color_index drawn_comps = pdev->drawn_comps; + byte shape = 0; /* Quiet compiler. */ + byte src_alpha; + const gx_color_index mask = ((gx_color_index)1 << 8) - 1; + const int shift = 8; + int num_spots = buf->num_spots; + int first_blend_spot = num_comp; + pdf14_mark_fill_rect_fn fn; + + if (num_spots > 0 && !blend_valid_for_spot(blend_mode)) + first_blend_spot = num_comp - num_spots; + if (blend_mode == BLEND_MODE_Normal) + first_blend_spot = 0; + + if (buf->data == NULL) + return 0; + /* NB: gx_color_index is 4 or 8 bytes */ +#if 0 + if (sizeof(color) <= sizeof(ulong)) + if_debug8m('v', dev->memory, + "[v]pdf14_mark_fill_rectangle, (%d, %d), %d x %d color = %lx bm %d, nc %d, overprint %d\n", + x, y, w, h, (ulong)color, blend_mode, num_chan, overprint); + else + if_debug9m('v', dev->memory, + "[v]pdf14_mark_fill_rectangle, (%d, %d), %d x %d color = %08lx%08lx bm %d, nc %d, overprint %d\n", + x, y, w, h, + (ulong)(color >> 8*(sizeof(color) - sizeof(ulong))), (ulong)color, + blend_mode, num_chan, overprint); +#endif + /* + * Unpack the gx_color_index values. Complement the components for subtractive + * color spaces. + */ + if (has_tags) { + curr_tag = (color >> (num_comp*8)) & 0xff; + } + if (devn) { + if (additive) { + for (j = 0; j < (num_comp - num_spots); j++) { + src[j] = ((pdc->colors.devn.values[j]) >> shift & mask); + } + for (j = 0; j < num_spots; j++) { + src[j + num_comp - num_spots] = + 255 - ((pdc->colors.devn.values[j + num_comp - num_spots]) >> shift & mask); + } + } else { + for (j = 0; j < num_comp; j++) { + src[j] = 255 - ((pdc->colors.devn.values[j]) >> shift & mask); + } + } + } else + pdev->pdf14_procs->unpack_color(num_comp, color, pdev, src); + src_alpha = src[num_comp] = (byte)floor (255 * pdev->alpha + 0.5); + if (has_shape) + shape = (byte)floor (255 * pdev->shape + 0.5); + /* Fit the mark into the bounds of the buffer */ + if (x < buf->rect.p.x) { + w += x - buf->rect.p.x; + x = buf->rect.p.x; + } + if (y < buf->rect.p.y) { + h += y - buf->rect.p.y; + y = buf->rect.p.y; + } + if (x + w > buf->rect.q.x) w = buf->rect.q.x - x; + if (y + h > buf->rect.q.y) h = buf->rect.q.y - y; + /* Update the dirty rectangle with the mark */ + if (x < buf->dirty.p.x) buf->dirty.p.x = x; + if (y < buf->dirty.p.y) buf->dirty.p.y = y; + if (x + w > buf->dirty.q.x) buf->dirty.q.x = x + w; + if (y + h > buf->dirty.q.y) buf->dirty.q.y = y + h; + dst_ptr = buf->data + (x - buf->rect.p.x) + (y - buf->rect.p.y) * rowstride; + src_alpha = 255-src_alpha; + shape = 255-shape; + if (!has_alpha_g) + alpha_g_off = 0; + if (!has_shape) + shape_off = 0; + if (!has_tags) + tag_off = 0; + rowstride -= w; + /* The num_comp == 1 && additive case is very common (mono output + * devices no spot support), so we optimise that specifically here. */ + if (additive && num_spots == 0) { + if (num_comp == 1) + fn = mark_fill_rect_1comp_additive_no_spots; + else if (tag_off == 0 && shape_off == 0 && blend_mode == BLEND_MODE_Normal) + fn = mark_fill_rect_additive_nospots_common; + else + fn = mark_fill_rect_additive_nospots; + } else + fn = mark_fill_rect; + + fn(w, h, dst_ptr, src, num_comp, num_spots, first_blend_spot, src_alpha, + rowstride, planestride, additive, pdev, blend_mode, overprint, + drawn_comps, tag_off, curr_tag, alpha_g_off, shape_off, shape); + +#if 0 +/* #if RAW_DUMP */ + /* Dump the current buffer to see what we have. */ + + if(global_index/10.0 == (int) (global_index/10.0) ) + dump_raw_buffer(pdev->ctx->stack->rect.q.y-pdev->ctx->stack->rect.p.y, + pdev->ctx->stack->rect.q.x-pdev->ctx->stack->rect.p.x, + pdev->ctx->stack->n_planes, + pdev->ctx->stack->planestride, pdev->ctx->stack->rowstride, + "Draw_Rect",pdev->ctx->stack->data); + + global_index++; +#endif + return 0; +} |