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