This source file includes following definitions.
- svg_drawable_is_over
- svg_drawable_is_over
- svg_clone_use_stack
- svg_drawable_3d_pick
- svg_drawable_pick
- svg_drawable_traverse
- svg_rect_add_arc
- svg_rect_rebuild
- svg_traverse_rect
- compositor_init_svg_rect
- svg_circle_rebuild
- svg_traverse_circle
- compositor_init_svg_circle
- svg_ellipse_rebuild
- svg_traverse_ellipse
- compositor_init_svg_ellipse
- svg_line_rebuild
- svg_traverse_line
- compositor_init_svg_line
- svg_polyline_rebuild
- svg_traverse_polyline
- compositor_init_svg_polyline
- svg_polygon_rebuild
- svg_traverse_polygon
- compositor_init_svg_polygon
- svg_path_rebuild
- svg_traverse_path
- compositor_init_svg_path
#include "visual_manager.h"
#include "nodes_stacks.h"
#ifdef GPAC_DISABLE_SVG
Bool svg_drawable_is_over(Drawable *drawable, Fixed x, Fixed y, DrawAspect2D *asp, GF_TraverseState *tr_state, GF_Rect *glyph_rc)
{
return 0;
}
#else
Bool svg_drawable_is_over(Drawable *drawable, Fixed x, Fixed y, DrawAspect2D *asp, GF_TraverseState *tr_state, GF_Rect *glyph_rc)
{
u32 check_fill, check_stroke;
Bool check_over, check_outline, check_vis, inside;
GF_Rect rc;
u8 ptr_evt;
ptr_evt = *tr_state->svg_props->pointer_events;
if (ptr_evt==SVG_POINTEREVENTS_NONE) {
return 0;
}
if (glyph_rc) {
rc = *glyph_rc;
} else {
gf_path_get_bounds(drawable->path, &rc);
}
inside = ( (x >= rc.x) && (y <= rc.y) && (x <= rc.x + rc.width) && (y >= rc.y - rc.height) ) ? 1 : 0;
if (ptr_evt==SVG_POINTEREVENTS_BOUNDINGBOX) return inside;
check_fill = check_stroke = check_over = check_outline = check_vis = 0;
switch (ptr_evt) {
case SVG_POINTEREVENTS_VISIBLE:
check_vis = 1;
check_fill = 1;
check_stroke = 1;
break;
case SVG_POINTEREVENTS_VISIBLEFILL:
check_vis = 1;
check_fill = 1;
break;
case SVG_POINTEREVENTS_VISIBLESTROKE:
check_vis = 1;
check_stroke = 1;
break;
case SVG_POINTEREVENTS_VISIBLEPAINTED:
check_vis = 1;
check_fill = 2;
check_stroke = 2;
break;
case SVG_POINTEREVENTS_FILL:
check_fill = 1;
break;
case SVG_POINTEREVENTS_STROKE:
check_stroke = 1;
break;
case SVG_POINTEREVENTS_ALL:
check_fill = 1;
check_stroke = 1;
break;
case SVG_POINTEREVENTS_PAINTED:
check_fill = 2;
check_stroke = 2;
break;
default:
return 0;
}
if (check_stroke==1) {
asp->pen_props.width = tr_state->svg_props->stroke_width ? tr_state->svg_props->stroke_width->value : 0;
}
if (!asp->pen_props.width) check_stroke = 0;
if (check_stroke) {
if (!inside) {
Fixed width = asp->pen_props.width;
rc.x -= width;
rc.y += width;
rc.width += 2*width;
rc.height += 2*width;
inside = ( (x >= rc.x) && (y <= rc.y) && (x <= rc.x + rc.width) && (y >= rc.y - rc.height) ) ? 1 : 0;
if (!inside) return 0;
}
} else if (!inside) {
return 0;
}
if (check_vis) {
if (*tr_state->svg_props->visibility!=SVG_VISIBILITY_VISIBLE) return 0;
}
if (check_fill) {
if ((check_fill!=2) || asp->fill_texture || asp->fill_color) {
if (glyph_rc) return 1;
if (gf_path_point_over(drawable->path, x, y)) return 1;
}
}
if (check_stroke) {
StrikeInfo2D *si;
if ((check_stroke!=2) || asp->line_texture || asp->line_color) {
if (glyph_rc) return 1;
si = drawable_get_strikeinfo(tr_state->visual->compositor, drawable, asp, tr_state->appear, NULL, 0, NULL);
if (si && si->outline && gf_path_point_over(si->outline, x, y))
return 1;
}
}
return 0;
}
void svg_clone_use_stack(GF_Compositor *compositor, GF_TraverseState *tr_state)
{
u32 i, count;
count = gf_list_count(tr_state->use_stack);
gf_list_reset(compositor->hit_use_stack);
for (i=0; i<count; i++) {
GF_Node *node = gf_list_get(tr_state->use_stack, i);
gf_list_add(compositor->hit_use_stack, node);
}
}
#ifndef GPAC_DISABLE_3D
void svg_drawable_3d_pick(Drawable *drawable, GF_TraverseState *tr_state, DrawAspect2D *asp)
{
SFVec3f local_pt, world_pt, vdiff;
SFVec3f hit_normal;
SFVec2f text_coords;
u32 i, count;
Fixed sqdist;
Bool node_is_over;
GF_Compositor *compositor;
GF_Matrix mx;
GF_Ray r;
compositor = tr_state->visual->compositor;
r = tr_state->ray;
gf_mx_copy(mx, tr_state->model_matrix);
gf_mx_inverse(&mx);
gf_mx_apply_ray(&mx, &r);
if (compositor->hit_square_dist && !compositor->grabbed_sensor && !tr_state->layer3d) {
GF_Plane p;
GF_BBox box;
SFVec3f hit = compositor->hit_world_point;
gf_mx_apply_vec(&mx, &hit);
p.normal = r.dir;
p.d = -1 * gf_vec_dot(p.normal, hit);
gf_bbox_from_rect(&box, &drawable->path->bbox);
if (gf_bbox_plane_relation(&box, &p) == GF_BBOX_FRONT) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SVG Picking] bounding box of node %s (DEF %s) below current hit point - skipping\n", gf_node_get_class_name(drawable->node), gf_node_get_name(drawable->node)));
return;
}
}
node_is_over = 0;
if (compositor_get_2d_plane_intersection(&r, &local_pt)) {
node_is_over = svg_drawable_is_over(drawable, local_pt.x, local_pt.y, asp, tr_state, NULL);
}
if (!node_is_over) return;
hit_normal.x = hit_normal.y = 0;
hit_normal.z = FIX_ONE;
text_coords.x = gf_divfix(local_pt.x, drawable->path->bbox.width) + FIX_ONE/2;
text_coords.y = gf_divfix(local_pt.y, drawable->path->bbox.height) + FIX_ONE/2;
world_pt = local_pt;
gf_mx_apply_vec(&tr_state->model_matrix, &world_pt);
for (i=0; i<tr_state->num_clip_planes; i++) {
if (gf_plane_get_distance(&tr_state->clip_planes[i], &world_pt) < 0) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SVG Picking] node %s (def %s) is not in clipper half space\n", gf_node_get_class_name(drawable->node), gf_node_get_name(drawable->node)));
return;
}
}
gf_vec_diff(vdiff, world_pt, tr_state->ray.orig);
sqdist = gf_vec_lensq(vdiff);
if (compositor->hit_square_dist && (compositor->hit_square_dist+FIX_EPSILON<sqdist)) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SVG Picking] node %s (def %s) is farther (%g) than current pick (%g)\n", gf_node_get_class_name(drawable->node), gf_node_get_name(drawable->node), FIX2FLT(sqdist), FIX2FLT(compositor->hit_square_dist)));
return;
}
compositor->hit_square_dist = sqdist;
gf_list_reset(compositor->sensors);
count = gf_list_count(tr_state->vrml_sensors);
for (i=0; i<count; i++) {
gf_list_add(compositor->sensors, gf_list_get(tr_state->vrml_sensors, i));
}
gf_mx_copy(compositor->hit_world_to_local, tr_state->model_matrix);
gf_mx_copy(compositor->hit_local_to_world, mx);
compositor->hit_local_point = local_pt;
compositor->hit_world_point = world_pt;
compositor->hit_world_ray = tr_state->ray;
compositor->hit_normal = hit_normal;
compositor->hit_texcoords = text_coords;
svg_clone_use_stack(compositor, tr_state);
compositor->hit_appear = NULL;
compositor->hit_node = drawable->node;
compositor->hit_text = NULL;
compositor->hit_use_dom_events = 1;
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SVG Picking] node %s (def %s) is under mouse - hit %g %g %g\n", gf_node_get_class_name(drawable->node), gf_node_get_name(drawable->node),
FIX2FLT(world_pt.x), FIX2FLT(world_pt.y), FIX2FLT(world_pt.z)));
}
#endif
void svg_drawable_pick(GF_Node *node, Drawable *drawable, GF_TraverseState *tr_state)
{
DrawAspect2D asp;
GF_Matrix2D inv_2d;
Fixed x, y;
Bool picked = 0;
GF_Compositor *compositor = tr_state->visual->compositor;
SVGPropertiesPointers backup_props;
GF_Matrix2D backup_matrix;
GF_Matrix mx_3d;
SVGAllAttributes all_atts;
if (!drawable->path) return;
gf_svg_flatten_attributes((SVG_Element *)node, &all_atts);
memcpy(&backup_props, tr_state->svg_props, sizeof(SVGPropertiesPointers));
gf_svg_apply_inheritance(&all_atts, tr_state->svg_props);
if (compositor_svg_is_display_off(tr_state->svg_props)) return;
compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d);
memset(&asp, 0, sizeof(DrawAspect2D));
drawable_get_aspect_2d_svg(node, &asp, tr_state);
#ifndef GPAC_DISABLE_3D
if (tr_state->visual->type_3d) {
svg_drawable_3d_pick(drawable, tr_state, &asp);
compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d);
memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
return;
}
#endif
gf_mx2d_copy(inv_2d, tr_state->transform);
gf_mx2d_inverse(&inv_2d);
x = tr_state->ray.orig.x;
y = tr_state->ray.orig.y;
gf_mx2d_apply_coords(&inv_2d, &x, &y);
picked = svg_drawable_is_over(drawable, x, y, &asp, tr_state, NULL);
if (picked) {
u32 count, i;
compositor->hit_local_point.x = x;
compositor->hit_local_point.y = y;
compositor->hit_local_point.z = 0;
gf_mx_from_mx2d(&compositor->hit_world_to_local, &tr_state->transform);
gf_mx_from_mx2d(&compositor->hit_local_to_world, &inv_2d);
compositor->hit_node = drawable->node;
compositor->hit_use_dom_events = 1;
compositor->hit_normal.x = compositor->hit_normal.y = 0;
compositor->hit_normal.z = FIX_ONE;
compositor->hit_texcoords.x = gf_divfix(x, drawable->path->bbox.width) + FIX_ONE/2;
compositor->hit_texcoords.y = gf_divfix(y, drawable->path->bbox.height) + FIX_ONE/2;
svg_clone_use_stack(compositor, tr_state);
compositor->hit_appear = NULL;
gf_list_reset(tr_state->visual->compositor->sensors);
count = gf_list_count(tr_state->vrml_sensors);
for (i=0; i<count; i++) {
gf_list_add(tr_state->visual->compositor->sensors, gf_list_get(tr_state->vrml_sensors, i));
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SVG Picking] node %s is under mouse - hit %g %g 0\n", gf_node_get_log_name(drawable->node), FIX2FLT(x), FIX2FLT(y)));
}
compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d);
memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
}
static void svg_drawable_traverse(GF_Node *node, void *rs, Bool is_destroy,
void (*rebuild_path)(GF_Node *, Drawable *, SVGAllAttributes *),
Bool is_svg_rect, Bool is_svg_path)
{
GF_Matrix2D backup_matrix;
GF_Matrix mx_3d;
DrawableContext *ctx;
SVGPropertiesPointers backup_props;
u32 backup_flags;
Drawable *drawable = (Drawable *)gf_node_get_private(node);
GF_TraverseState *tr_state = (GF_TraverseState *)rs;
SVGAllAttributes all_atts;
if (is_destroy) {
#if USE_GF_PATH
if (is_svg_path) drawable->path = NULL;
#endif
drawable_node_del(node);
return;
}
assert(tr_state->traversing_mode!=TRAVERSE_DRAW_2D);
if (tr_state->traversing_mode==TRAVERSE_PICK) {
svg_drawable_pick(node, drawable, tr_state);
return;
}
gf_svg_flatten_attributes((SVG_Element *)node, &all_atts);
if (!compositor_svg_traverse_base(node, &all_atts, (GF_TraverseState *)rs, &backup_props, &backup_flags))
return;
if (gf_node_dirty_get(node) & GF_SG_SVG_GEOMETRY_DIRTY) {
rebuild_path(node, drawable, &all_atts);
gf_node_dirty_clear(node, GF_SG_SVG_GEOMETRY_DIRTY);
drawable_mark_modified(drawable, tr_state);
}
if (drawable->path) {
if (*(tr_state->svg_props->fill_rule)==GF_PATH_FILL_ZERO_NONZERO) {
if (!(drawable->path->flags & GF_PATH_FILL_ZERO_NONZERO)) {
drawable->path->flags |= GF_PATH_FILL_ZERO_NONZERO;
drawable_mark_modified(drawable, tr_state);
}
} else {
if (drawable->path->flags & GF_PATH_FILL_ZERO_NONZERO) {
drawable->path->flags &= ~GF_PATH_FILL_ZERO_NONZERO;
drawable_mark_modified(drawable, tr_state);
}
}
}
if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) {
if (! compositor_svg_is_display_off(tr_state->svg_props)) {
DrawAspect2D asp;
gf_path_get_bounds(drawable->path, &tr_state->bounds);
if (!tr_state->ignore_strike) {
memset(&asp, 0, sizeof(DrawAspect2D));
drawable_get_aspect_2d_svg(node, &asp, tr_state);
if (asp.pen_props.width) {
StrikeInfo2D *si = drawable_get_strikeinfo(tr_state->visual->compositor, drawable, &asp, NULL, drawable->path, 0, NULL);
if (si && si->outline) {
gf_path_get_bounds(si->outline, &tr_state->bounds);
}
}
}
compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, NULL);
if (!tr_state->abort_bounds_traverse)
gf_mx2d_apply_rect(&tr_state->transform, &tr_state->bounds);
gf_sc_get_nodes_bounds(node, NULL, tr_state, NULL);
compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, NULL);
}
} else if (tr_state->traversing_mode == TRAVERSE_SORT) {
gf_node_dirty_clear(node, 0);
if (!compositor_svg_is_display_off(tr_state->svg_props) &&
( *(tr_state->svg_props->visibility) != SVG_VISIBILITY_HIDDEN) ) {
compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d);
ctx = drawable_init_context_svg(drawable, tr_state);
if (ctx) {
if (is_svg_rect) {
if (ctx->aspect.fill_texture && ctx->aspect.fill_texture->transparent) {}
else if (GF_COL_A(ctx->aspect.fill_color) != 0xFF) {}
else if (ctx->transform.m[1] || ctx->transform.m[3]) {}
else {
ctx->flags &= ~CTX_IS_TRANSPARENT;
if (!ctx->aspect.pen_props.width)
ctx->flags |= CTX_NO_ANTIALIAS;
}
}
if (all_atts.pathLength && all_atts.pathLength->type==SVG_NUMBER_VALUE)
ctx->aspect.pen_props.path_length = all_atts.pathLength->value;
#ifndef GPAC_DISABLE_3D
if (tr_state->visual->type_3d) {
if (!drawable->mesh) {
drawable->mesh = new_mesh();
if (drawable->path) mesh_from_path(drawable->mesh, drawable->path);
}
visual_3d_draw_from_context(ctx, tr_state);
ctx->drawable = NULL;
} else
#endif
{
drawable_finalize_sort(ctx, tr_state, NULL);
}
}
compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d);
}
}
memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
tr_state->svg_flags = backup_flags;
}
static GF_Err svg_rect_add_arc(GF_Path *gp, Fixed end_x, Fixed end_y, Fixed cx, Fixed cy, Fixed rx, Fixed ry)
{
Fixed angle, start_angle, end_angle, sweep, _vx, _vy, start_x, start_y;
s32 i, num_steps;
if (!gp->n_points) return GF_BAD_PARAM;
start_x = gp->points[gp->n_points-1].x;
start_y = gp->points[gp->n_points-1].y;
start_angle = gf_atan2(start_y-cy, start_x-cx);
end_angle = gf_atan2(end_y-cy, end_x-cx);
sweep = end_angle - start_angle;
if (sweep<0) sweep += 2*GF_PI;
num_steps = 16;
for (i=1; i<=num_steps; i++) {
angle = start_angle + sweep*i/num_steps;
_vx = cx + gf_mulfix(rx, gf_cos(angle));
_vy = cy + gf_mulfix(ry, gf_sin(angle));
gf_path_add_line_to(gp, _vx, _vy);
}
return GF_OK;
}
static void svg_rect_rebuild(GF_Node *node, Drawable *stack, SVGAllAttributes *atts)
{
Fixed rx = (atts->rx ? atts->rx->value : 0);
Fixed ry = (atts->ry ? atts->ry->value : 0);
Fixed x = (atts->x ? atts->x->value : 0);
Fixed y = (atts->y ? atts->y->value : 0);
Fixed width = (atts->width ? atts->width->value : 0);
Fixed height = (atts->height ? atts->height->value : 0);
drawable_reset_path(stack);
if (!width || !height) return;
if (rx || ry) {
Fixed cx, cy;
if (rx >= width/2) rx = width/2;
if (ry >= height/2) ry = height/2;
if (rx == 0) rx = ry;
if (ry == 0) ry = rx;
gf_path_add_move_to(stack->path, x+rx, y);
if (width-rx!=rx)
gf_path_add_line_to(stack->path, x+width-rx, y);
cx = x+width-rx;
cy = y+ry;
svg_rect_add_arc(stack->path, x+width, y+ry, cx, cy, rx, ry);
if (height-ry!=ry)
gf_path_add_line_to(stack->path, x+width, y+height-ry);
cx = x+width-rx;
cy = y+height-ry;
svg_rect_add_arc(stack->path, x+width-rx, y+height, cx, cy, rx, ry);
if (width-rx!=rx)
gf_path_add_line_to(stack->path, x+rx, y+height);
cx = x+rx;
cy = y+height-ry;
svg_rect_add_arc(stack->path, x, y+height-ry, cx, cy, rx, ry);
if (height-ry!=ry)
gf_path_add_line_to(stack->path, x, y+ry);
cx = x+rx;
cy = y+ry;
svg_rect_add_arc(stack->path, x+rx, y, cx, cy, rx, ry);
gf_path_close(stack->path);
} else {
gf_path_add_move_to(stack->path, x, y);
gf_path_add_line_to(stack->path, x+width, y);
gf_path_add_line_to(stack->path, x+width, y+height);
gf_path_add_line_to(stack->path, x, y+height);
gf_path_close(stack->path);
}
}
static void svg_traverse_rect(GF_Node *node, void *rs, Bool is_destroy)
{
svg_drawable_traverse(node, rs, is_destroy, svg_rect_rebuild, 1, 0);
}
void compositor_init_svg_rect(GF_Compositor *compositor, GF_Node *node)
{
drawable_stack_new(compositor, node);
gf_node_set_callback_function(node, svg_traverse_rect);
}
static void svg_circle_rebuild(GF_Node *node, Drawable *stack, SVGAllAttributes *atts)
{
Fixed r = 2*(atts->r ? atts->r->value : 0);
drawable_reset_path(stack);
gf_path_add_ellipse(stack->path, (atts->cx ? atts->cx->value : 0), (atts->cy ? atts->cy->value : 0), r, r);
}
static void svg_traverse_circle(GF_Node *node, void *rs, Bool is_destroy)
{
svg_drawable_traverse(node, rs, is_destroy, svg_circle_rebuild, 0, 0);
}
void compositor_init_svg_circle(GF_Compositor *compositor, GF_Node *node)
{
drawable_stack_new(compositor, node);
gf_node_set_callback_function(node, svg_traverse_circle);
}
static void svg_ellipse_rebuild(GF_Node *node, Drawable *stack, SVGAllAttributes *atts)
{
drawable_reset_path(stack);
gf_path_add_ellipse(stack->path, (atts->cx ? atts->cx->value : 0),
(atts->cy ? atts->cy->value : 0),
(atts->rx ? 2*atts->rx->value : 0),
(atts->ry ? 2*atts->ry->value : 0));
}
static void svg_traverse_ellipse(GF_Node *node, void *rs, Bool is_destroy)
{
svg_drawable_traverse(node, rs, is_destroy, svg_ellipse_rebuild, 0, 0);
}
void compositor_init_svg_ellipse(GF_Compositor *compositor, GF_Node *node)
{
drawable_stack_new(compositor, node);
gf_node_set_callback_function(node, svg_traverse_ellipse);
}
static void svg_line_rebuild(GF_Node *node, Drawable *stack, SVGAllAttributes *atts)
{
drawable_reset_path(stack);
gf_path_add_move_to(stack->path, (atts->x1 ? atts->x1->value : 0), (atts->y1 ? atts->y1->value : 0));
gf_path_add_line_to(stack->path, (atts->x2 ? atts->x2->value : 0), (atts->y2 ? atts->y2->value : 0));
}
static void svg_traverse_line(GF_Node *node, void *rs, Bool is_destroy)
{
svg_drawable_traverse(node, rs, is_destroy, svg_line_rebuild, 0, 0);
}
void compositor_init_svg_line(GF_Compositor *compositor, GF_Node *node)
{
drawable_stack_new(compositor, node);
gf_node_set_callback_function(node, svg_traverse_line);
}
static void svg_polyline_rebuild(GF_Node *node, Drawable *stack, SVGAllAttributes *atts)
{
u32 i, nbPoints;
drawable_reset_path(stack);
if (atts->points)
nbPoints = gf_list_count(*atts->points);
else
nbPoints = 0;
if (nbPoints) {
SVG_Point *p = (SVG_Point *)gf_list_get(*atts->points, 0);
gf_path_add_move_to(stack->path, p->x, p->y);
for (i = 1; i < nbPoints; i++) {
p = (SVG_Point *)gf_list_get(*atts->points, i);
gf_path_add_line_to(stack->path, p->x, p->y);
}
} else {
gf_path_add_move_to(stack->path, 0, 0);
}
}
static void svg_traverse_polyline(GF_Node *node, void *rs, Bool is_destroy)
{
svg_drawable_traverse(node, rs, is_destroy, svg_polyline_rebuild, 0, 0);
}
void compositor_init_svg_polyline(GF_Compositor *compositor, GF_Node *node)
{
drawable_stack_new(compositor, node);
gf_node_set_callback_function(node, svg_traverse_polyline);
}
static void svg_polygon_rebuild(GF_Node *node, Drawable *stack, SVGAllAttributes *atts)
{
u32 i, nbPoints;
drawable_reset_path(stack);
if (atts->points)
nbPoints = gf_list_count(*atts->points);
else
nbPoints = 0;
if (nbPoints) {
SVG_Point *p = (SVG_Point *)gf_list_get(*atts->points, 0);
gf_path_add_move_to(stack->path, p->x, p->y);
for (i = 1; i < nbPoints; i++) {
p = (SVG_Point *)gf_list_get(*atts->points, i);
gf_path_add_line_to(stack->path, p->x, p->y);
}
} else {
gf_path_add_move_to(stack->path, 0, 0);
}
gf_path_close(stack->path);
}
static void svg_traverse_polygon(GF_Node *node, void *rs, Bool is_destroy)
{
svg_drawable_traverse(node, rs, is_destroy, svg_polygon_rebuild, 0, 0);
}
void compositor_init_svg_polygon(GF_Compositor *compositor, GF_Node *node)
{
drawable_stack_new(compositor, node);
gf_node_set_callback_function(node, svg_traverse_polygon);
}
static void svg_path_rebuild(GF_Node *node, Drawable *stack, SVGAllAttributes *atts)
{
#if USE_GF_PATH
drawable_reset_path_outline(stack);
stack->path = atts->d;
#else
drawable_reset_path(stack);
gf_svg_path_build(stack->path, atts->d->commands, atts->d->points);
#endif
}
static void svg_traverse_path(GF_Node *node, void *rs, Bool is_destroy)
{
svg_drawable_traverse(node, rs, is_destroy, svg_path_rebuild, 0, 1);
}
void compositor_init_svg_path(GF_Compositor *compositor, GF_Node *node)
{
Drawable *dr = drawable_stack_new(compositor, node);
gf_path_del(dr->path);
dr->path = NULL;
gf_node_set_callback_function(node, svg_traverse_path);
}
#endif