📄 loader_svg_sani.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / Scene Management sub-project * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <gpac/scene_manager.h>#include <gpac/constants.h>#include <gpac/utf.h>#include <gpac/xml.h>#include <gpac/events.h>#include <gpac/internal/bifs_dev.h>#include <gpac/internal/scenegraph_dev.h>#include <gpac/nodes_svg_sani.h>#ifndef GPAC_DISABLE_SVG#ifdef GPAC_ENABLE_SVG_SANItypedef struct{ GF_SceneLoader *load; GF_Err last_error; GF_SAXParser *sax_parser; Bool has_root; u32 command_depth; /* stack of SVG nodes*/ GF_List *node_stack; GF_List *defered_hrefs; GF_List *defered_animations; GF_List *defered_listeners; /*LASeR parsing*/ GF_StreamContext *laser_es; GF_AUContext *laser_au; GF_Command *command; /*SAF AU maps to OD AU and is used for each new media declaration*/ GF_AUContext *saf_au; GF_StreamContext *saf_es;} GF_SVG_SANI_Parser;typedef struct{ /*top of parsed sub-tree*/ SVG_SANI_Element *node; /*depth of unknown elements being skipped*/ u32 unknown_depth; /*last child added, used to speed-up parsing*/ GF_ChildNodeItem *last_child;} SVG_SANI_NodeStack;typedef struct { /* Stage of the resolving: 0: resolving attributes which depends on the target: from, to, by, values, type 1: resolving begin times 2: resolving end times */ u32 resolve_stage; /* Animation element being defered */ SVG_SANI_Element *animation_elt; /* anim parent*/ SVG_SANI_Element *anim_parent; /* target animated element*/ SVG_SANI_Element *target; /* id of the target element when unresolved*/ char *target_id; /* attributes which cannot be parsed until the type of the target attribute is known */ char *attributeName; char *type; /* only for animateTransform */ char *to; char *from; char *by; char *values;} DeferedSVG_SANI_Animation;static GF_Err svg_sani_report(GF_SVG_SANI_Parser *parser, GF_Err e, char *format, ...){#ifndef GPAC_DISABLE_LOG if (gf_log_get_level() && (gf_log_get_tools() & GF_LOG_PARSER)) { char szMsg[2048]; va_list args; va_start(args, format); vsprintf(szMsg, format, args); va_end(args); GF_LOG((u32) (e ? GF_LOG_ERROR : GF_LOG_WARNING), GF_LOG_PARSER, ("[SVG Parsing] %s (line %d)\n", szMsg, gf_xml_sax_get_line(parser->sax_parser)) ); }#endif if (e) parser->last_error = e; return e;}static void svg_sani_progress(void *cbk, u32 done, u32 total){ gf_set_progress("SVG Parsing", done, total);}static void svg_sani_init_root_element(GF_SVG_SANI_Parser *parser, SVG_SANI_svgElement *root_svg){ u32 svg_w, svg_h; svg_w = svg_h = 0; if (root_svg->width.type == SVG_NUMBER_VALUE) { svg_w = FIX2INT(root_svg->width.value); svg_h = FIX2INT(root_svg->height.value); } gf_sg_set_scene_size_info(parser->load->scene_graph, svg_w, svg_h, 1); if (parser->load->ctx) { parser->load->ctx->scene_width = svg_w; parser->load->ctx->scene_height = svg_h; } if (parser->load->type == GF_SM_LOAD_XSR) { assert(parser->command); assert(parser->command->tag == GF_SG_LSR_NEW_SCENE); parser->command->node = (GF_Node *)root_svg; } else { gf_sg_set_root_node(parser->load->scene_graph, (GF_Node *)root_svg); } parser->has_root = 1;}static void svg_sani_delete_defered_anim(DeferedSVG_SANI_Animation *anim, GF_List *defered_animations){ if (defered_animations) gf_list_del_item(defered_animations, anim); if (anim->target_id) free(anim->target_id); if (anim->attributeName) free(anim->attributeName); if (anim->to) free(anim->to); if (anim->from) free(anim->from); if (anim->by) free(anim->by); if (anim->values) free(anim->values); if (anim->type) free(anim->type); free(anim);}void svg_sani_reset_defered_animations(GF_List *l){ /*delete all unresolved anims*/ while (1) { DeferedSVG_SANI_Animation *anim = (DeferedSVG_SANI_Animation *)gf_list_last(l); if (!anim) break; svg_sani_delete_defered_anim(anim, l); }}static void svg_sani_post_process_href(GF_SVG_SANI_Parser *parser, XMLRI *iri){ /*keep data when encoding*/ if ( !(parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK)) return; /*unresolved, queue it...*/ if ((iri->type==XMLRI_ELEMENTID) && !iri->target && iri->string) { gf_list_add(parser->defered_hrefs, iri); } if (iri->type != XMLRI_STRING) return; gf_svg_store_embedded_data(iri, parser->load->localPath, parser->load->fileName);}static Bool svg_sani_resolve_smil_times(GF_SVG_SANI_Parser *parser, GF_SceneGraph *sg, SVG_SANI_Element *anim_parent, SVG_SANI_Element *anim, GF_List *smil_times, Bool is_end, const char *node_name){ u32 i, done, count = gf_list_count(smil_times); done = 0; for (i=0; i<count; i++) { SMIL_Time *t = (SMIL_Time *)gf_list_get(smil_times, i); /*not an event*/ if (t->type != GF_SMIL_TIME_EVENT) { done++; continue; } if (!t->element_id) { /*event source is anim parent*/ if (!t->element) t->element = (GF_Node *)anim_parent; done++; continue; } if (node_name && strcmp(node_name, t->element_id)) continue; t->element = gf_sg_find_node_by_name(sg, t->element_id); if (t->element) { free(t->element_id); t->element_id = NULL; done++; } } if (done!=count) return 0; return 1;}static Bool svg_sani_parse_animation(GF_SVG_SANI_Parser *parser, GF_SceneGraph *sg, DeferedSVG_SANI_Animation *anim, const char *nodeID){ GF_FieldInfo info; u32 tag; u8 anim_value_type = 0; if (anim->resolve_stage==0) { if (!anim->target) anim->target = (SVG_SANI_Element *) gf_sg_find_node_by_name(sg, anim->target_id + 1); if (!anim->target) return 0; /*setup IRI ptr*/ anim->animation_elt->xlink->href.type = XMLRI_ELEMENTID; anim->animation_elt->xlink->href.target = anim->target; gf_svg_register_iri(sg, &anim->animation_elt->xlink->href); tag = gf_node_get_tag((GF_Node *)anim->animation_elt); if (anim->attributeName) { SMIL_AttributeName *attname_value; /* get the type of the target attribute to determine type of the from/to/by ... */ if (gf_node_get_field_by_name((GF_Node *)anim->animation_elt, "attributeName", &info) != GF_OK) return 1; attname_value = (SMIL_AttributeName *)info.far_ptr; if (gf_node_get_field_by_name((GF_Node *)anim->target, anim->attributeName, &info) == GF_OK) { attname_value->type = info.fieldType; attname_value->field_ptr = info.far_ptr; attname_value->name = anim->attributeName; } else { return 1; } anim_value_type = attname_value->type; } else { if (tag == TAG_SVG_SANI_animateMotion) { anim_value_type = SVG_Motion_datatype; } else if (tag == TAG_SVG_SANI_discard) { anim->resolve_stage = 1; return svg_sani_parse_animation(parser, sg, anim, nodeID); } else { GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Parsing] missing attributeName attribute on %s\n", gf_node_get_name((GF_Node *)anim->animation_elt))); } } if (anim->type && (tag== TAG_SVG_SANI_animateTransform) ) { /* determine the transform_type in case of animateTransform attribute */ gf_node_get_field_by_name((GF_Node *)anim->animation_elt, "type", &info); gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->type, 0); switch(*(SVG_TransformType *) info.far_ptr) { case SVG_TRANSFORM_TRANSLATE: anim_value_type = SVG_Transform_Translate_datatype; break; case SVG_TRANSFORM_SCALE: anim_value_type = SVG_Transform_Scale_datatype; break; case SVG_TRANSFORM_ROTATE: anim_value_type = SVG_Transform_Rotate_datatype; break; case SVG_TRANSFORM_SKEWX: anim_value_type = SVG_Transform_SkewX_datatype; break; case SVG_TRANSFORM_SKEWY: anim_value_type = SVG_Transform_SkewY_datatype; break; case SVG_TRANSFORM_MATRIX: anim_value_type = SVG_Transform_datatype; break; default: GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] unknown datatype for animate transform.\n")); return 0; } } /* Parsing of to / from / by / values */ if (anim->to) { gf_node_get_field_by_name((GF_Node *)anim->animation_elt, "to", &info); gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->to, anim_value_type); if (anim_value_type==XMLRI_datatype) svg_sani_post_process_href(parser, (XMLRI*)anim->animation_elt->anim->to.value); } if (anim->from) { gf_node_get_field_by_name((GF_Node *)anim->animation_elt, "from", &info); gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->from, anim_value_type); if (anim_value_type==XMLRI_datatype) svg_sani_post_process_href(parser, (XMLRI*)anim->animation_elt->anim->from.value); } if (anim->by) { gf_node_get_field_by_name((GF_Node *)anim->animation_elt, "by", &info); gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->by, anim_value_type); if (anim_value_type==XMLRI_datatype) svg_sani_post_process_href(parser, (XMLRI*)anim->animation_elt->anim->by.value); } if (anim->values) { gf_node_get_field_by_name((GF_Node *)anim->animation_elt, "values", &info); gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->values, anim_value_type); if (anim_value_type==XMLRI_datatype) { u32 i, count = gf_list_count(anim->animation_elt->anim->values.values); for (i=0; i<count; i++) { XMLRI *iri = (XMLRI *)gf_list_get(anim->animation_elt->anim->values.values, i); svg_sani_post_process_href(parser, iri); } } } anim->resolve_stage = 1; } if (anim->resolve_stage == 1) { if (svg_sani_resolve_smil_times(parser, sg, anim->anim_parent, anim->animation_elt, anim->animation_elt->timing->begin, 0, nodeID)) { anim->resolve_stage = 2; } else { return 0; } } if (!svg_sani_resolve_smil_times(parser, sg, anim->anim_parent, anim->animation_elt, anim->animation_elt->timing->end, 1, nodeID)) return 0; /*animateMotion needs its children to be parsed !! */ if (!nodeID && gf_node_get_tag((GF_Node *)anim->animation_elt) == TAG_SVG_SANI_animateMotion) return 1; /*OK init the anim*/ gf_node_init((GF_Node *)anim->animation_elt); return 1;}static void svg_sani_resolved_refs(GF_SVG_SANI_Parser *parser, GF_SceneGraph *sg, const char *nodeID){ u32 count, i; /*check unresolved HREF*/ count = gf_list_count(parser->defered_hrefs); for (i=0; i<count; i++) { GF_Node *targ; XMLRI *iri = (XMLRI *)gf_list_get(parser->defered_hrefs, i); if (nodeID && strcmp(iri->string + 1, nodeID)) continue; targ = gf_sg_find_node_by_name(sg, iri->string + 1); if (targ) { iri->type = XMLRI_ELEMENTID; iri->target = (SVG_SANI_Element *) targ; gf_svg_register_iri(sg, iri); free(iri->string); iri->string = NULL; gf_list_rem(parser->defered_hrefs, i); i--; count--; } } /*check unresolved listeners*/ count = gf_list_count(parser->defered_listeners);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -