📄 loader_svg_da.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/scenegraph_dev.h>#include <gpac/internal/laser_dev.h>#include <gpac/nodes_svg_da.h>#ifndef GPAC_DISABLE_SVGtypedef struct _st_entry{ struct _st_entry *next; /*as refered to by xlink-href*/ char *stream_name; /*stream id*/ u32 id; const char *nhml_info;} SVG_SAFExternalStream;typedef struct{ GF_SceneLoader *load; GF_Err last_error; GF_SAXParser *sax_parser; Bool has_root; /* stack of SVG nodes*/ GF_List *node_stack; GF_List *defered_hrefs; GF_List *defered_animations; GF_List *defered_listeners; /*non-linear parsing*/ GF_List *peeked_nodes; /*LASeR parsing*/ u32 command_depth; 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; SVG_SAFExternalStream *streams;} GF_SVG_Parser;typedef struct{ /*top of parsed sub-tree*/ SVG_Element *node; /*depth of unknown elements being skipped*/ u32 unknown_depth; /*last child added, used to speed-up parsing*/ GF_ChildNodeItem *last_child;} SVG_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_Element *animation_elt; /* anim parent*/ SVG_Element *anim_parent; /* target animated element*/ SVG_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 *type; /* only for animateTransform */ char *to; char *from; char *by; char *values;} SVG_DeferedAnimation;static GF_Err svg_report(GF_SVG_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] line %d - %s\n", gf_xml_sax_get_line(parser->sax_parser), szMsg)); }#endif if (e) parser->last_error = e; return e;}static void svg_progress(void *cbk, u32 done, u32 total){ gf_set_progress("SVG (Dynamic Attribute List) Parsing", done, total);}static SVG_SAFExternalStream *svg_saf_get_stream(GF_SVG_Parser *parser, u32 id, const char *name){ SVG_SAFExternalStream *st; st = parser->streams; while (st) { if (id == st->id) return st; if (name && !strcmp(name, st->stream_name) ) return st; st = st->next; } return NULL;}static SVG_SAFExternalStream *svg_saf_get_next_available_stream(GF_SVG_Parser *parser){ /*1 reserved for base laser stream*/ u32 id = 1; SVG_SAFExternalStream *st = parser->streams; SVG_SAFExternalStream *prev = NULL; while (st) { prev = st; id = st->id; st = st->next; } GF_SAFEALLOC(st, SVG_SAFExternalStream); if (prev) prev->next = st; else parser->streams = st; st->id = id+1; return st;}static void svg_lsr_set_v2(GF_SVG_Parser *parser){ u32 i; if (parser->load->ctx && parser->load->ctx->root_od) { for (i=0; i<gf_list_count(parser->load->ctx->root_od->ESDescriptors); i++) { GF_ESD *esd = gf_list_get(parser->load->ctx->root_od->ESDescriptors, i); if (esd->decoderConfig->streamType==GF_STREAM_SCENE) { GF_LASERConfig *cfg = (GF_LASERConfig *)esd->decoderConfig->decoderSpecificInfo; if (cfg && (cfg->tag==GF_ODF_LASER_CFG_TAG)) { if (!cfg->extensionIDBits) cfg->extensionIDBits = 2; } } } }}static void svg_process_media_href(GF_SVG_Parser *parser, XMLRI *iri){ SVG_SAFExternalStream *st = svg_saf_get_stream(parser, 0, iri->string+1); if (st) { free(iri->string); iri->string = NULL; iri->lsr_stream_id = st->id; iri->type = XMLRI_STREAMID; }}static void xsr_exec_command_list(GF_Node *node, void *par, Bool is_destroy){ GF_DOMUpdates *up = (GF_DOMUpdates *)node; if (is_destroy || !up || (up->sgprivate->tag!=TAG_DOMUpdates)) return; gf_sg_command_apply_list(up->sgprivate->scenegraph, up->updates, 0);}static GF_Node *svg_find_node(GF_SVG_Parser *parser, char *ID){ u32 i, count, tag; char *node_class; GF_Node *n = gf_sg_find_node_by_name(parser->load->scene_graph, ID); if (n) return n; count = gf_list_count(parser->peeked_nodes); for (i=0; i<count; i++) { n = (GF_Node*)gf_list_get(parser->peeked_nodes, i); if (!strcmp(gf_node_get_name(n), ID)) return n; } node_class = gf_xml_sax_peek_node(parser->sax_parser, "id", ID, NULL, NULL, NULL, NULL); if (!node_class) return NULL; tag = gf_svg_get_element_tag(node_class); n = gf_node_new(parser->load->scene_graph, tag); free(node_class); if (n) { gf_svg_parse_element_id(n, ID, 0); gf_list_add(parser->peeked_nodes, n); } return n;}static void svg_post_process_href(GF_SVG_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 void svg_delete_defered_anim(SVG_DeferedAnimation *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->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);}static Bool svg_parse_animation(GF_SVG_Parser *parser, GF_SceneGraph *sg, SVG_DeferedAnimation *anim, const char *nodeID){ GF_FieldInfo info; u32 tag; u8 anim_value_type = 0; if (anim->resolve_stage==0) { /* Stage 0: parsing the animation attribute values for that we need to resolve the target first */ if (!anim->target) anim->target = (SVG_Element *) gf_sg_find_node_by_name(sg, anim->target_id + 1); if (!anim->target) { /* the target is still not known stay in stage 0 */ return 0; } else { XMLRI *iri; gf_svg_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_xlink_href, 1, 0, &info); iri = (XMLRI *)info.far_ptr; iri->type = XMLRI_ELEMENTID; iri->target = anim->target; gf_svg_register_iri(sg, iri); } tag = gf_node_get_tag((GF_Node *)anim->animation_elt); /* get the attribute name attribute if specified */ if (anim->type && (tag== TAG_SVG_animateTransform) ) { gf_svg_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_transform_type, 1, 0, &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: svg_report(parser, GF_OK, "unknown datatype for animate transform"); return 0; } } else if (gf_svg_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_attributeName, 0, 0, &info) == GF_OK) { gf_svg_get_attribute_by_name((GF_Node *)anim->target, ((SMIL_AttributeName *)info.far_ptr)->name, 1, 1, &info); anim_value_type = info.fieldType; } else { if (tag == TAG_SVG_animateMotion) { anim_value_type = SVG_Motion_datatype; } else if (tag == TAG_SVG_discard) { /* there is no value to parse in discard, we can jump to the next stage */ anim->resolve_stage = 1; return svg_parse_animation(parser, sg, anim, nodeID); } else { svg_report(parser, GF_OK, "Missing attributeName attribute on %s", gf_node_get_name((GF_Node *)anim->animation_elt)); return 0; } } if (anim->to) { gf_svg_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_to, 1, 0, &info); gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->to, anim_value_type); if (anim_value_type==XMLRI_datatype) svg_post_process_href(parser, (XMLRI*)((SMIL_AnimateValue *)info.far_ptr)->value); } if (anim->from) { gf_svg_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_from, 1, 0, &info); gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->from, anim_value_type); if (anim_value_type==XMLRI_datatype) svg_post_process_href(parser, (XMLRI*)((SMIL_AnimateValue *)info.far_ptr)->value); } if (anim->by) { gf_svg_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_by, 1, 0, &info); gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->by, anim_value_type); if (anim_value_type==XMLRI_datatype) svg_post_process_href(parser, (XMLRI*)((SMIL_AnimateValue *)info.far_ptr)->value); } if (anim->values) { gf_svg_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_values, 1, 0, &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; SMIL_AnimateValues *anim_values; anim_values = (SMIL_AnimateValues *)info.far_ptr; count = gf_list_count(anim_values->values); for (i=0; i<count; i++) { XMLRI *iri = (XMLRI *)gf_list_get(anim_values->values, i); svg_post_process_href(parser, iri); } } } anim->resolve_stage = 1; } if (anim->resolve_stage == 1) { /* Stage 1: parsing the begin values we go into the next stage only if at least one begin value is resolved */ gf_svg_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_begin, 1, 0, &info); if (gf_svg_resolve_smil_times(sg, anim->anim_parent, *(GF_List **)info.far_ptr, 0, nodeID)) { anim->resolve_stage = 2; } else { return 0; } } gf_svg_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_end, 1, 0, &info); if (!gf_svg_resolve_smil_times(sg, anim->anim_parent, *(GF_List **)info.far_ptr, 1, nodeID)) return 0; /*animateMotion needs its children to be parsed before it can be initialized !! */ if (gf_node_get_tag((GF_Node *)anim->animation_elt) != TAG_SVG_animateMotion) gf_node_init((GF_Node *)anim->animation_elt); return 1;}static void svg_resolved_refs(GF_SVG_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 = targ; gf_svg_register_iri(sg, iri);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -