diff --git a/src/lib/evas/filters/evas_filter.c b/src/lib/evas/filters/evas_filter.c index 8b5b2588fb..6f2f9896c6 100644 --- a/src/lib/evas/filters/evas_filter.c +++ b/src/lib/evas/filters/evas_filter.c @@ -18,7 +18,13 @@ static void _buffer_free(Evas_Filter_Buffer *fb); static void _command_del(Evas_Filter_Context *ctx, Evas_Filter_Command *cmd); +#ifdef CLAMP +# undef CLAMP +#endif +#define CLAMP(a,b,c) MIN(MAX((b),(a)),(c)) + #define DRAW_COLOR_SET(r, g, b, a) do { cmd->draw.R = r; cmd->draw.G = g; cmd->draw.B = b; cmd->draw.A = a; } while (0) +#define DRAW_CLIP_SET(x, y, w, h) do { cmd->draw.clipx = x; cmd->draw.clipy = y; cmd->draw.clipw = w; cmd->draw.cliph = h; } while (0) typedef struct _Evas_Filter_Thread_Command Evas_Filter_Thread_Command; struct _Evas_Filter_Thread_Command @@ -537,6 +543,36 @@ _filter_buffer_unlock_all(Evas_Filter_Context *ctx) buf->locked = EINA_FALSE; } +int +evas_filter_command_fill_add(Evas_Filter_Context *ctx, void *draw_context, + int bufid) +{ + Evas_Filter_Command *cmd; + Evas_Filter_Buffer *buf = NULL; + int R, G, B, A, cx, cy, cw, ch; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1); + EINA_SAFETY_ON_NULL_RETURN_VAL(draw_context, -1); + + buf = _filter_buffer_get(ctx, bufid); + if (!buf) + { + ERR("Buffer %d does not exist.", bufid); + return -1; + } + + cmd = _command_new(ctx, EVAS_FILTER_MODE_FILL, buf, NULL, NULL); + if (!cmd) return -1; + + ENFN->context_color_get(ENDT, draw_context, &R, &G, &B, &A); + DRAW_COLOR_SET(R, G, B, A); + + ENFN->context_clip_get(ENDT, draw_context, &cx, &cy, &cw, &ch); + DRAW_CLIP_SET(cx, cy, cw, ch); + + return cmd->id; +} + int evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx, int inbuf, int outbuf, Evas_Filter_Blur_Type type, @@ -551,6 +587,7 @@ evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx, int ret = 0, id; EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1); + EINA_SAFETY_ON_NULL_RETURN_VAL(drawctx, -1); switch (type) { @@ -1005,6 +1042,61 @@ end: return cmdid; } +static Eina_Bool +_fill_cpu(Evas_Filter_Command *cmd) +{ + Evas_Filter_Buffer *fb = cmd->input; + int step = fb->alpha_only ? sizeof(DATA8) : sizeof(DATA32); + int x = MAX(0, cmd->draw.clipx); + int y = MAX(0, cmd->draw.clipy); + DATA8 *ptr = ((RGBA_Image *) fb->backing)->mask.data; + int w, h, k, j; + + if (cmd->draw.clipw) + w = MIN(cmd->draw.clipw, fb->w); + else + w = fb->w - x; + if (cmd->draw.cliph) + h = MIN(cmd->draw.cliph, fb->h); + else + h = fb->h - y; + + ptr += y * step * fb->w; + if ((fb->alpha_only) + || (!cmd->draw.R && !cmd->draw.G && !cmd->draw.B && !cmd->draw.A) + || ((cmd->draw.R == 0xff) && (cmd->draw.G == 0xff) + && (cmd->draw.B == 0xff) && (cmd->draw.A == 0xff))) + { + for (k = 0; k < h; k++) + { + memset(ptr + (x * step), cmd->draw.A, step * w); + ptr += step * fb->w; + } + } + else + { + DATA32 *dst = ((DATA32 *) ptr) + x; + DATA32 color = ARGB_JOIN(cmd->draw.A, cmd->draw.R, cmd->draw.G, cmd->draw.B); + for (k = 0; k < h; k++) + { + for (j = 0; j < w; j++) + *dst++ = color; + dst += fb->w; + } + } + + return EINA_TRUE; +} + +Evas_Filter_Apply_Func +evas_filter_fill_cpu_func_get(Evas_Filter_Command *cmd) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(cmd, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input, NULL); + return _fill_cpu; +} + + /* Clip full input rect (0, 0, sw, sh) to target (dx, dy, dw, dh) * and get source's clipped sx, sy as well as destination x, y, cols and rows */ void @@ -1130,6 +1222,9 @@ _filter_command_run(Evas_Filter_Command *cmd) case EVAS_FILTER_MODE_DISPLACE: func = evas_filter_displace_cpu_func_get(cmd); break; + case EVAS_FILTER_MODE_FILL: + func = evas_filter_fill_cpu_func_get(cmd); + break; case EVAS_FILTER_MODE_MASK: func = evas_filter_mask_cpu_func_get(cmd); break; diff --git a/src/lib/evas/filters/evas_filter_parser.c b/src/lib/evas/filters/evas_filter_parser.c index b781bfd577..57e99b0dfb 100644 --- a/src/lib/evas/filters/evas_filter_parser.c +++ b/src/lib/evas/filters/evas_filter_parser.c @@ -860,6 +860,25 @@ _displace_instruction_prepare(Evas_Filter_Instruction *instr) return EINA_TRUE; } +static Eina_Bool +_fill_instruction_prepare(Evas_Filter_Instruction *instr) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(instr, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(instr->name, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(!strcasecmp(instr->name, "fill"), EINA_FALSE); + + /* + * fill [dst=]BUFFER [color=COLOR] + * Works with both Alpha and RGBA. + */ + + instr->type = EVAS_FILTER_MODE_BUFFER; + _instruction_param_seq_add(instr, "dst", VT_BUFFER, NULL); + _instruction_param_seq_add(instr, "color", VT_COLOR, 0x0); + + return EINA_TRUE; +} + static void _grow_padding_update(Evas_Filter_Instruction *instr, int *l, int *r, int *t, int *b) @@ -941,6 +960,8 @@ _instruction_create(const char *name) prepare = _curve_instruction_prepare; else if (!strcasecmp(name, "displace")) prepare = _displace_instruction_prepare; + else if (!strcasecmp(name, "fill")) + prepare = _fill_instruction_prepare; else if (!strcasecmp(name, "grow")) prepare = _grow_instruction_prepare; else if (!strcasecmp(name, "mask")) @@ -1318,6 +1339,30 @@ _instr2cmd_displace(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm, return cmdid; } +static int +_instr2cmd_fill(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm, + Evas_Filter_Instruction *instr, void *dc) +{ + const char *bufname; + Buffer *buf; + int R, G, B, A; + DATA32 color; + int cmdid; + + bufname = _instruction_param_gets(instr, "dst", NULL); + color = _instruction_param_getc(instr, "color", NULL); + // TODO/FIXME: Add clip info + + buf = _buffer_get(pgm, bufname); + + ENFN->context_color_get(ENDT, dc, &R, &G, &B, &A); + ENFN->context_color_set(ENDT, dc, R_VAL(&color), G_VAL(&color), B_VAL(&color), A_VAL(&color)); + cmdid = evas_filter_command_fill_add(ctx, dc, buf->cid); + ENFN->context_color_set(ENDT, dc, R, G, B, A); + + return cmdid; +} + static int _instr2cmd_grow(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr, void *dc) @@ -1389,6 +1434,9 @@ _command_from_instruction(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm, case EVAS_FILTER_MODE_DISPLACE: instr2cmd = _instr2cmd_displace; break; + case EVAS_FILTER_MODE_FILL: + instr2cmd = _instr2cmd_fill; + break; case EVAS_FILTER_MODE_GROW: instr2cmd = _instr2cmd_grow; break; diff --git a/src/lib/evas/filters/evas_filter_private.h b/src/lib/evas/filters/evas_filter_private.h index e3cd41f951..f7cb109e72 100644 --- a/src/lib/evas/filters/evas_filter_private.h +++ b/src/lib/evas/filters/evas_filter_private.h @@ -130,6 +130,7 @@ Evas_Filter_Apply_Func evas_filter_blur_cpu_func_get(Evas_Filter_Command *cmd) Evas_Filter_Apply_Func evas_filter_bump_map_cpu_func_get(Evas_Filter_Command *cmd); Evas_Filter_Apply_Func evas_filter_curve_cpu_func_get(Evas_Filter_Command *cmd); Evas_Filter_Apply_Func evas_filter_displace_cpu_func_get(Evas_Filter_Command *cmd); +Evas_Filter_Apply_Func evas_filter_fill_cpu_func_get(Evas_Filter_Command *cmd); Evas_Filter_Apply_Func evas_filter_mask_cpu_func_get(Evas_Filter_Command *cmd); /* Utility functions */ diff --git a/src/lib/evas/include/evas_filter.h b/src/lib/evas/include/evas_filter.h index f599707deb..8a3c02a368 100644 --- a/src/lib/evas/include/evas_filter.h +++ b/src/lib/evas/include/evas_filter.h @@ -26,6 +26,7 @@ enum _Evas_Filter_Mode EVAS_FILTER_MODE_BLUR, /**< @see Evas_Filter_Blur_Type */ EVAS_FILTER_MODE_CURVE, /**< Apply color curve */ EVAS_FILTER_MODE_DISPLACE, /**< Apply XY displacement based on RG mask */ + EVAS_FILTER_MODE_FILL, /**< Fill a buffer with a solid color */ EVAS_FILTER_MODE_MASK, /**< Apply Alpha or RGBA texture on image */ EVAS_FILTER_MODE_BUMP, /**< Apply bump mapping (light effect) */ EVAS_FILTER_MODE_LAST @@ -125,6 +126,17 @@ int evas_filter_command_blend_add(Evas_Filter_Context *ctx, */ int evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *draw_context, int inbuf, int outbuf, Evas_Filter_Blur_Type type, int dx, int dy, int ox, int oy); +/** + * @brief Fill a buffer with the current color + * @param ctx Current filter chain + * @param draw_context Current Evas draw context. Current color is used when buf is RGBA, and clip is used to specify the fill area. + * @param buf Buffer: ALPHA or RGBA + * @return Filter command ID or -1 in case of error + * @note The current draw context's render operation is ignored (always uses COPY mode). + */ +int evas_filter_command_fill_add(Evas_Filter_Context *ctx, void *draw_context, int buf); +int evas_filter_command_curve_add(Evas_Filter_Context *ctx, void *draw_context, int inbuf, int outbuf, DATA8 *curve /* 256 elements */, Evas_Filter_Channel channel); + /** * @brief Grow/Shrink an image, as defined in image processing (this is not a scale algorithm!) * @param ctx Current filter chain @@ -136,7 +148,6 @@ int evas_filter_command_blur_add(Evas_Filter_Context *ctx, * @return Filter command ID or -1 in case of error */ int evas_filter_command_grow_add(Evas_Filter_Context *ctx, void *draw_context, int inbuf, int outbuf, int radius, Eina_Bool smooth); -int evas_filter_command_curve_add(Evas_Filter_Context *ctx, void *draw_context, int inbuf, int outbuf, DATA8 *curve /* 256 elements */, Evas_Filter_Channel channel); /** * @brief Apply a displacement map to a buffer. This will move pixels from the source to the destination based on pixel per pixel offset, as defined in the displacement map