summaryrefslogtreecommitdiff
path: root/base/gxblend.c
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2017-10-05 14:37:37 +0100
committerRobin Watts <robin.watts@artifex.com>2017-10-05 19:43:57 +0100
commit882e0bfed09e839d53287164ebf4aa99ca5f116a (patch)
tree239cc94724cbcc8125c6e4e557e0a19a6beacb98 /base/gxblend.c
parent77cdf72595643da5d17e84fb72d8f58ccfe3d038 (diff)
downloadghostpdl-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.c389
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;
+}