1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4 
5 #include <math.h>
6 #include <float.h>
7 
8 #include <Eina.h>
9 #include <Ector.h>
10 #include <software/Ector_Software.h>
11 
12 #include "ector_private.h"
13 #include "ector_software_private.h"
14 
15 #define MY_CLASS ECTOR_RENDERER_SOFTWARE_SHAPE_CLASS
16 
17 typedef struct _Ector_Renderer_Software_Shape_Data Ector_Renderer_Software_Shape_Data;
18 typedef struct _Ector_Software_Shape_Task Ector_Software_Shape_Task;
19 
20 struct _Ector_Software_Shape_Task
21 {
22    Ector_Renderer_Software_Shape_Data *pd;
23 
24    const Efl_Gfx_Path_Command *cmds;
25    const double *pts;
26 
27    Efl_Gfx_Fill_Rule fill_rule;
28 };
29 
30 struct _Ector_Renderer_Software_Shape_Data
31 {
32    Efl_Gfx_Shape_Public        *public_shape;
33 
34    Ector_Software_Surface_Data *surface;
35    Ector_Renderer_Shape_Data   *shape;
36    Ector_Renderer_Data         *base;
37 
38    Shape_Rle_Data              *shape_data;
39    Shape_Rle_Data              *outline_data;
40 
41    Ector_Buffer                *comp;
42    Efl_Gfx_Vg_Composite_Method comp_method;
43 
44    Ector_Software_Shape_Task   *task;
45 };
46 
47 typedef struct _Outline
48 {
49    SW_FT_Outline ft_outline;
50    int points_alloc;
51    int contours_alloc;
52 } Outline;
53 
54 
55 #define TO_FT_COORD(x) ((x) * 64) // to freetype 26.6 coordinate.
56 
57 static inline void
_grow_outline_contour(Outline * outline,int num)58 _grow_outline_contour(Outline *outline, int num)
59 {
60    if ( outline->ft_outline.n_contours + num > outline->contours_alloc)
61      {
62         outline->contours_alloc += 5;
63         outline->ft_outline.contours = (short *) realloc(outline->ft_outline.contours,
64                                                          outline->contours_alloc * sizeof(short));
65      }
66 }
67 
68 static inline void
_grow_outline_points(Outline * outline,int num)69 _grow_outline_points(Outline *outline, int num)
70 {
71    if ( outline->ft_outline.n_points + num > outline->points_alloc)
72      {
73         outline->points_alloc += 50;
74         outline->ft_outline.points = (SW_FT_Vector *) realloc(outline->ft_outline.points,
75                                                               outline->points_alloc * sizeof(SW_FT_Vector));
76         outline->ft_outline.tags = (char *) realloc(outline->ft_outline.tags,
77                                                     outline->points_alloc * sizeof(char));
78      }
79 }
80 static Outline *
_outline_create()81 _outline_create()
82 {
83    Outline *outline = (Outline *) calloc(1, sizeof(Outline));
84    outline->points_alloc = 0;
85    outline->contours_alloc = 0;
86    _grow_outline_contour(outline, 1);
87    _grow_outline_points(outline, 1);
88    return outline;
89 }
90 
91 static
_outline_destroy(Outline * outline)92 void _outline_destroy(Outline *outline)
93 {
94    if (outline)
95      {
96         free(outline->ft_outline.points);
97         free(outline->ft_outline.tags);
98         free(outline->ft_outline.contours);
99         free(outline);
100      }
101 }
102 
103 static void
_outline_move_to(Outline * outline,double x,double y)104 _outline_move_to(Outline *outline, double x, double y)
105 {
106    SW_FT_Outline *ft_outline = &outline->ft_outline;
107 
108    _grow_outline_points(outline, 1);
109    ft_outline->points[ft_outline->n_points].x = TO_FT_COORD(x);
110    ft_outline->points[ft_outline->n_points].y = TO_FT_COORD(y);
111    ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_ON;
112 
113    if (ft_outline->n_points)
114      {
115         _grow_outline_contour(outline, 1);
116         ft_outline->contours[ft_outline->n_contours] = ft_outline->n_points - 1;
117         ft_outline->n_contours++;
118      }
119 
120    ft_outline->n_points++;
121 }
122 
123 static void
_outline_end(Outline * outline)124 _outline_end(Outline *outline)
125 {
126    SW_FT_Outline *ft_outline = &outline->ft_outline;
127 
128    _grow_outline_contour(outline, 1);
129 
130    if (ft_outline->n_points)
131      {
132         ft_outline->contours[ft_outline->n_contours] = ft_outline->n_points - 1;
133         ft_outline->n_contours++;
134      }
135 }
136 
137 
_outline_line_to(Outline * outline,double x,double y)138 static void  _outline_line_to(Outline *outline, double x, double y)
139 {
140    SW_FT_Outline *ft_outline = &outline->ft_outline;
141 
142    _grow_outline_points(outline, 1);
143    ft_outline->points[ft_outline->n_points].x = TO_FT_COORD(x);
144    ft_outline->points[ft_outline->n_points].y = TO_FT_COORD(y);
145    ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_ON;
146    ft_outline->n_points++;
147 }
148 
149 
150 static Eina_Bool
_outline_close_path(Outline * outline)151 _outline_close_path(Outline *outline)
152 {
153    SW_FT_Outline *ft_outline = &outline->ft_outline;
154    int index ;
155 
156    if (ft_outline->n_contours)
157      {
158         index = ft_outline->contours[ft_outline->n_contours - 1] + 1;
159      }
160    else
161      {
162         // First path
163         index = 0;
164      }
165 
166    // Make sure there is at least one point in the current path
167    if (ft_outline->n_points == index) return EINA_FALSE;
168 
169    // Close the path
170    _grow_outline_points(outline, 1);
171    ft_outline->points[ft_outline->n_points].x = ft_outline->points[index].x;
172    ft_outline->points[ft_outline->n_points].y = ft_outline->points[index].y;
173    ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_ON;
174    ft_outline->n_points++;
175 
176    return EINA_TRUE;
177 }
178 
179 
_outline_cubic_to(Outline * outline,double cx1,double cy1,double cx2,double cy2,double x,double y)180 static void _outline_cubic_to(Outline *outline, double cx1, double cy1,
181                               double cx2, double cy2, double x, double y)
182 {
183    SW_FT_Outline *ft_outline = &outline->ft_outline;
184 
185    _grow_outline_points(outline, 3);
186 
187    ft_outline->points[ft_outline->n_points].x = TO_FT_COORD(cx1);
188    ft_outline->points[ft_outline->n_points].y = TO_FT_COORD(cy1);
189    ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_CUBIC;
190    ft_outline->n_points++;
191 
192    ft_outline->points[ft_outline->n_points].x = TO_FT_COORD(cx2);
193    ft_outline->points[ft_outline->n_points].y = TO_FT_COORD(cy2);
194    ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_CUBIC;
195    ft_outline->n_points++;
196 
197    ft_outline->points[ft_outline->n_points].x = TO_FT_COORD(x);
198    ft_outline->points[ft_outline->n_points].y = TO_FT_COORD(y);
199    ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_ON;
200    ft_outline->n_points++;
201 }
202 
_outline_transform(Outline * outline,Eina_Matrix3 * m)203 static void _outline_transform(Outline *outline, Eina_Matrix3 *m)
204 {
205    int i;
206    double x, y;
207    SW_FT_Outline *ft_outline = &outline->ft_outline;
208 
209    if (m && (eina_matrix3_type_get(m) != EINA_MATRIX_TYPE_IDENTITY))
210      {
211         for (i = 0; i < ft_outline->n_points; i++)
212           {
213              eina_matrix3_point_transform(m,
214                                           ft_outline->points[i].x/64.0,/* convert back to normal coord.*/
215                                           ft_outline->points[i].y/64.0,/* convert back to normal coord.*/
216                                           &x, &y);
217 
218              ft_outline->points[i].x = TO_FT_COORD(x);
219              ft_outline->points[i].y = TO_FT_COORD(y);
220           }
221      }
222 }
223 
224 static Eina_Bool
_generate_outline(const Efl_Gfx_Path_Command * cmds,const double * pts,Outline * outline)225 _generate_outline(const Efl_Gfx_Path_Command *cmds, const double *pts, Outline * outline)
226 {
227    Eina_Bool close_path = EINA_FALSE;
228    for (; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++)
229      {
230         switch (*cmds)
231           {
232             case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO:
233 
234                _outline_move_to(outline, pts[0], pts[1]);
235 
236                pts += 2;
237                break;
238             case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO:
239 
240                _outline_line_to(outline, pts[0], pts[1]);
241 
242                pts += 2;
243                break;
244             case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO:
245 
246                _outline_cubic_to(outline,
247                                  pts[0], pts[1], pts[2], pts[3], // control points
248                                  pts[4], pts[5]); // destination point
249                pts += 6;
250                break;
251 
252             case EFL_GFX_PATH_COMMAND_TYPE_CLOSE:
253 
254                close_path = _outline_close_path(outline);
255                break;
256 
257             case EFL_GFX_PATH_COMMAND_TYPE_LAST:
258             case EFL_GFX_PATH_COMMAND_TYPE_END:
259                break;
260           }
261      }
262    _outline_end(outline);
263    return close_path;
264 }
265 
266 typedef struct _Line
267 {
268    double x1;
269    double y1;
270    double x2;
271    double y2;
272 }Line;
273 
274 static void
_line_value_set(Line * l,double x1,double y1,double x2,double y2)275 _line_value_set(Line *l, double x1, double y1, double x2, double y2)
276 {
277    l->x1 = x1;
278    l->y1 = y1;
279    l->x2 = x2;
280    l->y2 = y2;
281 }
282 
283 // approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm.
284 // With alpha = 1, beta = 3/8, giving results with the largest error less
285 // than 7% compared to the exact value.
286 static double
_line_length(Line * l)287 _line_length(Line *l)
288 {
289    double x = l->x2 - l->x1;
290    double y = l->y2 - l->y1;
291    x = x < 0 ? -x : x;
292    y = y < 0 ? -y : y;
293    return (x > y ? x + 0.375 * y : y + 0.375 * x);
294 }
295 
296 static void
_line_split_at_length(Line * l,double length,Line * left,Line * right)297 _line_split_at_length(Line *l, double length, Line *left, Line *right)
298 {
299    double len = _line_length(l);
300    double dx = ((l->x2 - l->x1)/len) *length;
301    double dy = ((l->y2 - l->y1)/len) *length;
302 
303    left->x1 = l->x1;
304    left->y1 = l->y1;
305    left->x2 = left->x1 + dx;
306    left->y2 = left->y1 + dy;
307 
308    right->x1 = left->x2;
309    right->y1 = left->y2;
310    right->x2 = l->x2;
311    right->y2 = l->y2;
312 }
313 
314 typedef struct _Dash_Stroker
315 {
316    Efl_Gfx_Dash *dash;
317    int           dash_len;
318    Outline      *outline;
319    int cur_dash_index;
320    double cur_dash_length;
321    Eina_Bool cur_op_gap;
322    double start_x, start_y;
323    double cur_x, cur_y;
324 }Dash_Stroker;
325 
326 static void
_dasher_line_to(Dash_Stroker * dasher,double x,double y)327 _dasher_line_to(Dash_Stroker *dasher, double x, double y)
328 {
329    Line l, left, right;
330    double line_len = 0.0;
331    _line_value_set(&l, dasher->cur_x, dasher->cur_y, x, y);
332    line_len = _line_length(&l);
333    if (line_len < dasher->cur_dash_length)
334      {
335         dasher->cur_dash_length -= line_len;
336         if (!dasher->cur_op_gap)
337           {
338              _outline_move_to(dasher->outline, dasher->cur_x, dasher->cur_y);
339              _outline_line_to(dasher->outline, x, y);
340           }
341      }
342    else
343      {
344         while (line_len > dasher->cur_dash_length)
345           {
346              line_len -= dasher->cur_dash_length;
347              _line_split_at_length(&l, dasher->cur_dash_length, &left, &right);
348              if (!dasher->cur_op_gap)
349                {
350                   _outline_move_to(dasher->outline, left.x1, left.y1);
351                   _outline_line_to(dasher->outline, left.x2, left.y2);
352                   dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].gap;
353                }
354              else
355                {
356                   dasher->cur_dash_index = (dasher->cur_dash_index +1) % dasher->dash_len ;
357                   dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].length;
358                }
359              dasher->cur_op_gap = !dasher->cur_op_gap;
360              l = right;
361              dasher->cur_x = l.x1;
362              dasher->cur_y = l.y1;
363           }
364         // remainder
365         dasher->cur_dash_length -= line_len;
366         if (!dasher->cur_op_gap)
367           {
368              _outline_move_to(dasher->outline, l.x1, l.y1);
369              _outline_line_to(dasher->outline, l.x2, l.y2);
370           }
371         if (dasher->cur_dash_length < 1.0)
372           {
373              // move to next dash
374              if (!dasher->cur_op_gap)
375                {
376                   dasher->cur_op_gap = EINA_TRUE;
377                   dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].gap;
378                }
379              else
380                {
381                   dasher->cur_op_gap = EINA_FALSE;
382                   dasher->cur_dash_index = (dasher->cur_dash_index +1) % dasher->dash_len ;
383                   dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].length;
384                }
385           }
386      }
387    dasher->cur_x = x;
388    dasher->cur_y = y;
389 }
390 
391 static void
_dasher_cubic_to(Dash_Stroker * dasher,double cx1,double cy1,double cx2,double cy2,double x,double y)392 _dasher_cubic_to(Dash_Stroker *dasher, double cx1 , double cy1, double cx2, double cy2, double x, double y)
393 {
394    Eina_Bezier b, left, right;
395    double bez_len = 0.0;
396    eina_bezier_values_set(&b, dasher->cur_x, dasher->cur_y, cx1, cy1, cx2, cy2, x, y);
397    bez_len = eina_bezier_length_get(&b);
398    if (bez_len < dasher->cur_dash_length)
399      {
400         dasher->cur_dash_length -= bez_len;
401         if (!dasher->cur_op_gap)
402           {
403              _outline_move_to(dasher->outline, dasher->cur_x, dasher->cur_y);
404              _outline_cubic_to(dasher->outline, cx1, cy1, cx2, cy2, x, y);
405           }
406      }
407    else
408      {
409         while (bez_len > dasher->cur_dash_length)
410           {
411              bez_len -= dasher->cur_dash_length;
412              eina_bezier_split_at_length(&b, dasher->cur_dash_length, &left, &right);
413              if (!dasher->cur_op_gap)
414                {
415                   _outline_move_to(dasher->outline, left.start.x, left.start.y);
416                   _outline_cubic_to(dasher->outline, left.ctrl_start.x, left.ctrl_start.y, left.ctrl_end.x, left.ctrl_end.y, left.end.x, left.end.y);
417                   dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].gap;
418                }
419              else
420                {
421                   dasher->cur_dash_index = (dasher->cur_dash_index +1) % dasher->dash_len ;
422                   dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].length;
423                }
424              dasher->cur_op_gap = !dasher->cur_op_gap;
425              b = right;
426              dasher->cur_x = b.start.x;
427              dasher->cur_y = b.start.y;
428           }
429          // remainder
430         dasher->cur_dash_length -= bez_len;
431         if (!dasher->cur_op_gap)
432           {
433              _outline_move_to(dasher->outline, b.start.x, b.start.y);
434              _outline_cubic_to(dasher->outline, b.ctrl_start.x, b.ctrl_start.y, b.ctrl_end.x, b.ctrl_end.y, b.end.x, b.end.y);
435           }
436         if (dasher->cur_dash_length < 1.0)
437           {
438              // move to next dash
439              if (!dasher->cur_op_gap)
440                {
441                   dasher->cur_op_gap = EINA_TRUE;
442                   dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].gap;
443                }
444              else
445                {
446                   dasher->cur_op_gap = EINA_FALSE;
447                   dasher->cur_dash_index = (dasher->cur_dash_index +1) % dasher->dash_len ;
448                   dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].length;
449                }
450           }
451       }
452    dasher->cur_x = x;
453    dasher->cur_y = y;
454 }
455 
456 static Eina_Bool
_generate_dashed_outline(const Efl_Gfx_Path_Command * cmds,const double * pts,Outline * outline,Efl_Gfx_Dash * dash,int dash_len)457 _generate_dashed_outline(const Efl_Gfx_Path_Command *cmds, const double *pts, Outline * outline, Efl_Gfx_Dash *dash, int dash_len)
458 {
459    Dash_Stroker dasher;
460    dasher.dash = dash;
461    dasher.dash_len = dash_len;
462    dasher.outline = outline;
463    dasher.cur_dash_length = 0.0;
464    dasher.cur_dash_index = 0;
465    dasher.cur_op_gap = EINA_FALSE;
466    dasher.start_x = 0.0;
467    dasher.start_y = 0.0;
468    dasher.cur_x = 0.0;
469    dasher.cur_y = 0.0;
470 
471    for (; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++)
472      {
473         switch (*cmds)
474           {
475             case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO:
476               {
477                  // reset the dash
478                  dasher.cur_dash_index = 0;
479                  dasher.cur_dash_length = dasher.dash[0].length;
480                  dasher.cur_op_gap = EINA_FALSE;
481                  dasher.start_x = pts[0];
482                  dasher.start_y = pts[1];
483                  dasher.cur_x = pts[0];
484                  dasher.cur_y = pts[1];
485                  pts += 2;
486               }
487                break;
488             case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO:
489                _dasher_line_to(&dasher, pts[0], pts[1]);
490                pts += 2;
491                break;
492             case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO:
493                _dasher_cubic_to(&dasher, pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]);
494                pts += 6;
495                break;
496 
497             case EFL_GFX_PATH_COMMAND_TYPE_CLOSE:
498                _dasher_line_to(&dasher, dasher.start_x, dasher.start_y);
499                break;
500 
501             case EFL_GFX_PATH_COMMAND_TYPE_LAST:
502             case EFL_GFX_PATH_COMMAND_TYPE_END:
503                break;
504           }
505      }
506    _outline_end(outline);
507    return EINA_FALSE;
508 }
509 
510 static Eina_Bool
_generate_stroke_data(Ector_Renderer_Software_Shape_Data * pd)511 _generate_stroke_data(Ector_Renderer_Software_Shape_Data *pd)
512 {
513    if (pd->outline_data) return EINA_FALSE;
514 
515    if (!pd->shape->stroke.fill &&
516        ((pd->public_shape->stroke.color.a == 0) ||
517         (pd->public_shape->stroke.width < 0.01)))
518      return EINA_FALSE;
519 
520    return EINA_TRUE;
521 }
522 
523 static Eina_Bool
_generate_shape_data(Ector_Renderer_Software_Shape_Data * pd)524 _generate_shape_data(Ector_Renderer_Software_Shape_Data *pd)
525 {
526    if (pd->shape_data) return EINA_FALSE;
527 
528    if (!pd->shape->fill && (pd->base->color.a == 0)) return EINA_FALSE;
529 
530    return EINA_TRUE;
531 }
532 
533 static Ector_Software_Shape_Task *
_need_update_rle(Eo * obj,Ector_Renderer_Software_Shape_Data * pd)534 _need_update_rle(Eo *obj, Ector_Renderer_Software_Shape_Data *pd)
535 {
536    if (pd->task) return pd->task;
537 
538    if (!pd->base->visibility || (!_generate_stroke_data(pd) &&
539        !_generate_shape_data(pd)))
540      return NULL;
541 
542    const Efl_Gfx_Path_Command *cmds;
543    const double *pts;
544    efl_gfx_path_get(obj, &cmds, &pts);
545    if (!cmds) return NULL;
546 
547    Ector_Software_Shape_Task *task = malloc(sizeof(Ector_Software_Shape_Task));
548    if (!task) return NULL;
549 
550    task->pd = pd;
551    task->cmds = cmds;
552    task->pts = pts;
553    task->fill_rule = efl_gfx_shape_fill_rule_get(obj);
554 
555    pd->task = task;
556 
557    return task;
558 }
559 
560 static void
_done_rle(void * data)561 _done_rle(void *data)
562 {
563    Ector_Software_Shape_Task *task = data;
564    if (!task) return;
565    if (task->pd) task->pd->task = NULL;
566    free(task);
567 }
568 
569 static void
_update_rle(void * data,Ector_Software_Thread * thread)570 _update_rle(void *data, Ector_Software_Thread *thread)
571 {
572    Ector_Software_Shape_Task *task = data;
573    Eina_Bool close_path;
574    Outline *outline, *dash_outline;
575 
576    outline = _outline_create();
577    close_path = _generate_outline(task->cmds, task->pts, outline);
578    if (task->fill_rule == EFL_GFX_FILL_RULE_ODD_EVEN)
579      outline->ft_outline.flags = SW_FT_OUTLINE_EVEN_ODD_FILL;
580    else
581      outline->ft_outline.flags = SW_FT_OUTLINE_NONE; // default is winding fill
582 
583    _outline_transform(outline, task->pd->base->m);
584 
585    //shape data generation
586    if (_generate_shape_data(task->pd))
587      task->pd->shape_data = ector_software_rasterizer_generate_rle_data(thread,
588                                                                         task->pd->surface->rasterizer,
589                                                                         &outline->ft_outline);
590 
591    //stroke data generation
592    if (_generate_stroke_data(task->pd))
593      {
594         ector_software_rasterizer_stroke_set(thread, task->pd->surface->rasterizer,
595                                              (task->pd->public_shape->stroke.width *
596                                               task->pd->public_shape->stroke.scale),
597                                              task->pd->public_shape->stroke.cap,
598                                              task->pd->public_shape->stroke.join,
599                                              task->pd->base->m,
600                                              task->pd->public_shape->stroke.miterlimit);
601 
602         if (task->pd->public_shape->stroke.dash)
603           {
604              dash_outline = _outline_create();
605              close_path = _generate_dashed_outline(task->cmds, task->pts, dash_outline,
606                                                    task->pd->public_shape->stroke.dash,
607                                                    task->pd->public_shape->stroke.dash_length);
608              _outline_transform(dash_outline, task->pd->base->m);
609              task->pd->outline_data = ector_software_rasterizer_generate_stroke_rle_data(thread,
610                                                                                          task->pd->surface->rasterizer,
611                                                                                          &dash_outline->ft_outline,
612                                                                                          close_path);
613              _outline_destroy(dash_outline);
614           }
615         else
616           {
617              task->pd->outline_data = ector_software_rasterizer_generate_stroke_rle_data(thread,
618                                                                                          task->pd->surface->rasterizer,
619                                                                                          &outline->ft_outline,
620                                                                                          close_path);
621           }
622      }
623    _outline_destroy(outline);
624 }
625 
626 static Eina_Bool
_ector_renderer_software_shape_ector_renderer_prepare(Eo * obj,Ector_Renderer_Software_Shape_Data * pd)627 _ector_renderer_software_shape_ector_renderer_prepare(Eo *obj,
628                                                       Ector_Renderer_Software_Shape_Data *pd)
629 {
630    // FIXME: shouldn't this be moved to the software base object?
631    if (!pd->surface)
632      pd->surface = efl_data_xref(pd->base->surface, ECTOR_SOFTWARE_SURFACE_CLASS, obj);
633 
634    // Asynchronously lazy build of the RLE data for this shape
635    if (!pd->task)
636      {
637         Ector_Software_Shape_Task *task = _need_update_rle(obj, pd);
638         if (task) ector_software_schedule(_update_rle, _done_rle, task);
639      }
640 
641    return EINA_TRUE;
642 }
643 
644 static Eina_Bool
_ector_renderer_software_shape_ector_renderer_draw(Eo * obj EINA_UNUSED,Ector_Renderer_Software_Shape_Data * pd,Efl_Gfx_Render_Op op,Eina_Array * clips,unsigned int mul_col)645 _ector_renderer_software_shape_ector_renderer_draw(Eo *obj EINA_UNUSED,
646                                                    Ector_Renderer_Software_Shape_Data *pd,
647                                                    Efl_Gfx_Render_Op op, Eina_Array *clips,
648                                                    unsigned int mul_col)
649 {
650    int x, y;
651 
652    // check if RLE data are ready
653    Ector_Software_Shape_Task *task = pd->task;
654    if (task) ector_software_wait(_update_rle, _done_rle, task);
655 
656    // adjust the offset
657    x = (int)pd->base->origin.x - pd->surface->x;
658    y = (int)pd->base->origin.y - pd->surface->y;
659 
660    ector_software_rasterizer_clip_rect_set(pd->surface->rasterizer, clips);
661    ector_software_rasterizer_transform_set(pd->surface->rasterizer, pd->base->m);
662 
663    // fill the span_data structure
664    if (pd->shape->fill)
665      {
666         ector_renderer_software_op_fill(pd->shape->fill);
667         ector_software_rasterizer_draw_rle_data(pd->surface->rasterizer,
668                                                 x, y, mul_col, op,
669                                                 pd->shape_data,
670                                                 pd->comp,
671                                                 pd->comp_method);
672      }
673    else
674      {
675         if (pd->base->color.a > 0)
676           {
677              ector_software_rasterizer_color_set(pd->surface->rasterizer,
678                                                  pd->base->color.r,
679                                                  pd->base->color.g,
680                                                  pd->base->color.b,
681                                                  pd->base->color.a);
682              ector_software_rasterizer_draw_rle_data(pd->surface->rasterizer,
683                                                      x, y, mul_col, op,
684                                                      pd->shape_data,
685                                                      pd->comp,
686                                                      pd->comp_method);
687           }
688      }
689 
690    if (!pd->outline_data) return EINA_TRUE;
691 
692    if (pd->shape->stroke.fill)
693      {
694         ector_renderer_software_op_fill(pd->shape->stroke.fill);
695         ector_software_rasterizer_draw_rle_data(pd->surface->rasterizer,
696                                                 x, y, mul_col, op,
697                                                 pd->outline_data,
698                                                 pd->comp,
699                                                 pd->comp_method);
700      }
701    else
702      {
703         if (pd->public_shape->stroke.color.a > 0)
704           {
705              ector_software_rasterizer_color_set(pd->surface->rasterizer,
706                                                  pd->public_shape->stroke.color.r,
707                                                  pd->public_shape->stroke.color.g,
708                                                  pd->public_shape->stroke.color.b,
709                                                  pd->public_shape->stroke.color.a);
710              ector_software_rasterizer_draw_rle_data(pd->surface->rasterizer,
711                                                      x, y, mul_col, op,
712                                                      pd->outline_data,
713                                                      pd->comp,
714                                                      pd->comp_method);
715           }
716      }
717 
718    return EINA_TRUE;
719 }
720 
721 static Eina_Bool
_ector_renderer_software_shape_ector_renderer_software_op_fill(Eo * obj EINA_UNUSED,Ector_Renderer_Software_Shape_Data * pd EINA_UNUSED)722 _ector_renderer_software_shape_ector_renderer_software_op_fill(Eo *obj EINA_UNUSED,
723                                                                  Ector_Renderer_Software_Shape_Data *pd EINA_UNUSED)
724 {
725    // FIXME: let's find out how to fill a shape with a shape later.
726    // I need to read SVG specification and see how to map that with software.
727    return EINA_FALSE;
728 }
729 
730 EOLIAN static void
_ector_renderer_software_shape_efl_gfx_path_commit(Eo * obj EINA_UNUSED,Ector_Renderer_Software_Shape_Data * pd)731 _ector_renderer_software_shape_efl_gfx_path_commit(Eo *obj EINA_UNUSED,
732                                                    Ector_Renderer_Software_Shape_Data *pd)
733 {
734    if (pd->shape_data)
735      {
736         ector_software_rasterizer_destroy_rle_data(pd->shape_data);
737         pd->shape_data = NULL;
738      }
739    if (pd->outline_data)
740      {
741         ector_software_rasterizer_destroy_rle_data(pd->outline_data);
742         pd->outline_data = NULL;
743      }
744 }
745 
746 static Eo *
_ector_renderer_software_shape_efl_object_constructor(Eo * obj,Ector_Renderer_Software_Shape_Data * pd)747 _ector_renderer_software_shape_efl_object_constructor(Eo *obj, Ector_Renderer_Software_Shape_Data *pd)
748 {
749    obj = efl_constructor(efl_super(obj, MY_CLASS));
750    if (!obj) return NULL;
751 
752    pd->public_shape = efl_data_xref(obj, EFL_GFX_SHAPE_MIXIN, obj);
753    pd->shape = efl_data_xref(obj, ECTOR_RENDERER_SHAPE_MIXIN, obj);
754    pd->base = efl_data_xref(obj, ECTOR_RENDERER_CLASS, obj);
755 
756    return obj;
757 }
758 
759 static void
_ector_renderer_software_shape_efl_object_destructor(Eo * obj,Ector_Renderer_Software_Shape_Data * pd)760 _ector_renderer_software_shape_efl_object_destructor(Eo *obj, Ector_Renderer_Software_Shape_Data *pd)
761 {
762    // FIXME: As base class, destructor can't call destructor of mixin class.
763    // Call explicit API to free shape data.
764    if (pd->task)
765      ector_software_wait(_update_rle, _done_rle, pd->task);
766 
767    efl_gfx_path_reset(obj);
768 
769    if (pd->shape_data) ector_software_rasterizer_destroy_rle_data(pd->shape_data);
770    if (pd->outline_data) ector_software_rasterizer_destroy_rle_data(pd->outline_data);
771 
772    efl_data_xunref(pd->base->surface, pd->surface, obj);
773    efl_data_xunref(obj, pd->base, obj);
774    efl_data_xunref(obj, pd->shape, obj);
775    efl_data_xunref(obj, pd->public_shape, obj);
776 
777    efl_destructor(efl_super(obj, MY_CLASS));
778 }
779 
780 unsigned int
_ector_renderer_software_shape_ector_renderer_crc_get(const Eo * obj,Ector_Renderer_Software_Shape_Data * pd)781 _ector_renderer_software_shape_ector_renderer_crc_get(const Eo *obj,
782                                                       Ector_Renderer_Software_Shape_Data *pd)
783 {
784    unsigned int crc;
785 
786    crc = ector_renderer_crc_get(efl_super(obj, MY_CLASS));
787 
788    crc = eina_crc((void*) &pd->shape->stroke.marker,
789                   sizeof (pd->shape->stroke.marker),
790                   crc, EINA_FALSE);
791    crc = eina_crc((void*) &pd->public_shape->stroke.scale,
792                   sizeof (pd->public_shape->stroke.scale) * 3,
793                   crc, EINA_FALSE); // scale, width, centered
794    crc = eina_crc((void*) &pd->public_shape->stroke.color,
795                   sizeof (pd->public_shape->stroke.color),
796                   crc, EINA_FALSE);
797    crc = eina_crc((void*) &pd->public_shape->stroke.cap,
798                   sizeof (pd->public_shape->stroke.cap),
799                   crc, EINA_FALSE);
800    crc = eina_crc((void*) &pd->public_shape->stroke.join,
801                   sizeof (pd->public_shape->stroke.join),
802                   crc, EINA_FALSE);
803 
804    if (pd->shape->fill)
805      crc = _renderer_crc_get(pd->shape->fill, crc);
806    if (pd->shape->stroke.fill)
807      crc = _renderer_crc_get(pd->shape->stroke.fill, crc);
808    if (pd->shape->stroke.marker)
809      crc = _renderer_crc_get(pd->shape->stroke.marker, crc);
810    if (pd->public_shape->stroke.dash_length)
811      {
812         crc = eina_crc((void*) pd->public_shape->stroke.dash,
813                        sizeof (Efl_Gfx_Dash) * pd->public_shape->stroke.dash_length,
814                        crc, EINA_FALSE);
815      }
816 
817    return crc;
818 }
819 
820 static void
_ector_renderer_software_shape_ector_renderer_comp_method_set(Eo * obj EINA_UNUSED,Ector_Renderer_Software_Shape_Data * pd,Ector_Buffer * comp,Efl_Gfx_Vg_Composite_Method method)821 _ector_renderer_software_shape_ector_renderer_comp_method_set(Eo *obj EINA_UNUSED,
822                                                               Ector_Renderer_Software_Shape_Data *pd,
823                                                               Ector_Buffer *comp,
824                                                               Efl_Gfx_Vg_Composite_Method method)
825 {
826    //Use ref/unref.
827    pd->comp = comp;
828    pd->comp_method = method;
829 }
830 
831 #include "ector_renderer_software_shape.eo.c"
832