Evas filters: Implement fill with padding
authorJean-Philippe Andre <jp.andre@samsung.com>
Thu, 2 Jan 2014 09:44:01 +0000 (18:44 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Fri, 7 Feb 2014 08:33:17 +0000 (17:33 +0900)
Add parameters l, r, t, b to clip the fill area.
While l=x and t=y, the width and height of the clip are determined
at filter run-time, since we don't know the buffer size before.

src/lib/evas/filters/evas_filter.c
src/lib/evas/filters/evas_filter_blend.c
src/lib/evas/filters/evas_filter_parser.c
src/lib/evas/filters/evas_filter_private.h

index daecc7363a0ae18cf9832d258261c0b73bbb55fe..2142962c0c82db5eb048aedf8010c0212cf6cc12 100644 (file)
@@ -24,7 +24,7 @@ static void _command_del(Evas_Filter_Context *ctx, Evas_Filter_Command *cmd);
 #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)
+#define DRAW_CLIP_SET(_x, _y, _w, _h) do { cmd->draw.clip.x = _x; cmd->draw.clip.y = _y; cmd->draw.clip.w = _w; cmd->draw.clip.h = _h; } while (0)
 #define DRAW_FILL_SET(fmode) do { cmd->draw.fillmode = fmode; } while (0)
 
 typedef struct _Evas_Filter_Thread_Command Evas_Filter_Thread_Command;
@@ -791,8 +791,8 @@ evas_filter_command_blend_add(Evas_Filter_Context *ctx, void *drawctx,
    cmd->draw.ox = ox;
    cmd->draw.oy = oy;
    cmd->draw.render_op = ENFN->context_render_op_get(ENDT, drawctx);
-   ENFN->context_clip_get(ENDT, drawctx, &cmd->draw.clipx, &cmd->draw.clipy,
-                          &cmd->draw.clipw, &cmd->draw.cliph);
+   ENFN->context_clip_get(ENDT, drawctx, &cmd->draw.clip.x, &cmd->draw.clip.y,
+                          &cmd->draw.clip.w, &cmd->draw.clip.h);
 
    return cmd->id;
 }
@@ -1057,19 +1057,29 @@ _fill_cpu(Evas_Filter_Command *cmd)
 {
    Evas_Filter_Buffer *fb = cmd->output;
    int step = fb->alpha_only ? sizeof(DATA8) : sizeof(DATA32);
-   int x = MAX(0, cmd->draw.clipx);
-   int y = MAX(0, cmd->draw.clipy);
+   int x = MAX(0, cmd->draw.clip.x);
+   int y = MAX(0, cmd->draw.clip.y);
    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);
+   if (!cmd->draw.clip_mode_lrtb)
+     {
+        if (cmd->draw.clip.w)
+          w = MIN(cmd->draw.clip.w, fb->w - x);
+        else
+          w = fb->w - x;
+        if (cmd->draw.clip.h)
+          h = MIN(cmd->draw.clip.h, fb->h - y);
+        else
+          h = fb->h - y;
+     }
    else
-     h = fb->h - y;
+     {
+        x = MAX(0, cmd->draw.clip.l);
+        y = MAX(0, cmd->draw.clip.t);
+        w = CLAMP(0, fb->w - x - cmd->draw.clip.r, fb->w - x);
+        h = CLAMP(0, fb->h - y - cmd->draw.clip.b, fb->h - y);
+     }
 
    ptr += y * step * fb->w;
    if ((fb->alpha_only)
@@ -1091,7 +1101,7 @@ _fill_cpu(Evas_Filter_Command *cmd)
           {
              for (j = 0; j < w; j++)
                *dst++ = color;
-             dst += fb->w;
+             dst += fb->w - w;
           }
      }
 
@@ -1187,7 +1197,8 @@ _filter_command_run(Evas_Filter_Command *cmd)
        cmd->id, _filter_name_get(cmd->mode),
        cmd->input->id, cmd->mask ? cmd->mask->id : 0, cmd->output->id);
 
-   if (!cmd->input->w && !cmd->input->h)
+   if (!cmd->input->w && !cmd->input->h
+       && (cmd->mode != EVAS_FILTER_MODE_FILL))
      {
         DBG("Skipping processing of empty input buffer (size 0x0)");
         return EINA_TRUE;
index 6781376e70b90c99b11885ec549ea911742e8b1e..ec988439c658b52bd73a3b82daaf8947ac748cc7 100644 (file)
@@ -92,8 +92,8 @@ _filter_blend_cpu_rgba(Evas_Filter_Command *cmd)
    cmd->ENFN->context_color_set(cmd->ENDT, drawctx, cmd->draw.R, cmd->draw.G,
                                 cmd->draw.B, cmd->draw.A);
    cmd->ENFN->context_render_op_set(cmd->ENDT, drawctx, cmd->draw.render_op);
-   cmd->ENFN->context_clip_set(cmd->ENDT, drawctx, cmd->draw.clipx,
-                               cmd->draw.clipy, cmd->draw.clipw, cmd->draw.cliph);
+   cmd->ENFN->context_clip_set(cmd->ENDT, drawctx, cmd->draw.clip.x,
+                               cmd->draw.clip.y, cmd->draw.clip.w, cmd->draw.clip.h);
 
    cmd->ENFN->image_draw(cmd->ENDT, drawctx, out, in,
                          0, 0, w, h, // src
index cb9f2d9ba738477e0bd3187dd3252be4e4a99461..0b64b770288f88ca794d63f10a0ebc7f6f4da8c0 100644 (file)
@@ -926,13 +926,22 @@ _fill_instruction_prepare(Evas_Filter_Instruction *instr)
    EINA_SAFETY_ON_FALSE_RETURN_VAL(!strcasecmp(instr->name, "fill"), EINA_FALSE);
 
    /*
-   * fill [dst=]BUFFER [color=COLOR]
+   * fill [dst=BUFFER] [color=COLOR] (l=INT) (r=INT) (t=INT) (b=INT)
+   *
    * Works with both Alpha and RGBA.
+   *
+   * The geometry is defined by l, r, t, b, offsets from the edges of the buffer
+   * These offsets always go INWARDS, which means b > 0 goes UP, while t > 0
+   * goes DOWN.
    */
 
    instr->type = EVAS_FILTER_MODE_FILL;
-   _instruction_param_seq_add(instr, "dst", VT_BUFFER, NULL);
+   _instruction_param_seq_add(instr, "dst", VT_BUFFER, "output");
    _instruction_param_seq_add(instr, "color", VT_COLOR, 0x0);
+   _instruction_param_seq_add(instr, "l", VT_INT, 0);
+   _instruction_param_seq_add(instr, "r", VT_INT, 0);
+   _instruction_param_seq_add(instr, "t", VT_INT, 0);
+   _instruction_param_seq_add(instr, "b", VT_INT, 0);
 
    return EINA_TRUE;
 }
@@ -1308,6 +1317,12 @@ evas_filter_program_proxy_source_get(Evas_Filter_Program *pgm, const char *name)
 #define SETCOLOR(c) do { ENFN->context_color_get(ENDT, dc, &R, &G, &B, &A); \
    ENFN->context_color_set(ENDT, dc, CR(c), CG(c), CB(c), CA(c)); } while (0)
 #define RESETCOLOR() do { ENFN->context_color_set(ENDT, dc, R, G, B, A); } while (0)
+
+#define SETCLIP(l, r, t, b) int _l = 0, _r = 0, _t = 0, _b = 0; \
+   do { ENFN->context_clip_get(ENDT, dc, &_l, &_r, &_t, &_b); \
+   ENFN->context_clip_set(ENDT, dc, l, r, t, b); } while (0)
+#define RESETCLIP() do { ENFN->context_clip_set(ENDT, dc, _l, _r, _t, _b); } while (0)
+
 int A, R, G, B;
 
 static Evas_Filter_Fill_Mode
@@ -1473,13 +1488,17 @@ _instr2cmd_fill(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm,
 {
    const char *bufname;
    Buffer *buf;
-   int R, G, B, A;
+   int R, G, B, A, l, r, t, b;
+   Evas_Filter_Command *cmd;
    DATA32 color;
    int cmdid;
 
    bufname = _instruction_param_gets(instr, "dst", NULL);
    color = _instruction_param_getc(instr, "color", NULL);
-   // TODO/FIXME: Add clip info
+   l = _instruction_param_geti(instr, "l", NULL);
+   r = _instruction_param_geti(instr, "r", NULL);
+   t = _instruction_param_geti(instr, "t", NULL);
+   b = _instruction_param_geti(instr, "b", NULL);
 
    buf = _buffer_get(pgm, bufname);
 
@@ -1487,6 +1506,13 @@ _instr2cmd_fill(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm,
    cmdid = evas_filter_command_fill_add(ctx, dc, buf->cid);
    RESETCOLOR();
 
+   cmd = EINA_INLIST_CONTAINER_GET(eina_inlist_last(ctx->commands), Evas_Filter_Command);
+   cmd->draw.clip.l = l;
+   cmd->draw.clip.r = r;
+   cmd->draw.clip.t = t;
+   cmd->draw.clip.b = b;
+   cmd->draw.clip_mode_lrtb = EINA_TRUE;
+
    return cmdid;
 }
 
index 0a0c85e3c44f1db29702e0d29ba0bb8379cef17a..1357a3f786e95672f51ee2dfae9a25defbd672ed 100644 (file)
@@ -106,8 +106,16 @@ struct _Evas_Filter_Command
       int render_op;
       int R, G, B, A;
       int ox, oy;
-      int clipx, clipy, clipw, cliph;
+      union {
+         struct {
+            int x, y, w, h;
+         };
+         struct {
+            int l, r, t, b;
+         };
+      } clip;
       Evas_Filter_Fill_Mode fillmode;
+      Eina_Bool clip_mode_lrtb : 1;
    } draw;
 };