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