summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSubhransu Mohanty <sub.mohanty@samsung.com>2015-08-17 14:44:46 +0900
committerCedric BAIL <cedric@osg.samsung.com>2015-08-19 15:04:46 +0200
commite9896ee363e22e45b658cc5df650bfa0a1406047 (patch)
treed4fa790158f77c6aad83bbb9a3d07064461cd002
parent8b075c65348e460166aa964c48f379938cd0bc7d (diff)
ector: add dash stroking feature in software backend.
Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
-rw-r--r--src/lib/ector/software/ector_renderer_software_shape.c266
1 files changed, 263 insertions, 3 deletions
diff --git a/src/lib/ector/software/ector_renderer_software_shape.c b/src/lib/ector/software/ector_renderer_software_shape.c
index 2ea12eeebe..060879801e 100644
--- a/src/lib/ector/software/ector_renderer_software_shape.c
+++ b/src/lib/ector/software/ector_renderer_software_shape.c
@@ -245,6 +245,250 @@ _generate_outline(const Efl_Gfx_Path_Command *cmds, const double *pts, Outline *
245 return close_path; 245 return close_path;
246} 246}
247 247
248typedef struct _Line
249{
250 double x1;
251 double y1;
252 double x2;
253 double y2;
254}Line;
255
256static void
257_line_value_set(Line *l, double x1, double y1, double x2, double y2)
258{
259 l->x1 = x1;
260 l->y1 = y1;
261 l->x2 = x2;
262 l->y2 = y2;
263}
264
265// approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm.
266// With alpha = 1, beta = 3/8, giving results with a largest error less
267// than 7% compared to the exact value.
268static double
269_line_length(Line *l)
270{
271 double x = l->x2 - l->x1;
272 double y = l->y2 - l->y1;
273 x = x < 0 ? -x : x;
274 y = y < 0 ? -y : y;
275 return (x > y ? x + 0.375 * y : y + 0.375 * x);
276}
277
278static void
279_line_split_at_length(Line *l, double length, Line *left, Line *right)
280{
281 double len = _line_length(l);
282 double dx = ((l->x2 - l->x1)/len) *length;
283 double dy = ((l->y2 - l->y1)/len) *length;
284
285 left->x1 = l->x1;
286 left->y1 = l->y1;
287 left->x2 = left->x1 + dx;
288 left->y2 = left->y1 + dy;
289
290 right->x1 = left->x2;
291 right->y1 = left->y2;
292 right->x2 = l->x2;
293 right->y2 = l->y2;
294}
295
296typedef struct _Dash_Stroker
297{
298 Efl_Gfx_Dash *dash;
299 int dash_len;
300 Outline *outline;
301 int cur_dash_index;
302 double cur_dash_length;
303 Eina_Bool cur_op_gap;
304 double start_x, start_y;
305 double cur_x, cur_y;
306}Dash_Stroker;
307
308static void
309_dasher_line_to(Dash_Stroker *dasher, double x, double y)
310{
311 Line l, left, right;
312 double line_len = 0.0;
313 _line_value_set(&l, dasher->cur_x, dasher->cur_y, x, y);
314 line_len = _line_length(&l);
315 if (line_len < dasher->cur_dash_length)
316 {
317 dasher->cur_dash_length -= line_len;
318 if (!dasher->cur_op_gap)
319 {
320 _outline_move_to(dasher->outline, dasher->cur_x, dasher->cur_y);
321 _outline_line_to(dasher->outline, x, y);
322 }
323 }
324 else
325 {
326 while (line_len > dasher->cur_dash_length)
327 {
328 line_len -= dasher->cur_dash_length;
329 _line_split_at_length(&l, dasher->cur_dash_length, &left, &right);
330 if (!dasher->cur_op_gap)
331 {
332 _outline_move_to(dasher->outline, left.x1, left.y1);
333 _outline_line_to(dasher->outline, left.x2, left.y2);
334 dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].gap;
335 }
336 else
337 {
338 dasher->cur_dash_index = (dasher->cur_dash_index +1) % dasher->dash_len ;
339 dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].length;
340 }
341 dasher->cur_op_gap = !dasher->cur_op_gap;
342 l = right;
343 dasher->cur_x = l.x1;
344 dasher->cur_y = l.y1;
345 }
346 // remainder
347 dasher->cur_dash_length -= line_len;
348 if (!dasher->cur_op_gap)
349 {
350 _outline_move_to(dasher->outline, l.x1, l.y1);
351 _outline_line_to(dasher->outline, l.x2, l.y2);
352 }
353 if (dasher->cur_dash_length < 1.0)
354 {
355 // move to next dash
356 if (!dasher->cur_op_gap)
357 {
358 dasher->cur_op_gap = EINA_TRUE;
359 dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].gap;
360 }
361 else
362 {
363 dasher->cur_op_gap = EINA_FALSE;
364 dasher->cur_dash_index = (dasher->cur_dash_index +1) % dasher->dash_len ;
365 dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].length;
366 }
367 }
368 }
369 dasher->cur_x = x;
370 dasher->cur_y = y;
371}
372
373static void
374_dasher_cubic_to(Dash_Stroker *dasher, double cx1 , double cy1, double cx2, double cy2, double x, double y)
375{
376 Eina_Bezier b, left, right;
377 double bez_len = 0.0;
378 eina_bezier_values_set(&b, dasher->cur_x, dasher->cur_y, cx1, cy1, cx2, cy2, x, y);
379 bez_len = eina_bezier_length_get(&b);
380 if (bez_len < dasher->cur_dash_length)
381 {
382 dasher->cur_dash_length -= bez_len;
383 if (!dasher->cur_op_gap)
384 {
385 _outline_move_to(dasher->outline, dasher->cur_x, dasher->cur_y);
386 _outline_cubic_to(dasher->outline, cx1, cy1, cx2, cy2, x, y);
387 }
388 }
389 else
390 {
391 while (bez_len > dasher->cur_dash_length)
392 {
393 bez_len -= dasher->cur_dash_length;
394 eina_bezier_split_at_length(&b, dasher->cur_dash_length, &left, &right);
395 if (!dasher->cur_op_gap)
396 {
397 _outline_move_to(dasher->outline, left.start.x, left.start.y);
398 _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);
399 dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].gap;
400 }
401 else
402 {
403 dasher->cur_dash_index = (dasher->cur_dash_index +1) % dasher->dash_len ;
404 dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].length;
405 }
406 dasher->cur_op_gap = !dasher->cur_op_gap;
407 b = right;
408 dasher->cur_x = b.start.x;
409 dasher->cur_y = b.start.y;
410 }
411 // remainder
412 dasher->cur_dash_length -= bez_len;
413 if (!dasher->cur_op_gap)
414 {
415 _outline_move_to(dasher->outline, b.start.x, b.start.y);
416 _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);
417 }
418 if (dasher->cur_dash_length < 1.0)
419 {
420 // move to next dash
421 if (!dasher->cur_op_gap)
422 {
423 dasher->cur_op_gap = EINA_TRUE;
424 dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].gap;
425 }
426 else
427 {
428 dasher->cur_op_gap = EINA_FALSE;
429 dasher->cur_dash_index = (dasher->cur_dash_index +1) % dasher->dash_len ;
430 dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].length;
431 }
432 }
433 }
434 dasher->cur_x = x;
435 dasher->cur_y = y;
436}
437
438static Eina_Bool
439_generate_dashed_outline(const Efl_Gfx_Path_Command *cmds, const double *pts, Outline * outline, Efl_Gfx_Dash *dash, int dash_len)
440{
441 Dash_Stroker dasher;
442 dasher.dash = dash;
443 dasher.dash_len = dash_len;
444 dasher.outline = outline;
445 dasher.cur_dash_length = 0.0;
446 dasher.cur_dash_index = 0;
447 dasher.cur_op_gap = EINA_FALSE;
448 dasher.start_x = 0.0;
449 dasher.start_y = 0.0;
450 dasher.cur_x = 0.0;
451 dasher.cur_y = 0.0;
452
453 for (; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++)
454 {
455 switch (*cmds)
456 {
457 case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO:
458 {
459 // reset the dash
460 dasher.cur_dash_index = 0;
461 dasher.cur_dash_length = dasher.dash[0].length;
462 dasher.cur_op_gap = EINA_FALSE;
463 dasher.start_x = pts[0];
464 dasher.start_y = pts[1];
465 dasher.cur_x = pts[0];
466 dasher.cur_y = pts[1];
467 pts += 2;
468 }
469 break;
470 case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO:
471 _dasher_line_to(&dasher, pts[0], pts[1]);
472 pts += 2;
473 break;
474 case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO:
475 _dasher_cubic_to(&dasher, pts[2], pts[3], pts[4], pts[5], pts[0], pts[1]);
476 pts += 6;
477 break;
478
479 case EFL_GFX_PATH_COMMAND_TYPE_CLOSE:
480 _dasher_line_to(&dasher, dasher.start_x, dasher.start_y);
481 break;
482
483 case EFL_GFX_PATH_COMMAND_TYPE_LAST:
484 case EFL_GFX_PATH_COMMAND_TYPE_END:
485 break;
486 }
487 }
488 _outline_end(outline);
489 return EINA_FALSE;
490}
491
248static Eina_Bool 492static Eina_Bool
249_generate_stroke_data(Ector_Renderer_Software_Shape_Data *pd) 493_generate_stroke_data(Ector_Renderer_Software_Shape_Data *pd)
250{ 494{
@@ -296,9 +540,25 @@ _update_rle(Eo *obj, Ector_Renderer_Software_Shape_Data *pd)
296 pd->shape->stroke.scale), 540 pd->shape->stroke.scale),
297 pd->shape->stroke.cap, 541 pd->shape->stroke.cap,
298 pd->shape->stroke.join); 542 pd->shape->stroke.join);
299 pd->outline_data = ector_software_rasterizer_generate_stroke_rle_data(pd->surface->software, 543
300 &outline->ft_outline, 544 if (pd->shape->stroke.dash)
301 close_path); 545 {
546 dash_outline = _outline_create();
547 close_path = _generate_dashed_outline(cmds, pts, dash_outline,
548 pd->shape->stroke.dash,
549 pd->shape->stroke.dash_length);
550 _outline_transform(dash_outline, pd->base->m);
551 pd->outline_data = ector_software_rasterizer_generate_stroke_rle_data(pd->surface->software,
552 &dash_outline->ft_outline,
553 close_path);
554 _outline_destroy(dash_outline);
555 }
556 else
557 {
558 pd->outline_data = ector_software_rasterizer_generate_stroke_rle_data(pd->surface->software,
559 &outline->ft_outline,
560 close_path);
561 }
302 } 562 }
303 _outline_destroy(outline); 563 _outline_destroy(outline);
304 } 564 }