Evas filters: Add offset parameter to vflip
authorJean-Philippe Andre <jp.andre@samsung.com>
Tue, 7 Jan 2014 09:38:22 +0000 (18:38 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Fri, 7 Feb 2014 08:33:17 +0000 (17:33 +0900)
It is not possible to logically handle padding and offset at the same
time for a proper mirror effect, unless this is handled directly at the
transformation level.

Also, add support for blend() operation padding computation.

src/lib/evas/filters/evas_filter.c
src/lib/evas/filters/evas_filter_parser.c
src/lib/evas/filters/evas_filter_transform.c
src/lib/evas/include/evas_filter.h

index c4ec46b..0f86852 100644 (file)
@@ -1048,9 +1048,11 @@ end:
 }
 
 int
-evas_filter_command_transform_add(Evas_Filter_Context *ctx, void *draw_context,
+evas_filter_command_transform_add(Evas_Filter_Context *ctx,
+                                  void *draw_context EINA_UNUSED,
                                   int inbuf, int outbuf,
-                                  Evas_Filter_Transform_Flags flags)
+                                  Evas_Filter_Transform_Flags flags,
+                                  int ox, int oy)
 {
    Evas_Filter_Command *cmd;
    Evas_Filter_Buffer *in, *out;
@@ -1076,6 +1078,8 @@ evas_filter_command_transform_add(Evas_Filter_Context *ctx, void *draw_context,
    if (!cmd) return -1;
 
    cmd->transform.flags = flags;
+   cmd->draw.ox = ox;
+   cmd->draw.oy = oy;
 
    return cmd->id;
 }
index d1546e6..d936abe 100644 (file)
@@ -684,6 +684,38 @@ _buffer_del(Buffer *buf)
 
 /* Instruction definitions */
 
+static void
+_blend_padding_update(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr,
+                      int *padl, int *padr, int *padt, int *padb)
+{
+   const char *outbuf;
+   Buffer *out;
+   int ox, oy, l = 0, r = 0, t = 0, b = 0;
+
+   ox = _instruction_param_geti(instr, "ox", NULL);
+   oy = _instruction_param_geti(instr, "oy", NULL);
+
+   outbuf = _instruction_param_gets(instr, "dst", NULL);
+   out = _buffer_get(pgm, outbuf);
+   EINA_SAFETY_ON_NULL_RETURN(out);
+
+   if (ox < 0) l = (-ox);
+   else r = ox;
+
+   if (oy < 0) t = (-oy);
+   else b = oy;
+
+   if (out->pad.l < l) out->pad.l = l;
+   if (out->pad.r < r) out->pad.r = r;
+   if (out->pad.t < t) out->pad.t = t;
+   if (out->pad.b < b) out->pad.b = b;
+
+   if (padl) *padl = l;
+   if (padr) *padr = r;
+   if (padt) *padt = t;
+   if (padb) *padb = b;
+}
+
 static Eina_Bool
 _blend_instruction_prepare(Evas_Filter_Instruction *instr)
 {
@@ -696,6 +728,7 @@ _blend_instruction_prepare(Evas_Filter_Instruction *instr)
    */
 
    instr->type = EVAS_FILTER_MODE_BLEND;
+   instr->pad.update = _blend_padding_update;
    _instruction_param_seq_add(instr, "src", VT_BUFFER, "input");
    _instruction_param_seq_add(instr, "dst", VT_BUFFER, "output");
    _instruction_param_seq_add(instr, "ox", VT_INT, 0);
@@ -1024,6 +1057,62 @@ _mask_instruction_prepare(Evas_Filter_Instruction *instr)
    return EINA_TRUE;
 }
 
+static void
+_transform_padding_update(Evas_Filter_Program *pgm,
+                          Evas_Filter_Instruction *instr,
+                          int *padl, int *padr, int *padt, int *padb)
+{
+   const char *outbuf;
+   Buffer *out;
+   int ox, oy, l = 0, r = 0, t = 0, b = 0;
+
+   //ox = _instruction_param_geti(instr, "ox", NULL);
+   ox = 0;
+   oy = _instruction_param_geti(instr, "oy", NULL);
+
+   outbuf = _instruction_param_gets(instr, "dst", NULL);
+   out = _buffer_get(pgm, outbuf);
+   EINA_SAFETY_ON_NULL_RETURN(out);
+
+   if (ox < 0) l = (-ox) * 2;
+   else r = ox * 2;
+
+   if (oy < 0) t = (-oy) * 2;
+   else b = oy * 2;
+
+   if (out->pad.l < l) out->pad.l = l;
+   if (out->pad.r < r) out->pad.r = r;
+   if (out->pad.t < t) out->pad.t = t;
+   if (out->pad.b < b) out->pad.b = b;
+
+   if (padl) *padl = l;
+   if (padr) *padr = r;
+   if (padt) *padt = t;
+   if (padb) *padb = b;
+}
+
+static Eina_Bool
+_transform_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, "transform"), EINA_FALSE);
+
+   /*
+    * mask [op=]STRING [input=BUFFER] [output=BUFFER] (oy=INT)
+    */
+
+   instr->type = EVAS_FILTER_MODE_TRANSFORM;
+   instr->pad.update = _transform_padding_update;
+   _instruction_param_seq_add(instr, "op", VT_STRING, "vflip");
+   _instruction_param_seq_add(instr, "src", VT_BUFFER, "input");
+   _instruction_param_seq_add(instr, "dst", VT_BUFFER, "output");
+   //_instruction_param_name_add(instr, "ox", VT_INT, 0);
+   _instruction_param_name_add(instr, "oy", VT_INT, 0);
+
+   return EINA_TRUE;
+}
+
 static Evas_Filter_Instruction *
 _instruction_create(const char *name)
 {
@@ -1048,6 +1137,8 @@ _instruction_create(const char *name)
      prepare = _grow_instruction_prepare;
    else if (!strcasecmp(name, "mask"))
      prepare = _mask_instruction_prepare;
+   else if (!strcasecmp(name, "transform"))
+     prepare = _transform_instruction_prepare;
 
    if (!prepare)
      {
@@ -1648,6 +1739,34 @@ interpolated:
 }
 
 static int
+_instr2cmd_transform(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm,
+                     Evas_Filter_Instruction *instr, void *dc)
+{
+   Evas_Filter_Transform_Flags flags;
+   const char *src, *dst, *op;
+   Buffer *in, *out;
+   int ox = 0, oy;
+
+   op = _instruction_param_gets(instr, "op", NULL);
+   src = _instruction_param_gets(instr, "src", NULL);
+   dst = _instruction_param_gets(instr, "dst", NULL);
+   // ox = _instruction_param_geti(instr, "ox", NULL);
+   oy = _instruction_param_geti(instr, "oy", NULL);
+
+   if (!strcasecmp(op, "vflip"))
+     flags = EVAS_FILTER_TRANSFORM_VFLIP;
+   else
+     {
+        ERR("Invalid transform '%s'", op);
+        return -1;
+     }
+
+   in = _buffer_get(pgm, src);
+   out = _buffer_get(pgm, dst);
+   return evas_filter_command_transform_add(ctx, dc, in->cid, out->cid, flags, ox, oy);
+}
+
+static int
 _command_from_instruction(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm,
                           Evas_Filter_Instruction *instr, void *dc)
 {
@@ -1680,6 +1799,9 @@ _command_from_instruction(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm,
       case EVAS_FILTER_MODE_CURVE:
         instr2cmd = _instr2cmd_curve;
         break;
+      case EVAS_FILTER_MODE_TRANSFORM:
+        instr2cmd = _instr2cmd_transform;
+        break;
       default:
         CRI("Invalid instruction type: %d", instr->type);
         return -1;
index 7ae81d6..bc9f65d 100644 (file)
@@ -5,7 +5,8 @@ _vflip_cpu(Evas_Filter_Command *cmd)
 {
    size_t datasize, stride;
    DATA8 *in, *out, *span;
-   int w, h, sy, dy;
+   int w, h, sy, dy, oy, center, t, b, objh;
+   int s0, s1, d0, d1;
 
    EINA_SAFETY_ON_NULL_RETURN_VAL(cmd, EINA_FALSE);
    EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input, EINA_FALSE);
@@ -24,23 +25,43 @@ _vflip_cpu(Evas_Filter_Command *cmd)
    datasize = cmd->input->alpha_only ? sizeof(DATA8) : sizeof(DATA32);
    stride = w * datasize;
 
+   oy = cmd->draw.oy;
+   t = cmd->ctx->padt;
+   b = cmd->ctx->padb;
+   objh = h - t - b;
+   center = t + objh / 2 + oy;
+
+   s0 = t;
+   s1 = h - b - 1;
+   if (oy >= 0)
+     {
+        d0 = center + (objh / 2) + oy;
+        d1 = center - (objh / 2) - oy;
+     }
+   else
+     {
+        d0 = center + (objh / 2) - oy;
+        d1 = center - (objh / 2) + oy;
+     }
+
    if (in == out)
      {
         span = malloc(stride);
         if (!span) return EINA_FALSE;
      }
 
-   for (sy = 0, dy = h - 1; dy >= 0; sy++, dy--)
+   for (sy = s0, dy = d0; (dy >= d1) && (sy <= s1); sy++, dy--)
      {
         DATA8* src = in + stride * sy;
         DATA8* dst = out + stride * dy;
 
         if (in == out)
           {
+             if (src == dst) break;
              memcpy(span, dst, stride);
              memcpy(dst, src, stride);
              memcpy(src, span, stride);
-             if (sy >= (h / 2)) break;
+             if (sy >= center) break;
           }
         else
           memcpy(dst, src, stride);
index 1d1a171..28623ee 100644 (file)
@@ -227,9 +227,11 @@ int                      evas_filter_command_bump_map_add(Evas_Filter_Context *c
  * @param inbuf          Input buffer (Alpha or RGBA)
  * @param outbuf         Output buffer (Alpha or RGBA), same size as inbuf
  * @param flags          Specifies the operation to apply (eg. vflip)
+ * @param ox             X offset
+ * @param oy             Y offset
  * @return               Filter command ID or -1 in case of error
  */
-int                      evas_filter_command_transform_add(Evas_Filter_Context *ctx, void *draw_context, int inbuf, int outbuf, Evas_Filter_Transform_Flags flags);
+int                      evas_filter_command_transform_add(Evas_Filter_Context *ctx, void *draw_context, int inbuf, int outbuf, Evas_Filter_Transform_Flags flags, int ox, int oy);
 
 #endif