This source file includes following definitions.
- gf_svg_is_animation_tag
- gf_svg_is_timing_tag
- gf_svg_create_node
- gf_svg_node_del
- gf_svg_node_init
- gf_svg_node_changed
- gf_svg_reset_path
- gf_svg_path_build
- gf_smil_delete_times
- gf_svg_delete_points
- gf_svg_delete_coordinates
- gf_svg_reset_iri
- gf_svg_delete_paint
- svg_delete_one_anim_value
- gf_svg_reset_animate_values
- gf_svg_reset_animate_value
- gf_svg_delete_attribute_value
- gf_smil_delete_key_types
#include <gpac/internal/scenegraph_dev.h>
#ifndef GPAC_DISABLE_SVG
#include <gpac/nodes_svg.h>
Bool gf_svg_is_animation_tag(u32 tag)
{
        return (tag == TAG_SVG_set ||
                tag == TAG_SVG_animate ||
                tag == TAG_SVG_animateColor ||
                tag == TAG_SVG_animateTransform ||
                tag == TAG_SVG_animateMotion ||
                tag == TAG_SVG_discard
               ) ? 1 : 0;
}
Bool gf_svg_is_timing_tag(u32 tag)
{
        if (gf_svg_is_animation_tag(tag)) return 1;
        else return (tag == TAG_SVG_animation ||
                             tag == TAG_SVG_audio ||
                             tag == TAG_LSR_conditional ||
                             tag == TAG_LSR_updates ||
                             tag == TAG_SVG_video)? GF_TRUE : GF_FALSE;
}
SVG_Element *gf_svg_create_node(u32 ElementTag)
{
        SVG_Element *p;
        if (gf_svg_is_timing_tag(ElementTag)) {
                SVGTimedAnimBaseElement *tap;
                GF_SAFEALLOC(tap, SVGTimedAnimBaseElement);
                p = (SVG_Element *)tap;
        } else if (ElementTag == TAG_SVG_handler) {
                SVG_handlerElement *hdl;
                GF_SAFEALLOC(hdl, SVG_handlerElement);
                p = (SVG_Element *)hdl;
        } else {
                GF_SAFEALLOC(p, SVG_Element);
        }
        gf_node_setup((GF_Node *)p, ElementTag);
        gf_sg_parent_setup((GF_Node *) p);
        return p;
}
void gf_svg_node_del(GF_Node *node)
{
        SVG_Element *p = (SVG_Element *)node;
        if (p->sgprivate->interact && p->sgprivate->interact->animations) {
                gf_smil_anim_delete_animations((GF_Node *)p);
        }
        if (p->sgprivate->tag==TAG_SVG_listener) {
                
                gf_dom_event_remove_listener_from_parent((GF_DOMEventTarget *)node->sgprivate->UserPrivate, (GF_Node *)p);
        }
        
        if (p->sgprivate->tag==TAG_SVG_handler) {
                GF_Node *listener = p->sgprivate->UserPrivate;
                if (listener && (listener->sgprivate->tag==TAG_SVG_listener)) {
                        GF_FieldInfo info;
                        if (gf_node_get_attribute_by_tag(listener, TAG_XMLEV_ATT_handler, 0, 0, &info) == GF_OK) {
                                XMLRI *iri = (XMLRI *)info.far_ptr;
                                if (iri->target) {
                                        assert(iri->target==p);
                                        iri->target = NULL;
                                }
                        }
                        gf_node_unregister(listener, NULL);
                }
        }
        
        if (node->sgprivate->interact && node->sgprivate->interact->dom_evt) {
                u32 i, count;
                count = gf_dom_listener_count(node);
                for (i=0; i<count; i++) {
                        GF_Node *listener = (GF_Node *)gf_list_get(node->sgprivate->interact->dom_evt->listeners, i);
                        listener->sgprivate->UserPrivate = NULL;
                }
        }
        if (gf_svg_is_timing_tag(node->sgprivate->tag)) {
                SVGTimedAnimBaseElement *tap = (SVGTimedAnimBaseElement *)node;
                if (tap->animp) {
                        gf_free(tap->animp);
                        gf_smil_anim_remove_from_target((GF_Node *)tap, (GF_Node *)tap->xlinkp->href->target);
                }
                if (tap->timingp)               {
                        gf_smil_timing_delete_runtime_info((GF_Node *)tap, tap->timingp->runtime);
                        gf_free(tap->timingp);
                }
                if (tap->xlinkp)        gf_free(tap->xlinkp);
        }
        gf_node_delete_attributes(node);
        gf_sg_parent_reset(node);
        gf_node_free(node);
}
Bool gf_svg_node_init(GF_Node *node)
{
        switch (node->sgprivate->tag) {
        case TAG_SVG_script:
                if (node->sgprivate->scenegraph->script_load)
                        node->sgprivate->scenegraph->script_load(node);
                return 1;
        case TAG_SVG_handler:
                if (node->sgprivate->scenegraph->script_load)
                        node->sgprivate->scenegraph->script_load(node);
                if (node->sgprivate->scenegraph->script_action)
                        ((SVG_handlerElement*)node)->handle_event = gf_sg_handle_dom_event;
                return 1;
        case TAG_LSR_conditional:
                gf_smil_timing_init_runtime_info(node);
                gf_smil_setup_events(node);
                return 1;
        case TAG_SVG_animateMotion:
        case TAG_SVG_set:
        case TAG_SVG_animate:
        case TAG_SVG_animateColor:
        case TAG_SVG_animateTransform:
                gf_smil_anim_init_node(node);
                gf_smil_setup_events(node);
                
                return (node->sgprivate->UserPrivate || node->sgprivate->UserCallback) ? 1 : 0;
        case TAG_SVG_audio:
        case TAG_SVG_video:
        case TAG_LSR_updates:
                gf_smil_timing_init_runtime_info(node);
                gf_smil_setup_events(node);
                
                return (node->sgprivate->UserPrivate || node->sgprivate->UserCallback) ? 1 : 0;
        case TAG_SVG_animation:
                gf_smil_timing_init_runtime_info(node);
                gf_smil_setup_events(node);
                return 0;
        
        case TAG_SVG_discard:
                gf_smil_anim_init_discard(node);
                gf_smil_setup_events(node);
                return 1;
        default:
                return 0;
        }
        return 0;
}
Bool gf_svg_node_changed(GF_Node *node, GF_FieldInfo *field)
{
        switch (node->sgprivate->tag) {
        case TAG_SVG_animateMotion:
        case TAG_SVG_discard:
        case TAG_SVG_set:
        case TAG_SVG_animate:
        case TAG_SVG_animateColor:
        case TAG_SVG_animateTransform:
        case TAG_LSR_conditional:
                gf_smil_timing_modified(node, field);
                return 1;
        case TAG_SVG_animation:
        case TAG_SVG_audio:
        case TAG_SVG_video:
        case TAG_LSR_updates:
                gf_smil_timing_modified(node, field);
                
                return 0;
        }
        return 0;
}
void gf_svg_reset_path(SVG_PathData d)
{
#if USE_GF_PATH
        gf_path_reset(&d);
#else
        u32 i, count;
        count = gf_list_count(d.commands);
        for (i = 0; i < count; i++) {
                u8 *command = (u8 *)gf_list_get(d.commands, i);
                gf_free(command);
        }
        gf_list_del(d.commands);
        count = gf_list_count(d.points);
        for (i = 0; i < count; i++) {
                SVG_Point *pt = (SVG_Point *)gf_list_get(d.points, i);
                gf_free(pt);
        }
        gf_list_del(d.points);
#endif
}
GF_EXPORT
void gf_svg_path_build(GF_Path *path, GF_List *commands, GF_List *points)
{
        u32 i, j, command_count;
        SVG_Point orig, ct_orig, ct_end, end, *tmp;
        command_count = gf_list_count(commands);
        orig.x = orig.y = ct_orig.x = ct_orig.y = 0;
        for (i=0, j=0; i<command_count; i++) {
                u8 *command = (u8 *)gf_list_get(commands, i);
                switch (*command) {
                case SVG_PATHCOMMAND_M: 
                        tmp = (SVG_Point*)gf_list_get(points, j);
                        orig = *tmp;
                        gf_path_add_move_to(path, orig.x, orig.y);
                        j++;
                        
                        ct_orig = orig;
                        break;
                case SVG_PATHCOMMAND_L: 
                        tmp = (SVG_Point*)gf_list_get(points, j);
                        end = *tmp;
                        gf_path_add_line_to(path, end.x, end.y);
                        j++;
                        orig = end;
                        
                        ct_orig = orig;
                        break;
                case SVG_PATHCOMMAND_C: 
                        tmp = (SVG_Point*)gf_list_get(points, j);
                        ct_orig = *tmp;
                        tmp = (SVG_Point*)gf_list_get(points, j+1);
                        ct_end = *tmp;
                        tmp = (SVG_Point*)gf_list_get(points, j+2);
                        end = *tmp;
                        gf_path_add_cubic_to(path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y);
                        ct_orig = ct_end;
                        orig = end;
                        j+=3;
                        break;
                case SVG_PATHCOMMAND_S: 
                        ct_orig.x = 2*orig.x - ct_orig.x;
                        ct_orig.y = 2*orig.y - ct_orig.y;
                        tmp = (SVG_Point*)gf_list_get(points, j);
                        ct_end = *tmp;
                        tmp = (SVG_Point*)gf_list_get(points, j+1);
                        end = *tmp;
                        gf_path_add_cubic_to(path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y);
                        ct_orig = ct_end;
                        orig = end;
                        j+=2;
                        break;
                case SVG_PATHCOMMAND_Q: 
                        tmp = (SVG_Point*)gf_list_get(points, j);
                        ct_orig = *tmp;
                        tmp = (SVG_Point*)gf_list_get(points, j+1);
                        end = *tmp;
                        gf_path_add_quadratic_to(path, ct_orig.x, ct_orig.y, end.x, end.y);
                        orig = end;
                        j+=2;
                        break;
                case SVG_PATHCOMMAND_T: 
                        ct_orig.x = 2*orig.x - ct_orig.x;
                        ct_orig.y = 2*orig.y - ct_orig.y;
                        tmp = (SVG_Point*)gf_list_get(points, j);
                        end = *tmp;
                        gf_path_add_quadratic_to(path, ct_orig.x, ct_orig.y, end.x, end.y);
                        orig = end;
                        j++;
                        break;
                case SVG_PATHCOMMAND_Z: 
                        gf_path_close(path);
                        break;
                }
        }
}
void gf_smil_delete_times(GF_List *list)
{
        u32 i, count;
        count = gf_list_count(list);
        for (i = 0; i < count; i++) {
                SMIL_Time *v = (SMIL_Time *)gf_list_get(list, i);
                if (v->element_id) gf_free(v->element_id);
                gf_free(v);
        }
        gf_list_del(list);
}
void gf_svg_delete_points(GF_List *list)
{
        u32 i, count = gf_list_count(list);
        for (i = 0; i < count; i++) {
                SVG_Point *p = (SVG_Point *)gf_list_get(list, i);
                gf_free(p);
        }
        gf_list_del(list);
}
void gf_svg_delete_coordinates(GF_List *list)
{
        u32 i, count = gf_list_count(list);
        for (i = 0; i < count; i++) {
                SVG_Coordinate *c = (SVG_Coordinate *)gf_list_get(list, i);
                gf_free(c);
        }
        gf_list_del(list);
}
void gf_svg_reset_iri(GF_SceneGraph *sg, XMLRI *iri)
{
        if (!iri) return;
        if (iri->string) gf_free(iri->string);
        gf_node_unregister_iri(sg, iri);
}
void gf_svg_delete_paint(GF_SceneGraph *sg, SVG_Paint *paint)
{
        if (!paint) return;
        
        if (sg) gf_svg_reset_iri(sg, &paint->iri);
        gf_free(paint);
}
static void svg_delete_one_anim_value(u8 anim_datatype, void *anim_value, GF_SceneGraph *sg)
{
        
        gf_svg_delete_attribute_value(anim_datatype, anim_value, sg);
}
void gf_svg_reset_animate_values(SMIL_AnimateValues anim_values, GF_SceneGraph *sg)
{
        u32 i, count;
        count = gf_list_count(anim_values.values);
        for (i = 0; i < count; i++) {
                void *value = gf_list_get(anim_values.values, i);
                svg_delete_one_anim_value(anim_values.type, value, sg);
        }
        gf_list_del(anim_values.values);
        anim_values.values = NULL;
}
void gf_svg_reset_animate_value(SMIL_AnimateValue anim_value, GF_SceneGraph *sg)
{
        svg_delete_one_anim_value(anim_value.type, anim_value.value, sg);
        anim_value.value = NULL;
}
void gf_svg_delete_attribute_value(u32 type, void *value, GF_SceneGraph *sg)
{
        GF_List *l;
        switch (type) {
        case SVG_Paint_datatype:
                gf_svg_delete_paint(sg, (SVG_Paint *)value);
                break;
        case XMLRI_datatype:
        case XML_IDREF_datatype:
                gf_svg_reset_iri(sg, (XMLRI *)value);
                gf_free(value);
                break;
        case SVG_Focus_datatype:
                gf_svg_reset_iri(sg, & ((SVG_Focus*)value)->target);
                gf_free(value);
                break;
        case SVG_PathData_datatype:
#if USE_GF_PATH
                gf_path_del((GF_Path *)value);
#else
                gf_free(value);
#endif
                break;
        case SVG_ID_datatype:
        case DOM_String_datatype:
        case SVG_ContentType_datatype:
        case SVG_LanguageID_datatype:
                if (*(SVG_String *)value) gf_free(*(SVG_String *)value);
                gf_free(value);
                break;
        case SVG_StrokeDashArray_datatype:
                if (((SVG_StrokeDashArray*)value)->array.vals) gf_free(((SVG_StrokeDashArray*)value)->array.vals);
                if (((SVG_StrokeDashArray*)value)->array.units) gf_free(((SVG_StrokeDashArray*)value)->array.units);
                gf_free(value);
                break;
        case SMIL_KeyTimes_datatype:
        case SMIL_KeyPoints_datatype:
        case SMIL_KeySplines_datatype:
        case SVG_Numbers_datatype:
        case SVG_Coordinates_datatype:
        case SVG_Points_datatype:
                l = *(GF_List**)value;
                while (gf_list_count(l)) {
                        void *n = gf_list_last(l);
                        gf_list_rem_last(l);
                        gf_free(n);
                }
                gf_list_del(l);
                gf_free(value);
                break;
        case SVG_FontFamily_datatype:
        {
                SVG_FontFamily *ff = (SVG_FontFamily *)value;
                if (ff->value) gf_free(ff->value);
                gf_free(value);
        }
        break;
        case SMIL_AttributeName_datatype:
        {
                SMIL_AttributeName *an = (SMIL_AttributeName *)value;
                if (an->name) gf_free(an->name);
                gf_free(value);
        }
        break;
        case SMIL_Times_datatype:
                gf_smil_delete_times(*(SMIL_Times *)value);
                gf_free(value);
                break;
        case SMIL_AnimateValue_datatype:
                svg_delete_one_anim_value(((SMIL_AnimateValue *)value)->type, ((SMIL_AnimateValue *)value)->value, sg);
                gf_free(value);
                break;
        case SMIL_AnimateValues_datatype:
                gf_svg_reset_animate_values(*((SMIL_AnimateValues *)value), sg);
                gf_free(value);
                break;
        case DOM_StringList_datatype:
                l = *(GF_List**)value;
                while (gf_list_count(l)) {
                        char *n = gf_list_last(l);
                        gf_list_rem_last(l);
                        gf_free(n);
                }
                gf_list_del(l);
                gf_free(value);
                break;
        case XMLRI_List_datatype:
                l = *(GF_List**)value;
                while (gf_list_count(l)) {
                        XMLRI *r = gf_list_last(l);
                        gf_list_rem_last(l);
                        if (r->string) gf_free(r->string);
                        gf_free(r);
                }
                gf_list_del(l);
                gf_free(value);
                break;
        case SMIL_RepeatCount_datatype:
        case SMIL_Duration_datatype:
        case SVG_Length_datatype:
        case SVG_Coordinate_datatype:
        case SVG_Visibility_datatype:
        case SVG_Display_datatype:
        default:
                gf_free(value);
        }
}
void gf_smil_delete_key_types(GF_List *l)
{
        while (gf_list_count(l)) {
                Fixed *t = (Fixed *)gf_list_get(l, 0);
                gf_list_rem(l, 0);
                gf_free(t);
        }
        gf_list_del(l);
}
#endif