1 #include "evas_engine_filter.h"
2 
3 /* Apply geometrical transformations to a buffer.
4  *
5  * This filter is a very simplistic at the moment, future improvements require
6  * more options to the API.
7  */
8 
9 static Eina_Bool
_vflip_cpu(Evas_Filter_Command * cmd)10 _vflip_cpu(Evas_Filter_Command *cmd)
11 {
12    unsigned int src_len, src_stride, dst_len, dst_stride;
13    uint8_t *in, *out = NULL;
14    int w, h, sy, dy, oy, center, t, b, objh;
15    Efl_Gfx_Colorspace cspace = cmd->output->alpha_only ? E_ALPHA : E_ARGB;
16    int s0, s1, d0, d1;
17    Eina_Bool ret = 0;
18 
19    if (!cmd->draw.A && (cmd->draw.rop == EFL_GFX_RENDER_OP_BLEND))
20      return EINA_TRUE;
21 
22    w = cmd->input->w;
23    h = cmd->input->h;
24    in = _buffer_map_all(cmd->input->buffer, &src_len, E_READ, cspace, &src_stride);
25    out = _buffer_map_all(cmd->output->buffer, &dst_len,
26                          E_WRITE | ECTOR_BUFFER_ACCESS_FLAG_COW,
27                          cspace, &dst_stride);
28 
29    EINA_SAFETY_ON_FALSE_GOTO(cmd->output->w == w, end);
30    EINA_SAFETY_ON_FALSE_GOTO(cmd->output->h == h, end);
31    EINA_SAFETY_ON_FALSE_GOTO(src_stride <= dst_stride, end);
32    EINA_SAFETY_ON_NULL_GOTO(in, end);
33    EINA_SAFETY_ON_NULL_GOTO(out, end);
34    EINA_SAFETY_ON_FALSE_GOTO(in != out, end);
35 
36    oy = cmd->draw.oy;
37    t = cmd->ctx->pad.final.t;
38    b = cmd->ctx->pad.final.b;
39    objh = h - t - b;
40    center = t + objh / 2 + oy;
41 
42    if (oy >= 0)
43      {
44         s1 = d0 = center + (objh / 2) + oy;
45         s0 = d1 = center - (objh / 2) - oy;
46      }
47    else
48      {
49         s1 = d0 = center + (objh / 2) - oy;
50         s0 = d1 = center - (objh / 2) + oy;
51      }
52 
53    /* avoid crashes */
54    d0 = CLAMP(0, d0, h - 1);
55    d1 = CLAMP(0, d1, h - 1);
56    s0 = CLAMP(0, s0, h - 1);
57    s1 = CLAMP(0, s1, h - 1);
58 
59    if (cmd->input->buffer == cmd->output->buffer)
60      {
61         /* flip a single buffer --> override its own contents */
62         for (sy = s0, dy = d0; (dy >= d1) && (sy <= s1); sy++, dy--)
63           {
64              uint8_t* src = in + src_stride * sy;
65              uint8_t* dst = out + dst_stride * dy;
66 
67              memcpy(dst, src, src_stride);
68           }
69      }
70    else if (cspace == E_ALPHA)
71      {
72         /* blend onto a target (alpha -> alpha) */
73         Draw_Func_Alpha func = efl_draw_alpha_func_get(cmd->draw.rop, EINA_FALSE);
74         EINA_SAFETY_ON_NULL_GOTO(func, end);
75 
76         for (sy = s0, dy = d0; (dy >= d1) && (sy <= s1); sy++, dy--)
77           {
78              uint8_t* src = in + src_stride * sy;
79              uint8_t* dst = out + dst_stride * dy;
80 
81              func(dst, src, w);
82           }
83      }
84    else
85      {
86         /* blend onto a target (rgba -> rgba) */
87         uint32_t color = ARGB_JOIN(cmd->draw.A, cmd->draw.R, cmd->draw.G, cmd->draw.B);
88         RGBA_Comp_Func func;
89 
90         func = efl_draw_func_span_get(cmd->draw.rop, color, EINA_TRUE);
91         EINA_SAFETY_ON_NULL_GOTO(func, end);
92 
93         for (sy = s0, dy = d0; (dy >= d1) && (sy <= s1); sy++, dy--)
94           {
95              uint32_t* src = (uint32_t *) (in + src_stride * sy);
96              uint32_t* dst = (uint32_t *) (out + dst_stride * dy);
97 
98              func(dst, src, w, color, 255);
99           }
100      }
101 
102    /* fill out outer areas */
103    if (cmd->draw.rop == EFL_GFX_RENDER_OP_COPY)
104      {
105         if (d1 > 0)
106           memset(out, 0, dst_stride * d1);
107         if (d0 < (h - 1))
108           memset(out + dst_stride * d0, 0, dst_stride * (h - d0 - 1));
109      }
110 
111    ret = EINA_TRUE;
112 
113 end:
114    ector_buffer_unmap(cmd->input->buffer, in, src_len);
115    ector_buffer_unmap(cmd->output->buffer, out, dst_len);
116    return ret;
117 }
118 
119 Software_Filter_Func
eng_filter_transform_func_get(Evas_Filter_Command * cmd)120 eng_filter_transform_func_get(Evas_Filter_Command *cmd)
121 {
122    EINA_SAFETY_ON_NULL_RETURN_VAL(cmd, NULL);
123 
124    switch (cmd->transform.flags)
125      {
126       case EVAS_FILTER_TRANSFORM_VFLIP:
127         return _vflip_cpu;
128       default:
129         CRI("Unknown transform flag %d", (int) cmd->transform.flags);
130         return NULL;
131      }
132 }
133