summaryrefslogtreecommitdiff
path: root/src/static_libs
diff options
context:
space:
mode:
authorHermet Park <hermetpark@gmail.com>2019-06-21 17:30:19 +0900
committerHermet Park <hermetpark@gmail.com>2019-06-21 17:35:48 +0900
commit23af6ec640c4166aa912f8d6be1e3b78b0780913 (patch)
treeb844eb6e5dab6dccdb8dda72d028fda3958e7c69 /src/static_libs
parent1c02b7740de0938bcbad2e26ee055ad570cdf77c (diff)
evas vector: support json loader for rlottie integration.
Summary: Introduce a new evas json loader to support lottie animation. This json loader uses rlottie library which is a new github open project. These days most ui frameworks (windowpws, skia, qt, xamarin, react, nativescript) supports lottie, the rlottie was designed to support lottie as a standalone library and compatible with efl as well. To enable this,please install rlottie library then remove json disabler in meson_options.txt For more information, See lottie/rlottie project and its a introdcution article: https://airbnb.io/lottie/#/ https://github.com/samsung/rlottie https://hermet.pe.kr/143 Co-authored-by: JunsuChoi <jsuya.choi@samsung.com> {D8941} {D8944} Reviewers: #committers, jsuya, bu5hm4n Subscribers: bu5hm4n, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D8940
Diffstat (limited to 'src/static_libs')
-rw-r--r--src/static_libs/vg_common/meson.build5
-rw-r--r--src/static_libs/vg_common/vg_common.h6
-rw-r--r--src/static_libs/vg_common/vg_common_json.c438
3 files changed, 449 insertions, 0 deletions
diff --git a/src/static_libs/vg_common/meson.build b/src/static_libs/vg_common/meson.build
index 648fcd5..9dfb47f 100644
--- a/src/static_libs/vg_common/meson.build
+++ b/src/static_libs/vg_common/meson.build
@@ -5,6 +5,11 @@ vg_common_src = files([
5 'vg_common.h', 5 'vg_common.h',
6]) 6])
7 7
8if get_option('evas-loaders-disabler').contains('json') == false
9 config_h.set('BUILD_VG_LOADER_JSON', '1')
10 vg_common_src += files('vg_common_json.c')
11endif
12
8vg_common_inc_dir = include_directories('.') 13vg_common_inc_dir = include_directories('.')
9 14
10vg_common = declare_dependency( 15vg_common = declare_dependency(
diff --git a/src/static_libs/vg_common/vg_common.h b/src/static_libs/vg_common/vg_common.h
index 3484a71..fc8d566 100644
--- a/src/static_libs/vg_common/vg_common.h
+++ b/src/static_libs/vg_common/vg_common.h
@@ -319,4 +319,10 @@ Vg_File_Data * vg_common_svg_create_vg_node(Svg_Node *node);
319Svg_Node *vg_common_svg_create_svg_node(Vg_File_Data *node); 319Svg_Node *vg_common_svg_create_svg_node(Vg_File_Data *node);
320void vg_common_svg_node_free(Svg_Node *node); 320void vg_common_svg_node_free(Svg_Node *node);
321 321
322
323/******************************************************************************************
324 * Lottie Compatible feature implementation
325 ******************************************************************************************/
326Eina_Bool vg_common_json_create_vg_node(Vg_File_Data *vfd);
327
322#endif //EVAS_VG_COMMON_H_ 328#endif //EVAS_VG_COMMON_H_
diff --git a/src/static_libs/vg_common/vg_common_json.c b/src/static_libs/vg_common/vg_common_json.c
new file mode 100644
index 0000000..c97bfea
--- /dev/null
+++ b/src/static_libs/vg_common/vg_common_json.c
@@ -0,0 +1,438 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include "vg_common.h"
6#include <Evas.h>
7
8#ifdef BUILD_VG_LOADER_JSON
9
10#include <rlottie_capi.h>
11
12//FIXME: This enum add temporarily to help understanding of additional code
13//related to masking in prepare_mask.
14//This needs to be formally declared through the eo class.
15typedef enum _EFL_CANVAS_VG_NODE_BLEND_TYPE
16{
17 EFL_CANVAS_VG_NODE_BLEND_TYPE_NONE = 0,
18 EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA,
19 EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA_INV,
20 EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_ADD,
21 EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_SUBSTRACT,
22 EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_INTERSECT,
23 EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_DIFFERENCE
24}EFL_CANVAS_VG_NODE_BLEND_TYPE;
25//
26
27static char*
28_get_key_val(void *key)
29{
30 static char buf[30];
31 snprintf(buf, sizeof(buf), "%ld", (size_t) key);
32 return buf;
33}
34
35static void
36_construct_drawable_nodes(Efl_Canvas_Vg_Container *parent, const LOTLayerNode *layer, int depth EINA_UNUSED)
37{
38 if (!parent) return;
39
40 for (unsigned int i = 0; i < layer->mNodeList.size; i++)
41 {
42 LOTNode *node = layer->mNodeList.ptr[i];
43 if (!node) continue;
44
45 const float *data = node->mPath.ptPtr;
46 if (!data) continue;
47
48 char *key = _get_key_val(node);
49 Efl_Canvas_Vg_Shape *shape = efl_key_data_get(parent, key);
50 if (!shape)
51 {
52 shape = efl_add(EFL_CANVAS_VG_SHAPE_CLASS, parent);
53 efl_key_data_set(parent, key, shape);
54 }
55 else
56 efl_gfx_path_reset(shape);
57
58 efl_gfx_entity_visible_set(shape, EINA_TRUE);
59#if DEBUG
60 for (int i = 0; i < depth; i++) printf(" ");
61 printf("%s (%p)\n", efl_class_name_get(efl_class_get(shape)), shape);
62#endif
63 //0: Path
64 efl_gfx_path_reserve(shape, node->mPath.elmCount, node->mPath.ptCount);
65
66 for (int i = 0; i < node->mPath.elmCount; i++)
67 {
68 switch (node->mPath.elmPtr[i])
69 {
70 case 0:
71 efl_gfx_path_append_move_to(shape, data[0], data[1]);
72 data += 2;
73 break;
74 case 1:
75 efl_gfx_path_append_line_to(shape, data[0], data[1]);
76 data += 2;
77 break;
78 case 2:
79 efl_gfx_path_append_cubic_to(shape, data[0], data[1], data[2], data[3], data[4], data[5]);
80 data += 6;
81 break;
82 case 3:
83 efl_gfx_path_append_close(shape);
84 break;
85 default:
86 ERR("No reserved path type = %d", node->mPath.elmPtr[i]);
87 }
88 }
89
90 //1: Stroke
91 if (node->mStroke.enable)
92 {
93 //Stroke Width
94 efl_gfx_shape_stroke_width_set(shape, node->mStroke.width);
95
96 //Stroke Cap
97 Efl_Gfx_Cap cap;
98 switch (node->mStroke.cap)
99 {
100 case CapFlat: cap = EFL_GFX_CAP_BUTT; break;
101 case CapSquare: cap = EFL_GFX_CAP_SQUARE; break;
102 case CapRound: cap = EFL_GFX_CAP_ROUND; break;
103 default: cap = EFL_GFX_CAP_BUTT; break;
104 }
105 efl_gfx_shape_stroke_cap_set(shape, cap);
106
107 //Stroke Join
108 Efl_Gfx_Join join;
109 switch (node->mStroke.join)
110 {
111 case JoinMiter: join = EFL_GFX_JOIN_MITER; break;
112 case JoinBevel: join = EFL_GFX_JOIN_BEVEL; break;
113 case JoinRound: join = EFL_GFX_JOIN_ROUND; break;
114 default: join = EFL_GFX_JOIN_MITER; break;
115 }
116 efl_gfx_shape_stroke_join_set(shape, join);
117
118 //Stroke Dash
119 if (node->mStroke.dashArraySize > 0)
120 {
121 int size = (node->mStroke.dashArraySize / 2);
122 Efl_Gfx_Dash *dash = malloc(sizeof(Efl_Gfx_Dash) * size);
123 if (dash)
124 {
125 for (int i = 0; i <= size; i+=2)
126 {
127 dash[i].length = node->mStroke.dashArray[i];
128 dash[i].gap = node->mStroke.dashArray[i + 1];
129 }
130 efl_gfx_shape_stroke_dash_set(shape, dash, size);
131 free(dash);
132 }
133 }
134 }
135
136 //2: Fill Method
137 switch (node->mBrushType)
138 {
139 case BrushSolid:
140 {
141 float pa = ((float)node->mColor.a) / 255;
142 int r = (int)(((float) node->mColor.r) * pa);
143 int g = (int)(((float) node->mColor.g) * pa);
144 int b = (int)(((float) node->mColor.b) * pa);
145 int a = node->mColor.a;
146
147 if (node->mStroke.enable)
148 efl_gfx_shape_stroke_color_set(shape, r, g, b, a);
149 else
150 efl_gfx_color_set(shape, r, g, b, a);
151 }
152 break;
153 case BrushGradient:
154 {
155 Efl_Canvas_Vg_Gradient* grad = NULL;
156
157 if (node->mGradient.type == GradientLinear)
158 {
159 grad = efl_add(EFL_CANVAS_VG_GRADIENT_LINEAR_CLASS, parent);
160 efl_gfx_gradient_linear_start_set(grad, node->mGradient.start.x, node->mGradient.start.y);
161 efl_gfx_gradient_linear_end_set(grad, node->mGradient.end.x, node->mGradient.end.y);
162 }
163 else if (node->mGradient.type == GradientRadial)
164 {
165 grad = efl_add(EFL_CANVAS_VG_GRADIENT_RADIAL_CLASS, parent);
166 efl_gfx_gradient_radial_center_set(grad, node->mGradient.center.x, node->mGradient.center.y);
167 efl_gfx_gradient_radial_focal_set(grad, node->mGradient.focal.x, node->mGradient.focal.y);
168 efl_gfx_gradient_radial_radius_set(grad, node->mGradient.cradius);
169 }
170 else
171 ERR("No reserved gradient type = %d", node->mGradient.type);
172
173 if (grad)
174 {
175 //Gradient Stop
176 Efl_Gfx_Gradient_Stop* stops = malloc(sizeof(Efl_Gfx_Gradient_Stop) * node->mGradient.stopCount);
177 if (stops)
178 {
179 for (unsigned int i = 0; i < node->mGradient.stopCount; i++)
180 {
181 stops[i].offset = node->mGradient.stopPtr[i].pos;
182 float pa = ((float)node->mGradient.stopPtr[i].a) / 255;
183 stops[i].r = (int)(((float)node->mGradient.stopPtr[i].r) * pa);
184 stops[i].g = (int)(((float)node->mGradient.stopPtr[i].g) * pa);
185 stops[i].b = (int)(((float)node->mGradient.stopPtr[i].b) * pa);
186 stops[i].a = node->mGradient.stopPtr[i].a;
187 }
188 efl_gfx_gradient_stop_set(grad, stops, node->mGradient.stopCount);
189 free(stops);
190 }
191 if (node->mStroke.enable)
192 efl_canvas_vg_shape_stroke_fill_set(shape, grad);
193 else
194 efl_canvas_vg_shape_fill_set(shape, grad);
195 }
196 }
197 break;
198 default:
199 ERR("No reserved brush type = %d", node->mBrushType);
200 }
201
202 //3: Fill Rule
203 if (node->mFillRule == FillEvenOdd)
204 efl_gfx_shape_fill_rule_set(shape, EFL_GFX_FILL_RULE_ODD_EVEN);
205 else if (node->mFillRule == FillWinding)
206 efl_gfx_shape_fill_rule_set(shape, EFL_GFX_FILL_RULE_WINDING);
207 }
208}
209
210static void
211_construct_mask_nodes(Efl_Canvas_Vg_Container *parent, LOTMask *mask, int depth EINA_UNUSED)
212{
213 const float *data = mask->mPath.ptPtr;
214 if (!data) return;
215
216 char *key = _get_key_val(mask);
217 Efl_Canvas_Vg_Shape *shape = efl_key_data_get(parent, key);
218 if (!shape)
219 {
220 shape = efl_add(EFL_CANVAS_VG_SHAPE_CLASS, parent);
221 efl_key_data_set(parent, key, shape);
222 }
223 else
224 efl_gfx_path_reset(shape);
225
226 efl_gfx_entity_visible_set(shape, EINA_TRUE);
227
228 efl_gfx_path_reserve(shape, mask->mPath.elmCount, mask->mPath.ptCount);
229
230 for (int i = 0; i < mask->mPath.elmCount; i++)
231 {
232 switch (mask->mPath.elmPtr[i])
233 {
234 case 0:
235 efl_gfx_path_append_move_to(shape, data[0], data[1]);
236 data += 2;
237 break;
238 case 1:
239 efl_gfx_path_append_line_to(shape, data[0], data[1]);
240 data += 2;
241 break;
242 case 2:
243 efl_gfx_path_append_cubic_to(shape, data[0], data[1], data[2], data[3], data[4], data[5]);
244 data += 6;
245 break;
246 case 3:
247 efl_gfx_path_append_close(shape);
248 break;
249 default:
250 ERR("No reserved path type = %d", mask->mPath.elmPtr[i]);
251 break;
252 }
253 }
254 //White color and alpha setting
255 float pa = ((float)mask->mAlpha) / 255;
256 int r = (int) (255.0f * pa);
257 int g = (int) (255.0f * pa);
258 int b = (int) (255.0f * pa);
259 int a = mask->mAlpha;
260 efl_gfx_color_set(shape, r, g, b, a);
261}
262
263static void
264_construct_masks(Efl_Canvas_Vg_Container *mtarget, LOTMask *masks, unsigned int mask_cnt, int depth)
265{
266 char *key = NULL;
267
268 Efl_Canvas_Vg_Container *msource = NULL;
269
270 key = _get_key_val(mtarget);
271 msource = efl_key_data_get(mtarget, key);
272 if (!msource)
273 {
274 msource = efl_add(EFL_CANVAS_VG_CONTAINER_CLASS, mtarget);
275 efl_key_data_set(mtarget, key, msource);
276 }
277
278 //FIXME : EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA option is temporary
279 //Currently matte alpha implemtnes is same the mask intersect impletment.
280 //It has been implemented as a multiplication calculation.
281 efl_canvas_vg_node_mask_set(mtarget, msource, EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA);
282
283 mtarget = msource;
284
285 //Make mask layers
286 for (unsigned int i = 0; i < mask_cnt; i++)
287 {
288 LOTMask *mask = &masks[i];;
289 key = _get_key_val(mask);
290 msource = efl_key_data_get(mtarget, key);
291
292 if (!msource)
293 {
294 msource = efl_add(EFL_CANVAS_VG_CONTAINER_CLASS, mtarget);
295 efl_key_data_set(mtarget, key, msource);
296 }
297 _construct_mask_nodes(msource, mask, depth + 1);
298
299 EFL_CANVAS_VG_NODE_BLEND_TYPE mask_mode;
300 switch (mask->mMode)
301 {
302 case MaskSubstract:
303 mask_mode = EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_SUBSTRACT;
304 break;
305 case MaskIntersect:
306 mask_mode = EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_INTERSECT;
307 break;
308 case MaskDifference:
309 mask_mode = EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_DIFFERENCE;
310 break;
311 case MaskAdd:
312 default:
313 mask_mode = EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_ADD;
314 break;
315 }
316 efl_canvas_vg_node_mask_set(mtarget, msource, mask_mode);
317 mtarget = msource;
318 }
319}
320
321static void
322_update_vg_tree(Efl_Canvas_Vg_Container *root, const LOTLayerNode *layer, int depth EINA_UNUSED)
323{
324 if (!layer->mVisible)
325 {
326 efl_gfx_entity_visible_set(root, EINA_FALSE);
327 return;
328 }
329 efl_gfx_entity_visible_set(root, EINA_TRUE);
330
331 Efl_Canvas_Vg_Container *ptree = NULL;
332
333 //Note: We assume that if matte is valid, next layer must be a matte source.
334 int matte_mode = 0;
335 Efl_Canvas_Vg_Container *mtarget = NULL;
336 LOTLayerNode *mlayer = NULL;
337
338 //Is this layer a container layer?
339 for (unsigned int i = 0; i < layer->mLayerList.size; i++)
340 {
341 LOTLayerNode *clayer = layer->mLayerList.ptr[i];
342
343 //Source Layer
344 char *key = _get_key_val(clayer);
345 Efl_Canvas_Vg_Container *ctree = efl_key_data_get(root, key);
346 if (!ctree)
347 {
348 ctree = efl_add(EFL_CANVAS_VG_CONTAINER_CLASS, root);
349 efl_key_data_set(root, key, ctree);
350 }
351#if DEBUG
352 for (int i = 0; i < depth; i++) printf(" ");
353 printf("%s (%p) matte:%d => %p\n", efl_class_name_get(efl_class_get(ctree)), ctree, matte_mode, ptree);
354#endif
355 _update_vg_tree(ctree, clayer, depth+1);
356
357 if (matte_mode != 0)
358 {
359 efl_canvas_vg_node_mask_set(ptree, ctree, matte_mode);
360 mtarget = ctree;
361 }
362 matte_mode = (int) clayer->mMatte;
363
364 if (clayer->mMaskList.size > 0)
365 {
366 mlayer = clayer;
367 if (!mtarget) mtarget = ctree;
368 }
369
370 ptree = ctree;
371
372 //Remap Matte Mode
373 switch (matte_mode)
374 {
375 case MatteNone:
376 matte_mode = 0;
377 break;
378 case MatteAlpha:
379 matte_mode = EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA;
380 break;
381 case MatteAlphaInv:
382 matte_mode = EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA_INV;
383 break;
384 case MatteLuma:
385 matte_mode = 0;
386 ERR("TODO: MatteLuma");
387 break;
388 case MatteLumaInv:
389 matte_mode = 0;
390 ERR("TODO: MatteLumaInv");
391 break;
392 default:
393 matte_mode = 0;
394 break;
395 }
396 }
397
398 //Construct drawable nodes.
399 if (layer->mNodeList.size > 0)
400 _construct_drawable_nodes(root, layer, depth);
401
402 //Construct node that have mask.
403 if (mlayer)
404 _construct_masks(mtarget, mlayer->mMaskList.ptr, mlayer->mMaskList.size, depth);
405}
406#endif
407
408Eina_Bool
409vg_common_json_create_vg_node(Vg_File_Data *vfd)
410{
411#ifdef BUILD_VG_LOADER_JSON
412 Lottie_Animation *lot_anim = (Lottie_Animation *) vfd->loader_data;
413 if (!lot_anim) return EINA_FALSE;
414
415 unsigned int frame_num = (vfd->anim_data) ? vfd->anim_data->frame_num : 0;
416 const LOTLayerNode *tree =
417 lottie_animation_render_tree(lot_anim, frame_num,
418 vfd->view_box.w, vfd->view_box.h);
419#if DEBUG
420 printf("%s (%p)\n", efl_class_name_get(efl_class_get(vfd->root)), vfd->root);
421#endif
422
423 //Root node
424 Efl_Canvas_Vg_Container *root = vfd->root;
425 if (!root)
426 {
427 root = efl_add_ref(EFL_CANVAS_VG_CONTAINER_CLASS, NULL);
428 if (!root) return EINA_FALSE;
429 efl_key_data_set(root, _get_key_val((void *) tree), tree);
430 vfd->root = root;
431 }
432
433 _update_vg_tree(root, tree, 1);
434#else
435 return EINA_FALSE;
436#endif
437 return EINA_TRUE;
438}