Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2012
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / Scene Graph sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include <gpac/internal/scenegraph_dev.h>
27 : /*svg proto*/
28 : #include <gpac/scenegraph_svg.h>
29 : /*MPEG4 tags (for internal nodes)*/
30 : #include <gpac/nodes_mpeg4.h>
31 : /*X3D tags (for internal nodes)*/
32 : #include <gpac/nodes_x3d.h>
33 : #include <gpac/events.h>
34 : #include <gpac/nodes_svg.h>
35 :
36 : #ifdef GPAC_HAS_QJS
37 : #include "qjs_common.h"
38 : #endif
39 : static void ReplaceDEFNode(GF_Node *FromNode, GF_Node *node, GF_Node *newNode, Bool updateOrderedGroup);
40 :
41 : #ifndef GPAC_DISABLE_SVG
42 : static void ReplaceIRINode(GF_Node *FromNode, GF_Node *oldNode, GF_Node *newNode);
43 : #endif
44 :
45 93 : static void node_modif_stub(GF_SceneGraph *sg, GF_Node *node, GF_FieldInfo *info, GF_Node *script)
46 : {
47 93 : }
48 :
49 : GF_EXPORT
50 2899 : GF_SceneGraph *gf_sg_new()
51 : {
52 : GF_SceneGraph *tmp;
53 2899 : GF_SAFEALLOC(tmp, GF_SceneGraph);
54 2899 : if (!tmp) return NULL;
55 :
56 2899 : tmp->exported_nodes = gf_list_new();
57 :
58 : #ifndef GPAC_DISABLE_VRML
59 2899 : tmp->protos = gf_list_new();
60 2899 : tmp->unregistered_protos = gf_list_new();
61 2899 : tmp->Routes = gf_list_new();
62 2899 : tmp->routes_to_activate = gf_list_new();
63 2899 : tmp->routes_to_destroy = gf_list_new();
64 : #endif
65 :
66 : #ifndef GPAC_DISABLE_SVG
67 2899 : tmp->dom_evt_mx = gf_mx_new("DOMEvent");
68 2899 : tmp->dom_evt = gf_dom_event_target_new(GF_DOM_EVENT_TARGET_DOCUMENT, tmp);
69 2899 : tmp->xlink_hrefs = gf_list_new();
70 2899 : tmp->smil_timed_elements = gf_list_new();
71 2899 : tmp->modified_smil_timed_elements = gf_list_new();
72 2899 : tmp->listeners_to_add = gf_list_new();
73 : #endif
74 :
75 : #ifdef GPAC_HAS_QJS
76 2899 : tmp->scripts = gf_list_new();
77 2899 : tmp->objects = gf_list_new();
78 : #endif
79 2899 : tmp->on_node_modified = node_modif_stub;
80 :
81 : //test some functions only used in weird smil anim or dom JS, and not addressed in test suite
82 : #ifdef GPAC_ENABLE_COVERAGE
83 2899 : if (gf_sys_is_cov_mode()) {
84 : node_modif_stub(NULL, NULL, NULL, NULL);
85 2807 : gf_node_remove_id(NULL);
86 2807 : gf_node_list_get_child(NULL, 0);
87 2807 : gf_node_get_parent_count(NULL);
88 : gf_node_get_num_instances(NULL);
89 : gf_node_get_log_name(NULL);
90 : gf_sg_get_namespace(NULL, 0);
91 2807 : gf_node_parent_of(NULL, NULL);
92 : gf_sg_get_parent(tmp);
93 2807 : gf_node_get_attribute_count(NULL);
94 2807 : gf_xml_node_clone(NULL, NULL, NULL, NULL, 0);
95 2807 : gf_dom_flatten_textContent(NULL);
96 2807 : gf_smil_timing_pause(NULL);
97 2807 : gf_smil_timing_resume(NULL);
98 2807 : gf_smil_get_media_duration(NULL);
99 : }
100 : #endif
101 : return tmp;
102 : }
103 :
104 : GF_EXPORT
105 2202 : GF_SceneGraph *gf_sg_new_subscene(GF_SceneGraph *scene)
106 : {
107 : GF_SceneGraph *tmp;
108 2202 : if (!scene) return NULL;
109 2202 : tmp = gf_sg_new();
110 2202 : if (!tmp) return NULL;
111 2202 : tmp->parent_scene = scene;
112 2202 : tmp->script_action = scene->script_action;
113 2202 : tmp->script_action_cbck = scene->script_action_cbck;
114 2202 : tmp->script_load = scene->script_load;
115 2202 : tmp->on_node_modified = scene->on_node_modified;
116 :
117 : /*by default use the same callbacks*/
118 2202 : tmp->userpriv = scene->userpriv;
119 2202 : tmp->GetSceneTime = scene->GetSceneTime;
120 2202 : tmp->NodeCallback = scene->NodeCallback;
121 :
122 : #ifndef GPAC_DISABLE_VRML
123 2202 : tmp->GetExternProtoLib = scene->GetExternProtoLib;
124 : #endif
125 2202 : return tmp;
126 : }
127 :
128 :
129 : GF_EXPORT
130 1094 : void gf_sg_set_node_callback(GF_SceneGraph *sg, gf_sg_node_init_callback NodeCallback)
131 : {
132 1094 : sg->NodeCallback = NodeCallback;
133 1094 : }
134 :
135 : GF_EXPORT
136 709 : void gf_sg_set_scene_time_callback(GF_SceneGraph *sg, Double (*GetSceneTime)(void *user_priv))
137 : {
138 709 : sg->GetSceneTime = GetSceneTime;
139 709 : }
140 :
141 :
142 : GF_EXPORT
143 49435 : Double gf_node_get_scene_time(GF_Node *node)
144 : {
145 49435 : if (!node || !node->sgprivate->scenegraph->GetSceneTime) return 0.0;
146 49435 : return node->sgprivate->scenegraph->GetSceneTime(node->sgprivate->scenegraph->userpriv);
147 : }
148 :
149 :
150 : GF_EXPORT
151 2899 : void gf_sg_del(GF_SceneGraph *sg)
152 : {
153 2899 : if (!sg) return;
154 :
155 : #ifndef GPAC_DISABLE_VRML
156 2899 : if (sg->global_qp) {
157 24 : gf_node_unregister(sg->global_qp, NULL);
158 24 : sg->global_qp = NULL;
159 : }
160 : #endif
161 :
162 2899 : gf_sg_reset(sg);
163 :
164 : #ifndef GPAC_DISABLE_SVG
165 :
166 2899 : gf_dom_event_target_del(sg->dom_evt);
167 2899 : gf_list_del(sg->xlink_hrefs);
168 2899 : gf_list_del(sg->smil_timed_elements);
169 2899 : gf_list_del(sg->modified_smil_timed_elements);
170 2899 : gf_list_del(sg->listeners_to_add);
171 2899 : gf_mx_del(sg->dom_evt_mx);
172 : #endif
173 :
174 : #ifdef GPAC_HAS_QJS
175 2899 : gf_list_del(sg->scripts);
176 2899 : sg->scripts = NULL;
177 2899 : gf_list_del(sg->objects);
178 2899 : sg->objects = NULL;
179 : #ifndef GPAC_DISABLE_SVG
180 2899 : if (sg->svg_js) {
181 : void gf_svg_script_context_del(void *svg_js, GF_SceneGraph *scenegraph);
182 0 : gf_svg_script_context_del(sg->svg_js, sg);
183 : }
184 : #endif
185 :
186 : #endif //GPAC_HAS_QJS
187 :
188 : #ifndef GPAC_DISABLE_VRML
189 2899 : gf_list_del(sg->Routes);
190 2899 : gf_list_del(sg->protos);
191 2899 : gf_list_del(sg->unregistered_protos);
192 2899 : gf_list_del(sg->routes_to_activate);
193 2899 : gf_list_del(sg->routes_to_destroy);
194 : #endif
195 2899 : gf_list_del(sg->exported_nodes);
196 2899 : gf_free(sg);
197 : }
198 :
199 : /*recursive traverse of the whole graph to check for scope mixes (nodes from an inline graph
200 : inserted in a parent graph through bind or routes). We must do this otherwise we're certain to get random
201 : crashes or mem leaks.*/
202 0 : void SG_GraphRemoved(GF_Node *node, GF_SceneGraph *sg)
203 : {
204 : u32 i, count;
205 : GF_FieldInfo info;
206 : u32 tag;
207 :
208 :
209 0 : tag = node->sgprivate->tag;
210 0 : if (tag == TAG_ProtoNode) return;
211 :
212 : /*not possible in DOM ?*/
213 0 : if (tag>GF_NODE_RANGE_LAST_VRML) return;
214 :
215 0 : count = gf_node_get_field_count(node);
216 0 : for (i=0; i<count; i++) {
217 0 : gf_node_get_field(node, i, &info);
218 0 : if (info.fieldType==GF_SG_VRML_SFNODE) {
219 0 : GF_Node *n = *(GF_Node **) info.far_ptr;
220 0 : if (n) {
221 0 : if (n->sgprivate->scenegraph==sg) {
222 : /*if root of graph, skip*/
223 0 : if (sg->RootNode!=n) {
224 0 : gf_node_unregister(n, node);
225 : /*don't forget to remove node...*/
226 0 : *(GF_Node **) info.far_ptr = NULL;
227 : }
228 : } else {
229 0 : SG_GraphRemoved(n, sg);
230 : }
231 : }
232 : }
233 0 : else if (info.fieldType==GF_SG_VRML_MFNODE) {
234 0 : GF_ChildNodeItem *cur, *prev, *list = *(GF_ChildNodeItem **) info.far_ptr;
235 : prev = NULL;
236 0 : while (list) {
237 0 : if (list->node->sgprivate->scenegraph==sg) {
238 0 : gf_node_unregister(list->node, node);
239 :
240 : if (prev) prev->next = list->next;
241 0 : else *(GF_ChildNodeItem **) info.far_ptr = list->next;
242 : cur = list;
243 0 : gf_free(cur);
244 : } else {
245 0 : SG_GraphRemoved(list->node, sg);
246 : }
247 0 : list = list->next;
248 : }
249 : }
250 : /*for uncompressed files (bt/xmt/laserML), also reset command lists*/
251 0 : else if (info.fieldType==GF_SG_VRML_SFCOMMANDBUFFER) {
252 : u32 j, count2;
253 0 : SFCommandBuffer *cb = (SFCommandBuffer*)info.far_ptr;
254 0 : count2 = gf_list_count(cb->commandList);
255 0 : for (j=0; j<count2; j++) {
256 0 : u32 k = 0;
257 : GF_CommandField *f;
258 0 : GF_Command *com = gf_list_get(cb->commandList, j);
259 0 : while ((f=gf_list_enum(com->command_fields, &k))) {
260 0 : switch (f->fieldType) {
261 0 : case GF_SG_VRML_SFNODE:
262 0 : if (f->new_node) {
263 0 : if (f->new_node->sgprivate->scenegraph==sg) {
264 : /*if root of graph, skip*/
265 0 : if (sg->RootNode!=f->new_node) {
266 0 : gf_node_unregister(f->new_node, node);
267 : /*don't forget to remove node...*/
268 0 : f->new_node = NULL;
269 : }
270 : } else {
271 0 : SG_GraphRemoved(f->new_node, sg);
272 : }
273 : }
274 : break;
275 0 : case GF_SG_VRML_MFNODE:
276 0 : if (f->node_list) {
277 : GF_ChildNodeItem *cur, *prev, *list = f->node_list;
278 : prev = NULL;
279 0 : while (list) {
280 0 : if (list->node->sgprivate->scenegraph==sg) {
281 0 : gf_node_unregister(list->node, node);
282 :
283 : if (prev) prev->next = list->next;
284 0 : else f->node_list = list->next;
285 : cur = list;
286 0 : gf_free(cur);
287 : } else {
288 0 : SG_GraphRemoved(list->node, sg);
289 : }
290 0 : list = list->next;
291 : }
292 : }
293 : break;
294 : }
295 : }
296 : }
297 : }
298 : }
299 : }
300 :
301 : GFINLINE GF_Node *SG_SearchForNode(GF_SceneGraph *sg, GF_Node *node)
302 : {
303 : NodeIDedItem *reg_node = sg->id_node;
304 : while (reg_node) {
305 : if (reg_node->node == node) return reg_node->node;
306 : reg_node = reg_node->next;
307 : }
308 : return NULL;
309 : }
310 :
311 : static GFINLINE u32 get_num_id_nodes(GF_SceneGraph *sg)
312 : {
313 : u32 count = 0;
314 : NodeIDedItem *reg_node = sg->id_node;
315 79 : while (reg_node) {
316 63 : count++;
317 63 : reg_node = reg_node->next;
318 : }
319 : return count;
320 : }
321 :
322 : GF_EXPORT
323 5599 : void gf_sg_reset(GF_SceneGraph *sg)
324 : {
325 : GF_SceneGraph *par;
326 : GF_List *gc;
327 : #ifndef GPAC_DISABLE_SVG
328 : u32 type;
329 : #endif
330 : u32 count;
331 : NodeIDedItem *reg_node;
332 5599 : if (!sg) return;
333 :
334 5599 : GF_LOG(GF_LOG_DEBUG, GF_LOG_SCENE, ("[SceneGraph] Reseting scene graph\n"));
335 : #if 0
336 : /*inlined graph, remove any of this graph nodes from the parent graph*/
337 : if (!sg->pOwningProto && sg->parent_scene) {
338 : GF_SceneGraph *par = sg->parent_scene;
339 : while (par->parent_scene) par = par->parent_scene;
340 : if (par->RootNode) SG_GraphRemoved(par->RootNode, sg);
341 : }
342 : #endif
343 :
344 5599 : gc = gf_list_new();
345 : #ifdef GPAC_HAS_QJS
346 : /*scripts are the first source of cylic references in the graph. In order to clean properly
347 : force a remove of all script nodes, this will release all references to nodes in JS*/
348 11237 : while (gf_list_count(sg->scripts)) {
349 39 : GF_Node *n = gf_list_get(sg->scripts, 0);
350 39 : gf_list_rem(sg->scripts, 0);
351 : /*prevent destroy*/
352 39 : gf_node_register(n, NULL);
353 : /*remove from all parents*/
354 39 : gf_node_replace(n, NULL, 0);
355 : /*FORCE destroy in case the script refers to itself*/
356 39 : n->sgprivate->num_instances=1;
357 39 : gf_node_unregister(n, NULL);
358 : /*remember this script was forced to be destroyed*/
359 39 : gf_list_add(gc, n);
360 : }
361 : #endif
362 :
363 : #ifndef GPAC_DISABLE_SVG
364 :
365 5599 : gf_mx_p(sg->dom_evt_mx);
366 : /*remove listeners attached to the doc*/
367 5599 : gf_dom_event_remove_all_listeners(sg->dom_evt);
368 : /*flush any pending add_listener*/
369 5599 : gf_dom_listener_reset_deferred(sg);
370 5599 : gf_mx_v(sg->dom_evt_mx);
371 : #endif
372 :
373 : #ifndef GPAC_DISABLE_VRML
374 11202 : while (gf_list_count(sg->routes_to_activate)) {
375 4 : gf_list_rem(sg->routes_to_activate, 0);
376 : }
377 :
378 : /*destroy all routes*/
379 7512 : while (gf_list_count(sg->Routes)) {
380 1913 : GF_Route *r = (GF_Route*)gf_list_get(sg->Routes, 0);
381 : /*this will unregister the route from the graph, so don't delete the chain entry*/
382 1913 : gf_sg_route_del(r);
383 :
384 : }
385 : #endif
386 :
387 :
388 : /*reset all exported symbols */
389 5796 : while (gf_list_count(sg->exported_nodes)) {
390 197 : GF_Node *n = gf_list_get(sg->exported_nodes, 0);
391 197 : gf_list_rem(sg->exported_nodes, 0);
392 197 : gf_node_replace(n, NULL, 0);
393 : }
394 : /*reassign the list of exported nodes to our garbage collected nodes*/
395 5599 : gf_list_del(sg->exported_nodes);
396 5599 : sg->exported_nodes = gc;
397 :
398 : /*reset the main tree*/
399 5599 : if (sg->RootNode) gf_node_unregister(sg->RootNode, NULL);
400 5599 : sg->RootNode = NULL;
401 :
402 9286 : if (!sg->pOwningProto && gf_list_count(sg->protos) && sg->GetExternProtoLib)
403 46 : sg->GetExternProtoLib(sg->userpriv, NULL);
404 :
405 : /*WATCHOUT: we may have cyclic dependencies due to
406 : 1- a node referencing itself (forbidden in VRML)
407 : 2- nodes referred to in commands of conditionals children of this node (MPEG-4 is mute about that)
408 : we recursively preocess from last declared DEF node to first one
409 : */
410 5561 : restart:
411 5607 : reg_node = sg->id_node;
412 11214 : while (reg_node) {
413 : #if 0
414 : Bool ignore = 0;
415 : #endif
416 : GF_ParentList *nlist;
417 :
418 8 : GF_Node *node = reg_node->node;
419 8 : if (!node
420 : #ifndef GPAC_DISABLE_VRML
421 8 : || (node==sg->global_qp)
422 : #endif
423 : ) {
424 0 : reg_node = reg_node->next;
425 0 : continue;
426 : }
427 :
428 : /*first replace all instances in parents by NULL WITHOUT UNREGISTERING (to avoid destroying the node).
429 : This will take care of nodes referencing themselves*/
430 8 : nlist = node->sgprivate->parents;
431 : #ifndef GPAC_DISABLE_SVG
432 8 : type = (node->sgprivate->tag>GF_NODE_RANGE_LAST_VRML) ? 1 : 0;
433 : #endif
434 26 : while (nlist) {
435 10 : GF_ParentList *next = nlist->next;
436 : #if 0
437 : /*parent is a DEF'ed node, try to clean-up properly?*/
438 : if ((nlist->node!=node) && SG_SearchForNode(sg, nlist->node) != NULL) {
439 : ignore = 1;
440 : break;
441 : }
442 : #endif
443 :
444 : #ifndef GPAC_DISABLE_SVG
445 10 : if (type) {
446 0 : ReplaceIRINode(nlist->node, node, NULL);
447 : } else
448 : #endif
449 10 : ReplaceDEFNode(nlist->node, reg_node->node, NULL, 0);
450 :
451 : /*direct cyclic reference to ourselves, make sure we update the parentList to the next entry before freeing it
452 : since the next parent node could be reg_node again (reg_node->reg_node)*/
453 10 : if (nlist->node==node) {
454 0 : node->sgprivate->parents = next;
455 : }
456 :
457 10 : gf_free(nlist);
458 : nlist = next;
459 : #if 0
460 : if (ignore) {
461 : node->sgprivate->parents = nlist;
462 : continue;
463 : }
464 : #endif
465 : }
466 :
467 8 : node->sgprivate->parents = NULL;
468 :
469 : //sg->node_registry[i-1] = NULL;
470 8 : count = get_num_id_nodes(sg);
471 8 : node->sgprivate->num_instances = 1;
472 : /*remember this node was forced to be destroyed*/
473 8 : gf_list_add(sg->exported_nodes, node);
474 8 : gf_node_unregister(node, NULL);
475 16 : if (count != get_num_id_nodes(sg)) goto restart;
476 0 : reg_node = reg_node->next;
477 : }
478 :
479 : /*reset the forced destroy ndoes*/
480 5599 : gf_list_reset(sg->exported_nodes);
481 :
482 : #ifndef GPAC_DISABLE_VRML
483 : /*destroy all proto*/
484 11262 : while (gf_list_count(sg->protos)) {
485 64 : GF_Proto *p = (GF_Proto *)gf_list_get(sg->protos, 0);
486 : /*this will unregister the proto from the graph, so don't delete the chain entry*/
487 64 : gf_sg_proto_del(p);
488 : }
489 : /*destroy all unregistered proto*/
490 5599 : while (gf_list_count(sg->unregistered_protos)) {
491 0 : GF_Proto *p = (GF_Proto *)gf_list_get(sg->unregistered_protos, 0);
492 : /*this will unregister the proto from the graph, so don't delete the chain entry*/
493 0 : gf_sg_proto_del(p);
494 : }
495 :
496 : /*last destroy all routes*/
497 5599 : gf_sg_destroy_routes(sg);
498 5599 : sg->simulation_tick = 0;
499 :
500 : #endif /*GPAC_DISABLE_VRML*/
501 :
502 : #ifndef GPAC_DISABLE_SVG
503 : // assert(gf_list_count(sg->xlink_hrefs) == 0);
504 : #endif
505 :
506 11285 : while (gf_list_count(sg->ns)) {
507 87 : GF_XMLNS *ns = gf_list_get(sg->ns, 0);
508 87 : gf_list_rem(sg->ns, 0);
509 87 : if (ns->name) gf_free(ns->name);
510 87 : if (ns->qname) gf_free(ns->qname);
511 87 : gf_free(ns);
512 : }
513 5599 : gf_list_del(sg->ns);
514 5599 : sg->ns = 0;
515 :
516 : par = sg;
517 5599 : while (par->parent_scene) par = par->parent_scene;
518 :
519 : #ifndef GPAC_DISABLE_SVG
520 5599 : if (par != sg) {
521 : u32 i;
522 4248 : count = gf_list_count(par->smil_timed_elements);
523 4352 : for (i=0; i<count; i++) {
524 104 : SMIL_Timing_RTI *rti = gf_list_get(par->smil_timed_elements, i);
525 104 : if (rti->timed_elt->sgprivate->scenegraph == sg) {
526 0 : gf_list_rem(par->smil_timed_elements, i);
527 0 : i--;
528 0 : count--;
529 : }
530 : }
531 : }
532 : #endif
533 :
534 : #ifdef GF_SELF_REPLACE_ENABLE
535 : sg->graph_has_been_reset = 1;
536 : #endif
537 5599 : GF_LOG(GF_LOG_DEBUG, GF_LOG_SCENE, ("[SceneGraph] Scene graph has been reset\n"));
538 : }
539 :
540 :
541 : GFINLINE GF_Node *SG_SearchForDuplicateNodeID(GF_SceneGraph *sg, u32 nodeID, GF_Node *toExclude)
542 : {
543 : NodeIDedItem *reg_node = sg->id_node;
544 : while (reg_node) {
545 : if ((reg_node->node != toExclude) && (reg_node->NodeID == nodeID)) return reg_node->node;
546 : reg_node = reg_node->next;
547 : }
548 : return NULL;
549 : }
550 :
551 : #if 0 //unused
552 : void *gf_node_get_name_address(GF_Node*node)
553 : {
554 : NodeIDedItem *reg_node;
555 : if (!(node->sgprivate->flags & GF_NODE_IS_DEF)) return NULL;
556 : reg_node = node->sgprivate->scenegraph->id_node;
557 : while (reg_node) {
558 : if (reg_node->node == node) return ®_node->NodeName;
559 : reg_node = reg_node->next;
560 : }
561 : return NULL;
562 : }
563 : #endif
564 :
565 : GF_EXPORT
566 682 : void gf_sg_set_private(GF_SceneGraph *sg, void *ptr)
567 : {
568 682 : if (sg) sg->userpriv = ptr;
569 682 : }
570 :
571 : GF_EXPORT
572 39346 : void *gf_sg_get_private(GF_SceneGraph *sg)
573 : {
574 39346 : return sg ? sg->userpriv : NULL;
575 : }
576 :
577 :
578 : GF_EXPORT
579 2032 : void gf_sg_set_scene_size_info(GF_SceneGraph *sg, u32 width, u32 height, Bool usePixelMetrics)
580 : {
581 2032 : if (!sg) return;
582 2032 : if (width && height) {
583 1961 : sg->width = width;
584 1961 : sg->height = height;
585 : } else {
586 71 : sg->width = sg->height = 0;
587 : }
588 2032 : sg->usePixelMetrics = usePixelMetrics;
589 : }
590 :
591 : GF_EXPORT
592 7396 : Bool gf_sg_use_pixel_metrics(GF_SceneGraph *sg)
593 : {
594 7396 : if (sg) {
595 : #ifndef GPAC_DISABLE_VRML
596 0 : while (sg->pOwningProto) sg = sg->parent_scene;
597 : #endif
598 7396 : return sg->usePixelMetrics;
599 : }
600 : return 0;
601 : }
602 :
603 : GF_EXPORT
604 7096 : Bool gf_sg_get_scene_size_info(GF_SceneGraph *sg, u32 *width, u32 *height)
605 : {
606 7096 : if (!sg) return 0;
607 7096 : *width = sg->width;
608 7096 : *height = sg->height;
609 7096 : return (sg->width && sg->height) ? 1 : 0;
610 : }
611 :
612 :
613 : GF_EXPORT
614 132405 : GF_Node *gf_sg_get_root_node(GF_SceneGraph *sg)
615 : {
616 132405 : return sg ? sg->RootNode : NULL;
617 : }
618 :
619 : GF_EXPORT
620 374 : void gf_sg_set_root_node(GF_SceneGraph *sg, GF_Node *node)
621 : {
622 374 : if (sg) sg->RootNode = node;
623 374 : }
624 :
625 15730 : void remove_node_id(GF_SceneGraph *sg, GF_Node *node)
626 : {
627 15730 : NodeIDedItem *reg_node = sg->id_node;
628 15730 : if (!reg_node) return;
629 :
630 15730 : if (reg_node->node==node) {
631 10544 : sg->id_node = reg_node->next;
632 10544 : if (sg->id_node_last==reg_node)
633 1558 : sg->id_node_last = reg_node->next;
634 10544 : if (reg_node->NodeName) gf_free(reg_node->NodeName);
635 10544 : gf_free(reg_node);
636 : } else {
637 : NodeIDedItem *to_del;
638 115729 : while (reg_node->next) {
639 115729 : if (reg_node->next->node!=node) {
640 : reg_node = reg_node->next;
641 110543 : continue;
642 : }
643 : to_del = reg_node->next;
644 5186 : reg_node->next = to_del->next;
645 5186 : if (sg->id_node_last==to_del) {
646 705 : sg->id_node_last = reg_node->next ? reg_node->next : reg_node;
647 : }
648 5186 : if (to_del->NodeName) gf_free(to_del->NodeName);
649 5186 : to_del->NodeName = NULL;
650 5186 : gf_free(to_del);
651 5186 : break;
652 : }
653 : }
654 : }
655 :
656 10614 : GF_Err gf_node_try_destroy(GF_SceneGraph *sg, GF_Node *pNode, GF_Node *parentNode)
657 : {
658 10614 : if (!sg) return GF_BAD_PARAM;
659 : /*if node has been destroyed, don't even look at it*/
660 10614 : if (gf_list_find(sg->exported_nodes, pNode)>=0) return GF_OK;
661 10610 : if (!pNode || !pNode->sgprivate->num_instances) return GF_OK;
662 10610 : return gf_node_unregister(pNode, parentNode);
663 : }
664 :
665 : GF_EXPORT
666 145225 : GF_Err gf_node_unregister(GF_Node *pNode, GF_Node *parentNode)
667 : {
668 : #ifndef GPAC_DISABLE_VRML
669 : u32 j;
670 : #endif
671 : #ifdef GPAC_HAS_QJS
672 : Bool detach=0;
673 : #endif
674 : GF_SceneGraph *pSG;
675 :
676 145225 : if (!pNode) return GF_OK;
677 111584 : pSG = pNode->sgprivate->scenegraph;
678 :
679 111584 : if (parentNode) {
680 65947 : GF_ParentList *nlist = pNode->sgprivate->parents;
681 65947 : if (nlist) {
682 : GF_ParentList *prev = NULL;
683 295243 : while (nlist) {
684 295243 : if (nlist->node != parentNode) {
685 : prev = nlist;
686 230918 : nlist = nlist->next;
687 230918 : continue;
688 : }
689 64325 : if (prev) prev->next = nlist->next;
690 58280 : else pNode->sgprivate->parents = nlist->next;
691 64325 : gf_free(nlist);
692 : #ifdef GPAC_HAS_QJS
693 64325 : if (pNode->sgprivate->parents==NULL) detach=1;
694 : #endif
695 : break;
696 : }
697 : }
698 65947 : if (parentNode->sgprivate->scenegraph != pSG) {
699 2390 : gf_list_del_item(pSG->exported_nodes, pNode);
700 : }
701 : }
702 :
703 : #ifndef GPAC_DISABLE_VRML
704 : /*if this is a proto its is registered in its parent graph, not the current*/
705 111584 : if (pSG && (pNode == (GF_Node*)pSG->pOwningProto)) pSG = pSG->parent_scene;
706 : #endif
707 :
708 : /*unregister the instance*/
709 : assert(pNode->sgprivate->num_instances);
710 111584 : pNode->sgprivate->num_instances -= 1;
711 :
712 : /*this is just an instance removed*/
713 111584 : if (pNode->sgprivate->num_instances) {
714 : #ifdef GPAC_HAS_QJS
715 31834 : if (pNode->sgprivate->num_instances==1) detach=1;
716 31834 : if (pSG && pNode->sgprivate->scenegraph->on_node_modified && detach && pNode->sgprivate->interact && pNode->sgprivate->interact->js_binding) {
717 4022 : pNode->sgprivate->scenegraph->on_node_modified(pNode->sgprivate->scenegraph, pNode, NULL, NULL);
718 : }
719 : #endif
720 : return GF_OK;
721 : }
722 :
723 : assert(pNode->sgprivate->parents==NULL);
724 :
725 79750 : if (pSG) {
726 : GF_Route *r;
727 : /*if def, remove from sg def table*/
728 79146 : if (pNode->sgprivate->flags & GF_NODE_IS_DEF) {
729 15727 : remove_node_id(pSG, pNode);
730 : }
731 :
732 : #ifndef GPAC_DISABLE_VRML
733 : /*check all routes from or to this node and destroy them - cf spec*/
734 79146 : j=0;
735 298232 : while ((r = (GF_Route *)gf_list_enum(pSG->Routes, &j))) {
736 139940 : if ( (r->ToNode == pNode) || (r->FromNode == pNode)) {
737 13622 : gf_sg_route_del(r);
738 13622 : j--;
739 : }
740 : }
741 : #endif
742 :
743 : #ifndef GPAC_DISABLE_SVG
744 79146 : if (pSG->use_stack && (gf_list_del_item(pSG->use_stack, pNode)>=0)) {
745 0 : pSG->abort_bubbling = 1;
746 : }
747 : #endif
748 :
749 : }
750 : /*delete the node*/
751 79750 : if (pNode->sgprivate->scenegraph && (pNode->sgprivate->scenegraph->RootNode==pNode)) {
752 : pSG = pNode->sgprivate->scenegraph;
753 733 : gf_node_del(pNode);
754 733 : pSG->RootNode = NULL;
755 : } else {
756 79017 : gf_node_del(pNode);
757 : }
758 : return GF_OK;
759 : }
760 :
761 : GF_EXPORT
762 111598 : GF_Err gf_node_register(GF_Node *node, GF_Node *parentNode)
763 : {
764 111598 : if (!node) return GF_OK;
765 :
766 111567 : node->sgprivate->num_instances ++;
767 : /*parent may be NULL (top node and proto)*/
768 111567 : if (parentNode) {
769 64335 : if (!node->sgprivate->parents) {
770 51839 : node->sgprivate->parents = (GF_ParentList*)gf_malloc(sizeof(GF_ParentList));
771 51839 : node->sgprivate->parents->next = NULL;
772 51839 : node->sgprivate->parents->node = parentNode;
773 : } else {
774 : GF_ParentList *item, *nlist = node->sgprivate->parents;
775 423935 : while (nlist->next) nlist = nlist->next;
776 12496 : item = (GF_ParentList*)gf_malloc(sizeof(GF_ParentList));
777 12496 : item->next = NULL;
778 12496 : item->node = parentNode;
779 12496 : nlist->next = item;
780 : }
781 64335 : if (parentNode->sgprivate->scenegraph != node->sgprivate->scenegraph) {
782 2390 : gf_list_add(node->sgprivate->scenegraph->exported_nodes, node);
783 : }
784 : }
785 : return GF_OK;
786 : }
787 :
788 : /*replace or remove node instance in the given node (eg in all GF_Node or MFNode fields)
789 : this doesn't propagate in the scene graph. If updateOrderedGroup and new_node is NULL, the order field of OG
790 : is updated*/
791 460 : static void ReplaceDEFNode(GF_Node *FromNode, GF_Node *node, GF_Node *newNode, Bool updateOrderedGroup)
792 : {
793 : u32 i, j, count;
794 : GF_Node *p;
795 : GF_ChildNodeItem *list;
796 : GF_FieldInfo field;
797 :
798 : /*browse all fields*/
799 460 : count = gf_node_get_field_count(FromNode);
800 901 : for (i=0; i<count; i++) {
801 901 : gf_node_get_field(FromNode, i, &field);
802 901 : switch (field.fieldType) {
803 386 : case GF_SG_VRML_SFNODE:
804 : /*set to NULL for SFFields*/
805 386 : p = *((GF_Node **) field.far_ptr);
806 : /*this is a USE / DEF*/
807 386 : if (p == node) {
808 340 : *((GF_Node **) field.far_ptr) = NULL;
809 340 : if (newNode) {
810 9 : *((GF_Node **) field.far_ptr) = newNode;
811 : }
812 : goto exit;
813 : }
814 : break;
815 342 : case GF_SG_VRML_MFNODE:
816 342 : list = *(GF_ChildNodeItem **) field.far_ptr;
817 : j=0;
818 2886 : while (list) {
819 : /*replace nodes different from newNode but with same ID*/
820 2322 : if ((newNode == list->node) || (list->node != node)) {
821 2202 : list = list->next;
822 2202 : j++;
823 2202 : continue;
824 : }
825 120 : if (newNode) {
826 37 : list->node = newNode;
827 : } else {
828 83 : gf_node_list_del_child( (GF_ChildNodeItem **) field.far_ptr, list->node);
829 : #ifndef GPAC_DISABLE_VRML
830 83 : if (updateOrderedGroup && (FromNode->sgprivate->tag==TAG_MPEG4_OrderedGroup)) {
831 : GF_FieldInfo info;
832 : M_OrderedGroup *og = (M_OrderedGroup *)FromNode;
833 12 : info.fieldIndex = 3;
834 12 : info.fieldType = GF_SG_VRML_MFFLOAT;
835 12 : info.on_event_in = NULL;
836 12 : info.far_ptr = &og->order;
837 12 : gf_sg_vrml_mf_remove(&og->order, GF_SG_VRML_SFINT32, j);
838 12 : gf_node_changed_internal(FromNode, &info, 1);
839 : }
840 : #endif
841 : }
842 : goto exit;
843 : }
844 : break;
845 : /*not a node, continue*/
846 173 : default:
847 173 : continue;
848 : }
849 : }
850 : /*since we don't filter parent nodes this is called once per USE, not per container, so return if found*/
851 0 : exit:
852 :
853 : #ifndef GPAC_DISABLE_VRML
854 : /*Notify all scripts that the node is being removed from its parent - we have to do that because nodes used in scripts are not
855 : always registered in MF/SFNodes fields of the script.*/
856 460 : switch (FromNode->sgprivate->tag) {
857 0 : case TAG_MPEG4_Script:
858 : #ifndef GPAC_DISABLE_X3D
859 : case TAG_X3D_Script:
860 : #endif
861 0 : if (FromNode->sgprivate->scenegraph->on_node_modified)
862 0 : FromNode->sgprivate->scenegraph->on_node_modified(FromNode->sgprivate->scenegraph, node, NULL, FromNode);
863 : break;
864 : }
865 : #endif
866 :
867 460 : gf_node_changed(FromNode, &field);
868 460 : }
869 :
870 : #ifndef GPAC_DISABLE_SVG
871 :
872 4 : static void Replace_IRI(GF_SceneGraph *sg, GF_Node *old_node, GF_Node *newNode)
873 : {
874 : u32 i, count;
875 4 : count = gf_list_count(sg->xlink_hrefs);
876 80 : for (i=0; i<count; i++) {
877 80 : XMLRI *iri = (XMLRI *)gf_list_get(sg->xlink_hrefs, i);
878 80 : if (iri->target == old_node) {
879 0 : iri->target = newNode;
880 0 : if (!newNode) {
881 0 : gf_list_rem(sg->xlink_hrefs, i);
882 0 : i--;
883 0 : count--;
884 : }
885 : }
886 : }
887 4 : }
888 :
889 : /*replace or remove node instance in the given node (eg in all IRI)*/
890 4 : static void ReplaceIRINode(GF_Node *FromNode, GF_Node *old_node, GF_Node *newNode)
891 : {
892 : GF_ChildNodeItem *prev = NULL;
893 4 : GF_ChildNodeItem *child = ((SVG_Element *)FromNode)->children;
894 93 : while (child) {
895 89 : if (child->node != old_node) {
896 : prev = child;
897 85 : child = child->next;
898 85 : continue;
899 : }
900 4 : if (newNode) {
901 0 : child->node = newNode;
902 : } else {
903 4 : if (prev) prev->next = child->next;
904 2 : else ((SVG_Element *)FromNode)->children = child->next;
905 4 : gf_free(child);
906 : }
907 : break;
908 : }
909 4 : }
910 : #endif
911 :
912 : /*get all parents of the node and replace, the instance of the node and finally destroy the node*/
913 : GF_EXPORT
914 340 : GF_Err gf_node_replace(GF_Node *node, GF_Node *new_node, Bool updateOrderedGroup)
915 : {
916 : #ifndef GPAC_DISABLE_SVG
917 : u32 type;
918 : #endif
919 : #ifndef GPAC_DISABLE_VRML
920 : Bool replace_proto;
921 : #endif
922 : Bool replace_root;
923 :
924 : #ifndef GPAC_DISABLE_SVG
925 340 : type = (node->sgprivate->tag>GF_NODE_RANGE_LAST_VRML) ? 1 : 0;
926 340 : if (type) {
927 4 : Replace_IRI(node->sgprivate->scenegraph, node, new_node);
928 : }
929 : #endif
930 :
931 : /*first check if this is the root node*/
932 340 : replace_root = (node->sgprivate->scenegraph->RootNode == node) ? 1 : 0;
933 :
934 : #ifndef GPAC_DISABLE_VRML
935 : /*check for proto replacement*/
936 : replace_proto = 0;
937 340 : if (node->sgprivate->scenegraph->pOwningProto
938 1 : && (gf_list_find(node->sgprivate->scenegraph->pOwningProto->node_code, node)>=0)) {
939 : replace_proto = 1;
940 : }
941 : #endif
942 :
943 454 : while (node->sgprivate->parents) {
944 454 : Bool do_break = node->sgprivate->parents->next ? 0 : 1;
945 454 : GF_Node *par = node->sgprivate->parents->node;
946 :
947 : #ifndef GPAC_DISABLE_SVG
948 454 : if (type)
949 4 : ReplaceIRINode(par, node, new_node);
950 : else
951 : #endif
952 450 : ReplaceDEFNode(par, node, new_node, updateOrderedGroup);
953 :
954 454 : if (new_node) gf_node_register(new_node, par);
955 454 : gf_node_unregister(node, par);
956 454 : gf_node_changed(par, NULL);
957 454 : if (do_break) break;
958 : }
959 :
960 340 : if (replace_root) {
961 0 : GF_SceneGraph *pSG = node->sgprivate->scenegraph;
962 0 : gf_node_unregister(node, NULL);
963 0 : pSG->RootNode = new_node;
964 : }
965 : #ifndef GPAC_DISABLE_VRML
966 340 : if (replace_proto) {
967 0 : GF_SceneGraph *pSG = node->sgprivate->scenegraph;
968 0 : gf_list_del_item(pSG->pOwningProto->node_code, node);
969 0 : if (pSG->pOwningProto->RenderingNode==node) pSG->pOwningProto->RenderingNode = NULL;
970 0 : gf_node_unregister(node, NULL);
971 : }
972 : #endif
973 340 : return GF_OK;
974 : }
975 :
976 15730 : static GFINLINE void insert_node_def(GF_SceneGraph *sg, GF_Node *def, u32 ID, const char *name)
977 : {
978 : NodeIDedItem *reg_node, *cur;
979 :
980 15730 : reg_node = (NodeIDedItem *) gf_malloc(sizeof(NodeIDedItem));
981 15730 : reg_node->node = def;
982 15730 : reg_node->NodeID = ID;
983 15730 : reg_node->NodeName = name ? gf_strdup(name) : NULL;
984 :
985 15730 : if (!sg->id_node) {
986 1558 : sg->id_node = reg_node;
987 1558 : sg->id_node_last = sg->id_node;
988 1558 : reg_node->next = NULL;
989 14172 : } else if (sg->id_node_last->NodeID < ID) {
990 14049 : sg->id_node_last->next = reg_node;
991 14049 : sg->id_node_last = reg_node;
992 14049 : reg_node->next = NULL;
993 123 : } else if (sg->id_node->NodeID>ID) {
994 8 : reg_node->next = sg->id_node;
995 8 : sg->id_node = reg_node;
996 : } else {
997 : cur = sg->id_node;
998 1186 : while (cur->next) {
999 1185 : if (cur->next->NodeID>ID) {
1000 114 : reg_node->next = cur->next;
1001 114 : cur->next = reg_node;
1002 : return;
1003 : }
1004 : cur = cur->next;
1005 : }
1006 1 : cur->next = reg_node;
1007 1 : sg->id_node_last = reg_node;
1008 1 : reg_node->next = NULL;
1009 : }
1010 : }
1011 :
1012 :
1013 :
1014 : GF_EXPORT
1015 15730 : GF_Err gf_node_set_id(GF_Node *p, u32 ID, const char *name)
1016 : {
1017 : GF_SceneGraph *pSG;
1018 15730 : if (!ID || !p || !p->sgprivate->scenegraph) return GF_BAD_PARAM;
1019 :
1020 : pSG = p->sgprivate->scenegraph;
1021 : #ifndef GPAC_DISABLE_VRML
1022 : /*if this is a proto register to the parent graph, not the current*/
1023 15730 : if (p == (GF_Node*)pSG->pOwningProto) pSG = pSG->parent_scene;
1024 : #endif
1025 :
1026 : /*new DEF ID*/
1027 15730 : if (!(p->sgprivate->flags & GF_NODE_IS_DEF) ) {
1028 15728 : p->sgprivate->flags |= GF_NODE_IS_DEF;
1029 15728 : insert_node_def(pSG, p, ID, name);
1030 : }
1031 : /*reassigning ID, remove node def*/
1032 : else {
1033 2 : char *_name = gf_strdup(name);
1034 2 : remove_node_id(pSG, p);
1035 2 : insert_node_def(pSG, p, ID, _name);
1036 2 : gf_free(_name);
1037 : }
1038 : return GF_OK;
1039 : }
1040 :
1041 : GF_EXPORT
1042 2808 : GF_Err gf_node_remove_id(GF_Node *p)
1043 : {
1044 : GF_SceneGraph *pSG;
1045 2808 : if (!p) return GF_BAD_PARAM;
1046 :
1047 1 : pSG = p->sgprivate->scenegraph;
1048 : #ifndef GPAC_DISABLE_VRML
1049 : /*if this is a proto register to the parent graph, not the current*/
1050 1 : if (p == (GF_Node*)pSG->pOwningProto) pSG = pSG->parent_scene;
1051 : #endif
1052 :
1053 : /*new DEF ID*/
1054 1 : if (p->sgprivate->flags & GF_NODE_IS_DEF) {
1055 1 : remove_node_id(pSG, p);
1056 1 : p->sgprivate->flags &= ~GF_NODE_IS_DEF;
1057 1 : return GF_OK;
1058 : }
1059 : return GF_BAD_PARAM;
1060 : }
1061 :
1062 : /*calls RenderNode on this node*/
1063 : GF_EXPORT
1064 1750225 : void gf_node_traverse(GF_Node *node, void *renderStack)
1065 : {
1066 1750225 : if (!node || !node->sgprivate) return;
1067 :
1068 1749499 : if (node->sgprivate->flags & GF_NODE_IS_DEACTIVATED) return;
1069 :
1070 1749499 : if (node->sgprivate->UserCallback) {
1071 : #ifdef GF_CYCLIC_TRAVERSE_ON
1072 1565611 : if (node->sgprivate->flags & GF_NODE_IN_TRAVERSE) return;
1073 1565609 : node->sgprivate->flags |= GF_NODE_IN_TRAVERSE;
1074 : assert(node->sgprivate->flags);
1075 : #endif
1076 1565609 : GF_LOG(GF_LOG_DEBUG, GF_LOG_SCENE, ("[SceneGraph] Traversing node %s (ID %s)\n", gf_node_get_class_name(node) , gf_node_get_name(node) ));
1077 1565609 : node->sgprivate->UserCallback(node, renderStack, 0);
1078 : #ifdef GF_CYCLIC_TRAVERSE_ON
1079 1565609 : node->sgprivate->flags &= ~GF_NODE_IN_TRAVERSE;
1080 : #endif
1081 1565609 : return;
1082 : }
1083 :
1084 : #ifndef GPAC_DISABLE_VRML
1085 183888 : if (node->sgprivate->tag != TAG_ProtoNode) return;
1086 :
1087 : /*if no rendering function is assigned this is a real proto (otherwise this is an hardcoded one)*/
1088 : if (!node->sgprivate->UserCallback) {
1089 :
1090 : /*if a rendering node is assigned use it*/
1091 92957 : if (((GF_ProtoInstance *) node)->RenderingNode) {
1092 : node = ((GF_ProtoInstance *) node)->RenderingNode;
1093 : /*if rendering node is a proto and not a hardcoded proto, traverse it*/
1094 92766 : if (!node->sgprivate->UserCallback && (node->sgprivate->tag == TAG_ProtoNode)) {
1095 : gf_node_traverse(node, renderStack);
1096 : return;
1097 : }
1098 : }
1099 : /*if no rendering node, check if the proto is fully instantiated (externProto)*/
1100 : else {
1101 : GF_ProtoInstance *proto_inst = (GF_ProtoInstance *) node;
1102 191 : gf_node_dirty_clear(node, 0);
1103 : /*proto has been deleted or dummy proto (without node code)*/
1104 191 : if (!proto_inst->proto_interface || (proto_inst->flags & GF_SG_PROTO_LOADED) ) return;
1105 : /*try to load the code*/
1106 191 : gf_sg_proto_instantiate(proto_inst);
1107 :
1108 : /*if user callback is set, this is an hardcoded proto. If not, locate the first traversable node*/
1109 191 : if (!node->sgprivate->UserCallback) {
1110 191 : if (!proto_inst->RenderingNode) {
1111 176 : gf_node_dirty_set(node, 0, 1);
1112 176 : return;
1113 : }
1114 : /*signal we have been loaded*/
1115 15 : node->sgprivate->scenegraph->NodeCallback(node->sgprivate->scenegraph->userpriv, GF_SG_CALLBACK_MODIFIED, node, NULL);
1116 : }
1117 : }
1118 : }
1119 :
1120 92781 : if (node->sgprivate->UserCallback) {
1121 : #ifdef GF_CYCLIC_TRAVERSE_ON
1122 92766 : if (node->sgprivate->flags & GF_NODE_IN_TRAVERSE) return;
1123 92766 : node->sgprivate->flags |= GF_NODE_IN_TRAVERSE;
1124 : #endif
1125 92766 : GF_LOG(GF_LOG_DEBUG, GF_LOG_SCENE, ("[SceneGraph] Traversing node %s\n", gf_node_get_class_name(node) ));
1126 92766 : node->sgprivate->UserCallback(node, renderStack, 0);
1127 : #ifdef GF_CYCLIC_TRAVERSE_ON
1128 92766 : node->sgprivate->flags &= ~GF_NODE_IN_TRAVERSE;
1129 : #endif
1130 : }
1131 :
1132 : #endif /*GPAC_DISABLE_VRML*/
1133 : }
1134 :
1135 : GF_EXPORT
1136 4262 : void gf_node_allow_cyclic_traverse(GF_Node *node)
1137 : {
1138 : #ifdef GF_CYCLIC_TRAVERSE_ON
1139 4262 : if (node) node->sgprivate->flags &= ~GF_NODE_IN_TRAVERSE;
1140 : #endif
1141 4262 : }
1142 :
1143 :
1144 : GF_EXPORT
1145 9258 : Bool gf_node_set_cyclic_traverse_flag(GF_Node *node, Bool on)
1146 : {
1147 : Bool ret = 1;
1148 : #ifdef GF_CYCLIC_TRAVERSE_ON
1149 9258 : if (node) {
1150 9258 : ret = (node->sgprivate->flags & GF_NODE_IN_TRAVERSE) ? 0 : 1;
1151 9258 : if (on) {
1152 4629 : node->sgprivate->flags |= GF_NODE_IN_TRAVERSE;
1153 : } else {
1154 4629 : node->sgprivate->flags &= ~GF_NODE_IN_TRAVERSE;
1155 : }
1156 : }
1157 : #endif
1158 9258 : return ret;
1159 : }
1160 :
1161 : /*blindly calls RenderNode on all nodes in the "children" list*/
1162 : GF_EXPORT
1163 2372 : void gf_node_traverse_children(GF_Node *node, void *renderStack)
1164 : {
1165 : GF_ChildNodeItem *child;
1166 :
1167 : assert(node);
1168 2372 : child = ((GF_ParentNode *)node)->children;
1169 7899 : while (child) {
1170 3155 : gf_node_traverse(child->node, renderStack);
1171 3155 : child = child->next;
1172 : }
1173 2372 : }
1174 :
1175 :
1176 : GF_EXPORT
1177 39689 : GF_SceneGraph *gf_node_get_graph(GF_Node *node)
1178 : {
1179 39689 : return (node ? node->sgprivate->scenegraph : NULL);
1180 : }
1181 :
1182 : GF_EXPORT
1183 21151 : GF_Node *gf_sg_find_node(GF_SceneGraph *sg, u32 nodeID)
1184 : {
1185 21151 : NodeIDedItem *reg_node = sg->id_node;
1186 1191206 : while (reg_node) {
1187 1169584 : if (reg_node->NodeID == nodeID) return reg_node->node;
1188 1148904 : reg_node = reg_node->next;
1189 : }
1190 : return NULL;
1191 : }
1192 :
1193 : GF_EXPORT
1194 31139 : GF_Node *gf_sg_find_node_by_name(GF_SceneGraph *sg, char *name)
1195 : {
1196 31139 : if (name) {
1197 31139 : NodeIDedItem *reg_node = sg->id_node;
1198 1212934 : while (reg_node) {
1199 1171895 : if (reg_node->NodeName && !strcmp(reg_node->NodeName, name)) return reg_node->node;
1200 1150656 : reg_node = reg_node->next;
1201 : }
1202 : }
1203 : return NULL;
1204 : }
1205 :
1206 :
1207 : GF_EXPORT
1208 6095 : u32 gf_sg_get_next_available_node_id(GF_SceneGraph *sg)
1209 : {
1210 : u32 ID;
1211 : NodeIDedItem *reg_node;
1212 6095 : if (!sg->id_node) return 1;
1213 : reg_node = sg->id_node;
1214 5463 : ID = reg_node->NodeID;
1215 : /*nodes are sorted*/
1216 165565 : while (reg_node->next) {
1217 154652 : if (ID+1<reg_node->next->NodeID) return ID+1;
1218 : ID = reg_node->next->NodeID;
1219 : reg_node = reg_node->next;
1220 : }
1221 5450 : return ID+1;
1222 : }
1223 :
1224 : GF_EXPORT
1225 2360 : u32 gf_sg_get_max_node_id(GF_SceneGraph *sg)
1226 : {
1227 : NodeIDedItem *reg_node;
1228 2360 : if (!sg->id_node) return 0;
1229 2287 : if (sg->id_node_last) return sg->id_node_last->NodeID;
1230 : reg_node = sg->id_node;
1231 0 : while (reg_node->next) reg_node = reg_node->next;
1232 0 : return reg_node->NodeID;
1233 : }
1234 :
1235 79751 : void gf_node_setup(GF_Node *p, u32 tag)
1236 : {
1237 79751 : if (!p) {
1238 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SceneGraph] Failed to setup NULL node\n"));
1239 : return;
1240 : }
1241 79751 : GF_SAFEALLOC(p->sgprivate, NodePriv);
1242 79751 : if (!p->sgprivate) {
1243 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SceneGraph] Failed to allocate node scenegraph private handler\n"));
1244 : return;
1245 : }
1246 79751 : p->sgprivate->tag = tag;
1247 79751 : p->sgprivate->flags = GF_SG_NODE_DIRTY;
1248 : }
1249 :
1250 614 : GF_Node *gf_sg_new_base_node()
1251 : {
1252 614 : GF_Node *newnode = (GF_Node *)gf_malloc(sizeof(GF_Node));
1253 614 : gf_node_setup(newnode, TAG_UndefinedNode);
1254 614 : return newnode;
1255 : }
1256 : GF_EXPORT
1257 1683951 : u32 gf_node_get_tag(GF_Node*p)
1258 : {
1259 : assert(p);
1260 1683951 : return p->sgprivate->tag;
1261 : }
1262 : GF_EXPORT
1263 57255 : u32 gf_node_get_id(GF_Node*p)
1264 : {
1265 : NodeIDedItem *reg_node;
1266 : GF_SceneGraph *sg;
1267 : assert(p);
1268 57255 : if (!(p->sgprivate->flags & GF_NODE_IS_DEF)) return 0;
1269 39408 : sg = p->sgprivate->scenegraph;
1270 : #ifndef GPAC_DISABLE_VRML
1271 : /*if this is a proto, look in parent graph*/
1272 39408 : if (p == (GF_Node*)sg->pOwningProto) sg = sg->parent_scene;
1273 : #endif
1274 :
1275 39408 : reg_node = sg->id_node;
1276 2380120 : while (reg_node) {
1277 2340712 : if (reg_node->node==p) return reg_node->NodeID;
1278 2301304 : reg_node = reg_node->next;
1279 : }
1280 : return 0;
1281 : }
1282 :
1283 : GF_EXPORT
1284 1733 : const char *gf_node_get_name(GF_Node*p)
1285 : {
1286 : GF_SceneGraph *sg;
1287 : NodeIDedItem *reg_node;
1288 1733 : if (!p || !(p->sgprivate->flags & GF_NODE_IS_DEF)) return NULL;
1289 :
1290 1719 : sg = p->sgprivate->scenegraph;
1291 : #ifndef GPAC_DISABLE_VRML
1292 : /*if this is a proto, look in parent graph*/
1293 1719 : if (p == (GF_Node*)sg->pOwningProto) sg = sg->parent_scene;
1294 : #endif
1295 :
1296 1719 : reg_node = sg->id_node;
1297 188958 : while (reg_node) {
1298 187239 : if (reg_node->node==p) return reg_node->NodeName;
1299 185520 : reg_node = reg_node->next;
1300 : }
1301 : return NULL;
1302 : }
1303 :
1304 : GF_EXPORT
1305 31435 : const char *gf_node_get_name_and_id(GF_Node*p, u32 *id)
1306 : {
1307 : GF_SceneGraph *sg;
1308 : NodeIDedItem *reg_node;
1309 : assert(p);
1310 31435 : if (!(p->sgprivate->flags & GF_NODE_IS_DEF)) {
1311 22297 : *id = 0;
1312 22297 : return NULL;
1313 : }
1314 :
1315 9138 : sg = p->sgprivate->scenegraph;
1316 : #ifndef GPAC_DISABLE_VRML
1317 : /*if this is a proto, look in parent graph*/
1318 9138 : if (p == (GF_Node*)sg->pOwningProto) sg = sg->parent_scene;
1319 : #endif
1320 :
1321 9138 : reg_node = sg->id_node;
1322 262124 : while (reg_node) {
1323 252986 : if (reg_node->node==p) {
1324 9138 : *id = reg_node->NodeID;
1325 9138 : return reg_node->NodeName;
1326 : }
1327 243848 : reg_node = reg_node->next;
1328 : }
1329 0 : *id = 0;
1330 0 : return NULL;
1331 : }
1332 :
1333 : GF_EXPORT
1334 1611070 : void *gf_node_get_private(GF_Node*p)
1335 : {
1336 : assert(p);
1337 1611070 : return p->sgprivate->UserPrivate;
1338 : }
1339 : GF_EXPORT
1340 23581 : void gf_node_set_private(GF_Node*p, void *pr)
1341 : {
1342 : assert(p);
1343 23581 : p->sgprivate->UserPrivate = pr;
1344 23581 : }
1345 : GF_EXPORT
1346 27769 : GF_Err gf_node_set_callback_function(GF_Node *p, void (*TraverseNode)(GF_Node *node, void *render_stack, Bool is_destroy) )
1347 : {
1348 : assert(p);
1349 27769 : p->sgprivate->UserCallback = TraverseNode;
1350 27769 : return GF_OK;
1351 : }
1352 :
1353 5179 : void gf_sg_parent_setup(GF_Node *node)
1354 : {
1355 5179 : ((GF_ParentNode *)node)->children = NULL;
1356 5179 : node->sgprivate->flags |= GF_SG_CHILD_DIRTY;
1357 5179 : }
1358 :
1359 : GF_EXPORT
1360 64001 : void gf_node_unregister_children(GF_Node *container, GF_ChildNodeItem *child)
1361 : {
1362 162981 : while (child) {
1363 : GF_ChildNodeItem *cur;
1364 34979 : gf_node_unregister(child->node, container);
1365 : cur = child;
1366 34979 : child = child->next;
1367 34979 : gf_free(cur);
1368 : }
1369 64001 : }
1370 :
1371 : GF_EXPORT
1372 2194 : GF_Err gf_node_list_insert_child(GF_ChildNodeItem **list, GF_Node *n, u32 pos)
1373 : {
1374 : GF_ChildNodeItem *child, *cur, *prev;
1375 : u32 cur_pos = 0;
1376 :
1377 : assert(pos != (u32) -1);
1378 :
1379 2194 : child = *list;
1380 :
1381 2194 : cur = (GF_ChildNodeItem*) gf_malloc(sizeof(GF_ChildNodeItem));
1382 2194 : if (!cur) return GF_OUT_OF_MEM;
1383 2194 : cur->node = n;
1384 2194 : cur->next = NULL;
1385 : prev = NULL;
1386 87475 : while (child) {
1387 84631 : if (pos==cur_pos) break;
1388 : /*append*/
1389 84449 : if (!child->next) {
1390 1362 : child->next = cur;
1391 1362 : return GF_OK;
1392 : }
1393 : prev = child;
1394 : child = child->next;
1395 83087 : cur_pos++;
1396 : }
1397 832 : cur->next = child;
1398 832 : if (prev) prev->next = cur;
1399 712 : else *list = cur;
1400 : return GF_OK;
1401 : }
1402 :
1403 : #if 0 //unused
1404 : GF_Err gf_node_list_append_child(GF_ChildNodeItem **list, GF_ChildNodeItem **last_child, GF_Node *n)
1405 : {
1406 : GF_ChildNodeItem *child, *cur;
1407 :
1408 : child = *list;
1409 :
1410 : cur = (GF_ChildNodeItem*) gf_malloc(sizeof(GF_ChildNodeItem));
1411 : if (!cur) return GF_OUT_OF_MEM;
1412 : cur->node = n;
1413 : cur->next = NULL;
1414 :
1415 : if (!child) {
1416 : *list = cur;
1417 : *last_child = cur;
1418 : } else {
1419 : if (! *last_child) {
1420 : while (child->next) {
1421 : child = child->next;
1422 : }
1423 : *last_child = child;
1424 : }
1425 : (*last_child)->next = cur;
1426 : *last_child = cur;
1427 : }
1428 : return GF_OK;
1429 : }
1430 : #endif
1431 :
1432 : GF_EXPORT
1433 39957 : GF_Node *gf_node_list_get_child(GF_ChildNodeItem *list, s32 pos)
1434 : {
1435 : s32 cur_pos = 0;
1436 92551 : while (list) {
1437 49767 : if (pos==cur_pos) return list->node;
1438 12649 : if ((pos<0) && !list->next) return list->node;
1439 12637 : list = list->next;
1440 12637 : cur_pos++;
1441 : }
1442 : return NULL;
1443 : }
1444 :
1445 : GF_EXPORT
1446 2 : s32 gf_node_list_find_child(GF_ChildNodeItem *list, GF_Node *n)
1447 : {
1448 : s32 res = 0;
1449 13 : while (list) {
1450 11 : if (list->node==n) return res;
1451 9 : list = list->next;
1452 9 : res++;
1453 : }
1454 : return -1;
1455 : }
1456 :
1457 : GF_EXPORT
1458 9844 : GF_Err gf_node_list_add_child(GF_ChildNodeItem **list, GF_Node *n)
1459 : {
1460 : GF_ChildNodeItem *child, *cur;
1461 :
1462 9844 : child = *list;
1463 :
1464 9844 : cur = (GF_ChildNodeItem*) gf_malloc(sizeof(GF_ChildNodeItem));
1465 9844 : if (!cur) return GF_OUT_OF_MEM;
1466 9844 : cur->node = n;
1467 9844 : cur->next = NULL;
1468 9844 : if (child) {
1469 104478 : while (child->next) child = child->next;
1470 4094 : child->next = cur;
1471 : } else {
1472 5750 : *list = cur;
1473 : }
1474 : return GF_OK;
1475 : }
1476 :
1477 :
1478 : GF_EXPORT
1479 23471 : GF_Err gf_node_list_add_child_last(GF_ChildNodeItem **list, GF_Node *n, GF_ChildNodeItem **last_child)
1480 : {
1481 : GF_ChildNodeItem *child, *cur;
1482 :
1483 23471 : child = *list;
1484 :
1485 23471 : cur = (GF_ChildNodeItem*) gf_malloc(sizeof(GF_ChildNodeItem));
1486 23471 : if (!cur) return GF_OUT_OF_MEM;
1487 23471 : cur->node = n;
1488 23471 : cur->next = NULL;
1489 23471 : if (child) {
1490 14296 : if (last_child && (*last_child) ) {
1491 45 : while ((*last_child)->next) (*last_child) = (*last_child)->next;
1492 14106 : (*last_child)->next = cur;
1493 14106 : (*last_child) = (*last_child)->next;
1494 : } else {
1495 489 : while (child->next) child = child->next;
1496 190 : child->next = cur;
1497 190 : if (last_child) *last_child = child->next;
1498 : }
1499 : } else {
1500 9175 : *list = cur;
1501 9175 : if (last_child)
1502 8510 : *last_child = *list;
1503 : }
1504 : return GF_OK;
1505 : }
1506 :
1507 : GF_EXPORT
1508 88 : Bool gf_node_list_del_child(GF_ChildNodeItem **list, GF_Node *n)
1509 : {
1510 : GF_ChildNodeItem *child, *cur;
1511 :
1512 88 : child = *list;
1513 88 : if (!child) return 0;
1514 88 : if (child->node==n) {
1515 11 : *list = child->next;
1516 11 : gf_free(child);
1517 11 : return 1;
1518 : }
1519 :
1520 933 : while (child->next) {
1521 933 : if (child->next->node!=n) {
1522 : child = child->next;
1523 856 : continue;
1524 : }
1525 : cur = child->next;
1526 77 : child->next = cur->next;
1527 77 : gf_free(cur);
1528 77 : return 1;
1529 : }
1530 : return 0;
1531 : }
1532 :
1533 : GF_EXPORT
1534 150 : GF_Node *gf_node_list_del_child_idx(GF_ChildNodeItem **list, u32 pos)
1535 : {
1536 : u32 cur_pos = 0;
1537 : GF_Node *ret = NULL;
1538 : GF_ChildNodeItem *child, *cur;
1539 :
1540 150 : child = *list;
1541 150 : if (!child) return 0;
1542 150 : if (!pos) {
1543 40 : *list = child->next;
1544 40 : ret = child->node;
1545 40 : gf_free(child);
1546 40 : return ret;
1547 : }
1548 :
1549 110 : while (child->next) {
1550 110 : if (cur_pos+1 != pos) {
1551 : child = child->next;
1552 : cur_pos++;
1553 0 : continue;
1554 : }
1555 : cur = child->next;
1556 110 : child->next = cur->next;
1557 110 : ret = cur->node;
1558 110 : gf_free(cur);
1559 110 : return ret;
1560 : }
1561 : return NULL;
1562 : }
1563 :
1564 : GF_EXPORT
1565 8379 : u32 gf_node_list_get_count(GF_ChildNodeItem *list)
1566 : {
1567 : u32 count = 0;
1568 187844 : while (list) {
1569 171086 : count++;
1570 171086 : list = list->next;
1571 : }
1572 8379 : return count;
1573 : }
1574 :
1575 6428 : void gf_sg_parent_reset(GF_Node *node)
1576 : {
1577 6428 : gf_node_unregister_children(node, ((GF_ParentNode *)node)->children);
1578 6428 : ((GF_ParentNode *)node)->children = NULL;
1579 6428 : }
1580 :
1581 79750 : void gf_node_free(GF_Node *node)
1582 : {
1583 79750 : if (!node) return;
1584 :
1585 79750 : if (node->sgprivate->UserCallback) node->sgprivate->UserCallback(node, NULL, 1);
1586 :
1587 79750 : if (node->sgprivate->scenegraph && node->sgprivate->scenegraph->NodeCallback)
1588 37533 : node->sgprivate->scenegraph->NodeCallback(node->sgprivate->scenegraph->userpriv, GF_SG_CALLBACK_NODE_DESTROY, node, NULL);
1589 :
1590 79750 : if (node->sgprivate->interact) {
1591 10400 : if (node->sgprivate->interact->routes) {
1592 0 : gf_list_del(node->sgprivate->interact->routes);
1593 : }
1594 : #ifndef GPAC_DISABLE_SVG
1595 10400 : if (node->sgprivate->interact->dom_evt) {
1596 518 : gf_dom_event_remove_all_listeners(node->sgprivate->interact->dom_evt);
1597 518 : gf_dom_event_target_del(node->sgprivate->interact->dom_evt);
1598 : }
1599 10400 : if (node->sgprivate->interact->animations) {
1600 0 : gf_list_del(node->sgprivate->interact->animations);
1601 : }
1602 : #endif
1603 : #ifdef GPAC_HAS_QJS
1604 10400 : if (node->sgprivate->interact->js_binding) {
1605 3496 : if (node->sgprivate->scenegraph && node->sgprivate->scenegraph->on_node_modified)
1606 3496 : node->sgprivate->scenegraph->on_node_modified(node->sgprivate->scenegraph, node, NULL, NULL);
1607 3496 : gf_list_del(node->sgprivate->interact->js_binding->fields);
1608 3496 : gf_free(node->sgprivate->interact->js_binding);
1609 : }
1610 : #endif
1611 10400 : gf_free(node->sgprivate->interact);
1612 : }
1613 : assert(! node->sgprivate->parents);
1614 79750 : gf_free(node->sgprivate);
1615 79750 : gf_free(node);
1616 : }
1617 :
1618 : GF_EXPORT
1619 2807 : u32 gf_node_get_parent_count(GF_Node *node)
1620 : {
1621 : u32 count = 0;
1622 2807 : GF_ParentList *nlist = node ? node->sgprivate->parents : 0;
1623 2807 : while (nlist) {
1624 0 : count++;
1625 0 : nlist = nlist->next;
1626 : }
1627 2807 : return count;
1628 : }
1629 :
1630 : GF_EXPORT
1631 1374 : GF_Node *gf_node_get_parent(GF_Node *node, u32 idx)
1632 : {
1633 :
1634 1374 : GF_ParentList *nlist = node->sgprivate->parents;
1635 : /*break cyclic graphs*/
1636 1374 : if (node->sgprivate->scenegraph->RootNode==node) return NULL;
1637 : #ifndef GPAC_DISABLE_VRML
1638 577 : if (node->sgprivate->scenegraph->pOwningProto && node->sgprivate->scenegraph->pOwningProto->RenderingNode==node)
1639 : return NULL;
1640 : #endif
1641 577 : if (!nlist) return NULL;
1642 457 : while (idx) {
1643 0 : nlist = nlist->next;
1644 0 : idx--;
1645 : }
1646 457 : return nlist ? nlist->node : NULL;
1647 : }
1648 :
1649 21377 : static void dirty_children(GF_Node *node)
1650 : {
1651 : u32 i, count;
1652 : GF_FieldInfo info;
1653 29559 : if (!node) return;
1654 :
1655 13195 : node->sgprivate->flags &= GF_NODE_INTERNAL_FLAGS;
1656 13195 : if (node->sgprivate->tag>=GF_NODE_RANGE_LAST_VRML) {
1657 0 : GF_ChildNodeItem *child = ((GF_ParentNode*)node)->children;
1658 0 : while (child) {
1659 0 : dirty_children(child->node);
1660 0 : child = child->next;
1661 : }
1662 : } else {
1663 13195 : count = gf_node_get_field_count(node);
1664 89346 : for (i=0; i<count; i++) {
1665 76151 : gf_node_get_field(node, i, &info);
1666 76151 : if (info.fieldType==GF_SG_VRML_SFNODE) dirty_children(*(GF_Node **)info.far_ptr);
1667 61266 : else if (info.fieldType==GF_SG_VRML_MFNODE) {
1668 1794 : GF_ChildNodeItem *list = *(GF_ChildNodeItem **) info.far_ptr;
1669 4196 : while (list) {
1670 608 : dirty_children(list->node);
1671 608 : list = list->next;
1672 : }
1673 : }
1674 : }
1675 : }
1676 : }
1677 174189 : static void dirty_parents(GF_Node *node)
1678 : {
1679 : Bool check_root = 1;
1680 : GF_ParentList *nlist;
1681 : #if defined GPAC_CONFIG_ANDROID
1682 : if ( !node || !node->sgprivate )
1683 : return;
1684 : #else
1685 176778 : if (!node) return;
1686 : #endif
1687 176778 : nlist = node->sgprivate->parents;
1688 511591 : while (nlist) {
1689 158035 : GF_Node *p = nlist->node;
1690 158035 : if (! (p->sgprivate->flags & GF_SG_CHILD_DIRTY)) {
1691 95275 : p->sgprivate->flags |= GF_SG_CHILD_DIRTY;
1692 95275 : dirty_parents(p);
1693 : }
1694 : check_root = 0;
1695 158035 : nlist = nlist->next;
1696 : }
1697 : /*propagate to parent scene graph */
1698 : #if defined GPAC_CONFIG_ANDROID
1699 : if (check_root && node->sgprivate->scenegraph) {
1700 : #else
1701 176778 : if (check_root) {
1702 : #endif
1703 : /*if root node of the scenegraph*/
1704 28908 : if (node->sgprivate->scenegraph->NodeCallback && (node==node->sgprivate->scenegraph->RootNode) ) {
1705 23108 : node->sgprivate->scenegraph->NodeCallback(node->sgprivate->scenegraph->userpriv, GF_SG_CALLBACK_GRAPH_DIRTY, NULL, NULL);
1706 : }
1707 : #ifndef GPAC_DISABLE_VRML
1708 : /*or if parent graph is a protoinstance but the node is not this proto*/
1709 5800 : else if (node->sgprivate->scenegraph->pOwningProto) {
1710 : GF_Node *the_node = (GF_Node *) node->sgprivate->scenegraph->pOwningProto;
1711 3183 : if (the_node != node) dirty_parents(the_node);
1712 : }
1713 : #endif
1714 : }
1715 : }
1716 : GF_EXPORT
1717 5536 : void gf_node_dirty_parent_graph(GF_Node *node)
1718 : {
1719 : /*if root node of the scenegraph*/
1720 5536 : if (node->sgprivate->scenegraph->NodeCallback ) {
1721 5536 : node->sgprivate->scenegraph->NodeCallback(node->sgprivate->scenegraph->userpriv, GF_SG_CALLBACK_GRAPH_DIRTY, NULL, NULL);
1722 : }
1723 5536 : }
1724 :
1725 : GF_EXPORT
1726 77244 : void gf_node_dirty_set(GF_Node *node, u32 flags, Bool and_dirty_parents)
1727 : {
1728 77244 : if (!node) return;
1729 :
1730 77244 : if (flags) node->sgprivate->flags |= (flags & (~GF_NODE_INTERNAL_FLAGS) );
1731 68820 : else node->sgprivate->flags |= GF_SG_NODE_DIRTY;
1732 :
1733 77244 : if (and_dirty_parents) dirty_parents(node);
1734 : }
1735 :
1736 : GF_EXPORT
1737 4575 : void gf_node_dirty_parents(GF_Node *node)
1738 : {
1739 4575 : dirty_parents(node);
1740 4575 : }
1741 :
1742 : GF_EXPORT
1743 882328 : void gf_node_dirty_clear(GF_Node *node, u32 flag_to_remove)
1744 : {
1745 882328 : if (!node) return;
1746 882328 : if (flag_to_remove) node->sgprivate->flags &= ~ (flag_to_remove & ~GF_NODE_INTERNAL_FLAGS);
1747 386611 : else node->sgprivate->flags &= GF_NODE_INTERNAL_FLAGS;
1748 : }
1749 :
1750 : GF_EXPORT
1751 1548614 : u32 gf_node_dirty_get(GF_Node *node)
1752 : {
1753 1548614 : if (node) return (node->sgprivate->flags & ~GF_NODE_INTERNAL_FLAGS);
1754 : return 0;
1755 : }
1756 :
1757 :
1758 : GF_EXPORT
1759 130279 : void gf_node_dirty_reset(GF_Node *node, Bool reset_children)
1760 : {
1761 142875 : if (!node) return;
1762 136024 : if (node->sgprivate->flags & ~GF_NODE_INTERNAL_FLAGS) {
1763 18499 : node->sgprivate->flags &= GF_NODE_INTERNAL_FLAGS;
1764 18499 : if (reset_children) {
1765 5884 : dirty_children(node);
1766 : #ifndef GPAC_DISABLE_VRML
1767 12615 : } else if (node->sgprivate->tag==TAG_MPEG4_Appearance) {
1768 12596 : gf_node_dirty_reset( ((M_Appearance*)node)->material, 1);
1769 : #endif
1770 : }
1771 : }
1772 : }
1773 :
1774 :
1775 :
1776 : GF_EXPORT
1777 54632 : void gf_node_init(GF_Node *node)
1778 : {
1779 54632 : GF_SceneGraph *pSG = node->sgprivate->scenegraph;
1780 : assert(pSG);
1781 : /*no user-defined init, consider the scenegraph is only used for parsing/encoding/decoding*/
1782 54632 : if (!pSG->NodeCallback) return;
1783 :
1784 : /*internal nodes*/
1785 : #ifndef GPAC_DISABLE_VRML
1786 35411 : if (gf_sg_vrml_node_init(node)) return;
1787 : #endif
1788 :
1789 : #ifndef GPAC_DISABLE_SVG
1790 32928 : if (gf_svg_node_init(node)) return;
1791 : #endif
1792 :
1793 : /*user defined init*/
1794 32920 : pSG->NodeCallback(pSG->userpriv, GF_SG_CALLBACK_INIT, node, NULL);
1795 : }
1796 :
1797 :
1798 86880 : void gf_node_changed_internal(GF_Node *node, GF_FieldInfo *field, Bool notify_scripts)
1799 : {
1800 : GF_SceneGraph *sg;
1801 86880 : if (!node) return;
1802 :
1803 86880 : sg = node->sgprivate->scenegraph;
1804 : assert(sg);
1805 :
1806 : #ifndef GPAC_DISABLE_VRML
1807 : /*signal changes in node to JS for MFFields*/
1808 86880 : if (field && notify_scripts && (node->sgprivate->flags & GF_NODE_HAS_BINDING) && !gf_sg_vrml_is_sf_field(field->fieldType) ) {
1809 251 : sg->on_node_modified(sg, node, field, NULL);
1810 : }
1811 : #endif
1812 :
1813 : #ifndef GPAC_DISABLE_SVG
1814 86880 : if (field && node->sgprivate->interact && node->sgprivate->interact->dom_evt) {
1815 : GF_DOM_Event evt;
1816 : memset(&evt, 0, sizeof(GF_DOM_Event));
1817 45 : evt.bubbles = 1;
1818 45 : evt.type = GF_EVENT_ATTR_MODIFIED;
1819 45 : evt.attr = field;
1820 45 : evt.detail = field->fieldIndex;
1821 45 : gf_dom_event_fire(node, &evt);
1822 : }
1823 : #endif
1824 :
1825 :
1826 : /*internal nodes*/
1827 : #ifndef GPAC_DISABLE_VRML
1828 86880 : if (gf_sg_vrml_node_changed(node, field)) return;
1829 : #endif
1830 :
1831 : #ifndef GPAC_DISABLE_SVG
1832 61235 : if (gf_svg_node_changed(node, field)) return;
1833 : #endif
1834 :
1835 : /*force child dirty tag*/
1836 61227 : if (field && ( (field->fieldType==GF_SG_VRML_SFNODE) || (field->fieldType==GF_SG_VRML_MFNODE)) )
1837 4383 : node->sgprivate->flags |= GF_SG_CHILD_DIRTY;
1838 :
1839 61227 : if (sg->NodeCallback) sg->NodeCallback(sg->userpriv, GF_SG_CALLBACK_MODIFIED, node, field);
1840 : }
1841 :
1842 : GF_EXPORT
1843 54252 : void gf_node_changed(GF_Node *node, GF_FieldInfo *field)
1844 : {
1845 54252 : gf_node_changed_internal(node, field, 1);
1846 :
1847 : #ifndef GPAC_DISABLE_SVG
1848 : /* we should avoid dispatching a DOMSubtreeModified event on insertion of time values in begin/end fields
1849 : because this retriggers begin/end events and reinsertion */
1850 108504 : if ((field == NULL || ((field->fieldIndex != TAG_SVG_ATT_begin) && (field->fieldIndex != TAG_SVG_ATT_end))) &&
1851 54611 : node->sgprivate->tag >= GF_NODE_RANGE_FIRST_SVG && node->sgprivate->tag <= GF_NODE_RANGE_LAST_SVG) {
1852 : GF_DOM_Event evt;
1853 359 : evt.type = GF_EVENT_TREE_MODIFIED;
1854 359 : evt.bubbles = 0;
1855 359 : evt.relatedNode = node;
1856 359 : gf_dom_event_fire(node, &evt);
1857 : }
1858 : #endif
1859 54252 : }
1860 :
1861 79750 : void gf_node_del(GF_Node *node)
1862 : {
1863 79750 : if (node->sgprivate->tag==TAG_UndefinedNode) gf_node_free(node);
1864 79137 : else if (node->sgprivate->tag==TAG_DOMText) {
1865 : GF_DOMText *t = (GF_DOMText *)node;
1866 952 : if (t->textContent) gf_free(t->textContent);
1867 952 : gf_sg_parent_reset(node);
1868 952 : gf_node_free(node);
1869 : }
1870 78185 : else if (node->sgprivate->tag==TAG_DOMUpdates) {
1871 : u32 i, count;
1872 : GF_DOMUpdates *up = (GF_DOMUpdates *)node;
1873 7 : if (up->data) gf_free(up->data);
1874 7 : count = gf_list_count(up->updates);
1875 23 : for (i=0; i<count; i++) {
1876 16 : GF_Command *com = gf_list_get(up->updates, i);
1877 16 : gf_sg_command_del(com);
1878 : }
1879 7 : gf_list_del(up->updates);
1880 7 : gf_sg_parent_reset(node);
1881 7 : gf_node_free(node);
1882 : }
1883 78178 : else if (node->sgprivate->tag == TAG_DOMFullNode) {
1884 : GF_DOMFullNode *n = (GF_DOMFullNode *)node;
1885 : #ifndef GPAC_DISABLE_SVG
1886 288 : gf_node_delete_attributes(node);
1887 : #endif
1888 288 : if (n->name) gf_free(n->name);
1889 288 : gf_sg_parent_reset(node);
1890 288 : gf_node_free(node);
1891 : }
1892 : #ifndef GPAC_DISABLE_VRML
1893 77890 : else if (node->sgprivate->tag == TAG_ProtoNode) gf_sg_proto_del_instance((GF_ProtoInstance *)node);
1894 : #endif
1895 : #ifndef GPAC_DISABLE_VRML
1896 75931 : else if (node->sgprivate->tag<=GF_NODE_RANGE_LAST_MPEG4) gf_sg_mpeg4_node_del(node);
1897 : #ifndef GPAC_DISABLE_X3D
1898 5581 : else if (node->sgprivate->tag <= GF_NODE_RANGE_LAST_X3D) gf_sg_x3d_node_del(node);
1899 : #endif
1900 : #endif /*GPAC_DISABLE_VRML*/
1901 :
1902 : #ifndef GPAC_DISABLE_SVG
1903 5179 : else if (node->sgprivate->tag <= GF_NODE_RANGE_LAST_SVG) gf_svg_node_del(node);
1904 : #endif
1905 0 : else gf_node_free(node);
1906 79750 : }
1907 :
1908 : GF_EXPORT
1909 30153 : u32 gf_node_get_field_count(GF_Node *node)
1910 : {
1911 : assert(node);
1912 30153 : if (node->sgprivate->tag <= TAG_UndefinedNode) return 0;
1913 : #ifndef GPAC_DISABLE_VRML
1914 : /*for both MPEG4 & X3D*/
1915 30153 : else if (node->sgprivate->tag <= GF_NODE_RANGE_LAST_X3D) return gf_node_get_num_fields_in_mode(node, GF_SG_FIELD_CODING_ALL);
1916 : #endif
1917 : #ifndef GPAC_DISABLE_SVG
1918 0 : else if (node->sgprivate->tag >= GF_NODE_FIRST_DOM_NODE_TAG) return gf_node_get_attribute_count(node);
1919 : #endif
1920 : return 0;
1921 : }
1922 :
1923 : GF_EXPORT
1924 8703 : const char *gf_node_get_class_name(GF_Node *node)
1925 : {
1926 : assert(node && node->sgprivate->tag);
1927 8703 : if (node->sgprivate->tag==TAG_UndefinedNode) return "UndefinedNode";
1928 : #ifndef GPAC_DISABLE_VRML
1929 8703 : else if (node->sgprivate->tag==TAG_ProtoNode) return ((GF_ProtoInstance*)node)->proto_name;
1930 8643 : else if (node->sgprivate->tag <= GF_NODE_RANGE_LAST_MPEG4) return gf_sg_mpeg4_node_get_class_name(node->sgprivate->tag);
1931 : #ifndef GPAC_DISABLE_X3D
1932 4765 : else if (node->sgprivate->tag <= GF_NODE_RANGE_LAST_X3D) return gf_sg_x3d_node_get_class_name(node->sgprivate->tag);
1933 : #endif
1934 : #endif
1935 4636 : else if (node->sgprivate->tag==TAG_DOMText) return "DOMText";
1936 4575 : else if (node->sgprivate->tag==TAG_DOMFullNode) {
1937 : char *xmlns;
1938 : GF_DOMFullNode*full = (GF_DOMFullNode*)node;
1939 349 : u32 ns = gf_sg_get_namespace_code(node->sgprivate->scenegraph, NULL);
1940 349 : if (ns == full->ns) return full->name;
1941 32 : xmlns = (char *) gf_sg_get_namespace_qname(node->sgprivate->scenegraph, full->ns);
1942 32 : if (!xmlns) return full->name;
1943 20 : sprintf(node->sgprivate->scenegraph->szNameBuffer, "%s:%s", xmlns, full->name);
1944 20 : return node->sgprivate->scenegraph->szNameBuffer;
1945 : }
1946 : #ifndef GPAC_DISABLE_SVG
1947 4226 : else return gf_xml_get_element_name(node);
1948 : #endif
1949 : return "UnsupportedNode";
1950 : }
1951 :
1952 : #if 0 //unused
1953 : u32 gf_sg_node_get_tag_by_class_name(const char *name, u32 ns)
1954 : {
1955 : u32 tag = TAG_UndefinedNode;
1956 :
1957 : /* TODO: handle name spaces */
1958 : #ifndef GPAC_DISABLE_VRML
1959 : tag = gf_node_mpeg4_type_by_class_name(name);
1960 : if (tag) return tag;
1961 :
1962 : #ifndef GPAC_DISABLE_X3D
1963 : tag = gf_node_x3d_type_by_class_name(name);
1964 : if (tag) return tag;
1965 : #endif
1966 :
1967 : #endif
1968 :
1969 : #ifndef GPAC_DISABLE_SVG
1970 : tag = gf_xml_get_element_tag(name, ns);
1971 : if (tag != TAG_UndefinedNode) return tag;
1972 : #endif
1973 :
1974 : return tag;
1975 : }
1976 : #endif
1977 :
1978 :
1979 : GF_EXPORT
1980 76995 : GF_Node *gf_node_new(GF_SceneGraph *inScene, u32 tag)
1981 : {
1982 : GF_Node *node;
1983 : // if (!inScene) return NULL;
1984 : /*cannot create proto this way*/
1985 76995 : if (tag==TAG_ProtoNode) return NULL;
1986 76995 : else if (tag==TAG_UndefinedNode) node = gf_sg_new_base_node();
1987 : #ifndef GPAC_DISABLE_VRML
1988 76381 : else if (tag <= GF_NODE_RANGE_LAST_MPEG4) node = gf_sg_mpeg4_node_new(tag);
1989 : #ifndef GPAC_DISABLE_X3D
1990 6031 : else if (tag <= GF_NODE_RANGE_LAST_X3D) node = gf_sg_x3d_node_new(tag);
1991 : #endif
1992 : #endif
1993 5629 : else if (tag == TAG_DOMText) {
1994 : GF_DOMText *n;
1995 162 : GF_SAFEALLOC(n, GF_DOMText);
1996 162 : if (!n) return NULL;
1997 : node = (GF_Node*)n;
1998 162 : gf_node_setup(node, TAG_DOMText);
1999 : }
2000 5467 : else if (tag == TAG_DOMFullNode) {
2001 : GF_DOMFullNode*n;
2002 288 : GF_SAFEALLOC(n, GF_DOMFullNode);
2003 288 : if (!n) return NULL;
2004 : node = (GF_Node*)n;
2005 288 : gf_node_setup(node, TAG_DOMFullNode);
2006 : }
2007 : #ifndef GPAC_DISABLE_SVG
2008 5179 : else if (tag <= GF_NODE_RANGE_LAST_SVG) node = (GF_Node *) gf_svg_create_node(tag);
2009 : #endif
2010 : else node = NULL;
2011 :
2012 76995 : if (node) node->sgprivate->scenegraph = inScene;
2013 :
2014 : /*script is inited as soon as created since fields are dynamically added*/
2015 : #ifndef GPAC_DISABLE_VRML
2016 76995 : switch (tag) {
2017 458 : case TAG_MPEG4_Script:
2018 : #ifndef GPAC_DISABLE_X3D
2019 : case TAG_X3D_Script:
2020 : #endif
2021 458 : gf_sg_script_init(node);
2022 458 : break;
2023 : }
2024 : #endif
2025 :
2026 : return node;
2027 : }
2028 :
2029 :
2030 : GF_EXPORT
2031 650058 : GF_Err gf_node_get_field(GF_Node *node, u32 FieldIndex, GF_FieldInfo *info)
2032 : {
2033 : assert(node);
2034 : assert(info);
2035 : memset(info, 0, sizeof(GF_FieldInfo));
2036 650058 : info->fieldIndex = FieldIndex;
2037 :
2038 650058 : if (node->sgprivate->tag==TAG_UndefinedNode) return GF_BAD_PARAM;
2039 : #ifndef GPAC_DISABLE_VRML
2040 650058 : else if (node->sgprivate->tag == TAG_ProtoNode) return gf_sg_proto_get_field(NULL, node, info);
2041 604023 : else if (node->sgprivate->tag == TAG_MPEG4_Script)
2042 19167 : return gf_sg_script_get_field(node, info);
2043 : #ifndef GPAC_DISABLE_X3D
2044 584856 : else if (node->sgprivate->tag == TAG_X3D_Script)
2045 200 : return gf_sg_script_get_field(node, info);
2046 : #endif
2047 584656 : else if (node->sgprivate->tag <= GF_NODE_RANGE_LAST_MPEG4) return gf_sg_mpeg4_node_get_field(node, info);
2048 : #ifndef GPAC_DISABLE_X3D
2049 2502 : else if (node->sgprivate->tag <= GF_NODE_RANGE_LAST_X3D) return gf_sg_x3d_node_get_field(node, info);
2050 : #endif
2051 : #endif /*GPAC_DISABLE_VRML*/
2052 :
2053 : #ifndef GPAC_DISABLE_SVG
2054 7 : else if (node->sgprivate->tag >= GF_NODE_FIRST_DOM_NODE_TAG) return gf_node_get_attribute_info(node, info);
2055 : #endif
2056 : return GF_NOT_SUPPORTED;
2057 : }
2058 :
2059 0 : u32 gf_node_get_num_instances(GF_Node *node)
2060 : {
2061 0 : return node ? node->sgprivate->num_instances : 0;
2062 : }
2063 :
2064 1071 : static GF_Err gf_node_get_field_by_name_enum(GF_Node *node, char *name, GF_FieldInfo *field)
2065 : {
2066 : u32 i, count;
2067 : assert(node);
2068 1071 : count = gf_node_get_field_count(node);
2069 : memset(field, 0, sizeof(GF_FieldInfo));
2070 9177 : for (i=0; i<count; i++) {
2071 8857 : gf_node_get_field(node, i, field);
2072 8857 : if (!strcmp(field->name, name)) return GF_OK;
2073 : }
2074 : return GF_BAD_PARAM;
2075 : }
2076 :
2077 : GF_EXPORT
2078 112957 : GF_Err gf_node_get_field_by_name(GF_Node *node, char *name, GF_FieldInfo *field)
2079 : {
2080 : s32 res = -1;
2081 :
2082 112957 : if (node->sgprivate->tag==TAG_UndefinedNode) return GF_BAD_PARAM;
2083 : #ifndef GPAC_DISABLE_VRML
2084 112957 : else if (node->sgprivate->tag == TAG_ProtoNode) {
2085 24847 : res = gf_sg_proto_get_field_index_by_name(NULL, node, name);
2086 : }
2087 88110 : else if (node->sgprivate->tag == TAG_MPEG4_Script)
2088 1043 : return gf_node_get_field_by_name_enum(node, name, field);
2089 : #ifndef GPAC_DISABLE_X3D
2090 87067 : else if (node->sgprivate->tag == TAG_X3D_Script)
2091 28 : return gf_node_get_field_by_name_enum(node, name, field);
2092 : #endif
2093 87039 : else if (node->sgprivate->tag <= GF_NODE_RANGE_LAST_MPEG4) res = gf_sg_mpeg4_node_get_field_index_by_name(node, name);
2094 : #ifndef GPAC_DISABLE_X3D
2095 1503 : else if (node->sgprivate->tag <= GF_NODE_RANGE_LAST_X3D) res = gf_sg_x3d_node_get_field_index_by_name(node, name);
2096 : #endif
2097 : #endif /*GPAC_DISABLE_VRML*/
2098 :
2099 : #ifndef GPAC_DISABLE_SVG
2100 55 : else if (node->sgprivate->tag >= GF_NODE_FIRST_DOM_NODE_TAG) return gf_node_get_attribute_by_name(node, name, 0, 1, 0, field);
2101 : #endif
2102 111831 : if (res==-1) return GF_BAD_PARAM;
2103 99941 : return gf_node_get_field(node, (u32) res, field);
2104 : }
2105 :
2106 :
2107 : static char log_node_name[2+16+1];
2108 0 : const char *gf_node_get_log_name(GF_Node *anim)
2109 : {
2110 : const char *name;
2111 0 : if (!anim) return "";
2112 0 : name = gf_node_get_name(anim);
2113 0 : if (name) return name;
2114 : else {
2115 : sprintf(log_node_name, "%p", anim);
2116 0 : return log_node_name;
2117 : }
2118 : }
2119 :
2120 :
2121 :
2122 2 : static GF_Err gf_node_deactivate_ex(GF_Node *node)
2123 : {
2124 : #ifdef GPAC_DISABLE_SVG
2125 : return GF_NOT_SUPPORTED;
2126 : #else
2127 : GF_ChildNodeItem *item;
2128 2 : if (node->sgprivate->tag<GF_NODE_FIRST_DOM_NODE_TAG) return GF_BAD_PARAM;
2129 1 : if (! (node->sgprivate->flags & GF_NODE_IS_DEACTIVATED)) {
2130 :
2131 1 : node->sgprivate->flags |= GF_NODE_IS_DEACTIVATED;
2132 :
2133 : /*deactivate anmiations*/
2134 1 : if (gf_svg_is_timing_tag(node->sgprivate->tag)) {
2135 : SVGTimedAnimBaseElement *timed = (SVGTimedAnimBaseElement*)node;
2136 0 : if (gf_list_del_item(node->sgprivate->scenegraph->smil_timed_elements, timed->timingp->runtime)>=0) {
2137 0 : if (timed->timingp->runtime->evaluate) {
2138 0 : timed->timingp->runtime->evaluate(timed->timingp->runtime, 0, SMIL_TIMING_EVAL_DEACTIVATE);
2139 : }
2140 : }
2141 : }
2142 : /*TODO unregister all listeners*/
2143 :
2144 : }
2145 : /*and deactivate children*/
2146 1 : item = ((GF_ParentNode*)node)->children;
2147 3 : while (item) {
2148 1 : gf_node_deactivate_ex(item->node);
2149 1 : item = item->next;
2150 : }
2151 : return GF_OK;
2152 : #endif
2153 : }
2154 :
2155 1 : GF_Err gf_node_deactivate(GF_Node *node)
2156 : {
2157 1 : GF_Err e = gf_node_deactivate_ex(node);
2158 1 : gf_node_changed(node, NULL);
2159 1 : return e;
2160 : }
2161 :
2162 161 : static u32 gf_node_activate_ex(GF_Node *node)
2163 : {
2164 : #ifdef GPAC_DISABLE_SVG
2165 : return 0;
2166 : #else
2167 : u32 ret = 0;
2168 : GF_ChildNodeItem *item;
2169 161 : if (node->sgprivate->tag<GF_NODE_FIRST_DOM_NODE_TAG) return 0;
2170 100 : if (node->sgprivate->flags & GF_NODE_IS_DEACTIVATED) {
2171 :
2172 1 : node->sgprivate->flags &= ~GF_NODE_IS_DEACTIVATED;
2173 : ret ++;
2174 :
2175 : /*deactivate anmiations*/
2176 1 : if (gf_svg_is_timing_tag(node->sgprivate->tag)) {
2177 : SVGTimedAnimBaseElement *timed = (SVGTimedAnimBaseElement*)node;
2178 0 : gf_list_add(node->sgprivate->scenegraph->smil_timed_elements, timed->timingp->runtime);
2179 0 : node->sgprivate->flags &= ~GF_NODE_IS_DEACTIVATED;
2180 0 : if (timed->timingp->runtime->evaluate) {
2181 0 : timed->timingp->runtime->evaluate(timed->timingp->runtime, 0, SMIL_TIMING_EVAL_ACTIVATE);
2182 : }
2183 : }
2184 : /*TODO register all listeners*/
2185 :
2186 : }
2187 : /*and deactivate children*/
2188 100 : item = ((GF_ParentNode*)node)->children;
2189 272 : while (item) {
2190 72 : ret += gf_node_activate_ex(item->node);
2191 72 : item = item->next;
2192 : }
2193 : return ret;
2194 : #endif
2195 : }
2196 :
2197 89 : GF_Err gf_node_activate(GF_Node *node)
2198 : {
2199 89 : if (!node) return GF_BAD_PARAM;
2200 89 : if (gf_node_activate_ex(node))
2201 1 : gf_node_changed(node, NULL);
2202 : return GF_OK;
2203 : }
2204 :
2205 : GF_EXPORT
2206 17242 : GF_Node *gf_node_clone(GF_SceneGraph *inScene, GF_Node *orig, GF_Node *cloned_parent, char *id, Bool deep)
2207 : {
2208 17242 : if (!orig) return NULL;
2209 13515 : if (orig->sgprivate->tag < GF_NODE_RANGE_LAST_VRML) {
2210 : #ifndef GPAC_DISABLE_VRML
2211 : /*deep clone is always true for VRML*/
2212 13514 : return gf_vrml_node_clone(inScene, orig, cloned_parent, id);
2213 : #endif
2214 1 : } else if (orig->sgprivate->tag == TAG_DOMUpdates) {
2215 : /*TODO*/
2216 : return NULL;
2217 : } else {
2218 : #ifndef GPAC_DISABLE_SVG
2219 1 : return gf_xml_node_clone(inScene, orig, cloned_parent, id, deep);
2220 : #endif
2221 : }
2222 : return NULL;
2223 : }
2224 :
2225 285 : GF_NamespaceType gf_xml_get_namespace_id(char *name)
2226 : {
2227 285 : if (!strcmp(name, "http://www.w3.org/XML/1998/namespace")) return GF_XMLNS_XML;
2228 285 : else if (!strcmp(name, "http://www.w3.org/2001/xml-events")) return GF_XMLNS_XMLEV;
2229 269 : else if (!strcmp(name, "http://www.w3.org/1999/xlink")) return GF_XMLNS_XLINK;
2230 204 : else if (!strcmp(name, "http://www.w3.org/2000/svg")) return GF_XMLNS_SVG;
2231 64 : else if (!strcmp(name, "urn:mpeg:mpeg4:LASeR:2005")) return GF_XMLNS_LASER;
2232 62 : else if (!strcmp(name, "http://www.w3.org/ns/xbl")) return GF_XMLNS_XBL;
2233 62 : else if (!strcmp(name, "http://gpac.io/svg-extensions")) return GF_XMLNS_SVG_GPAC_EXTENSION;
2234 62 : return GF_XMLNS_UNDEFINED;
2235 : }
2236 :
2237 : GF_EXPORT
2238 285 : GF_Err gf_sg_add_namespace(GF_SceneGraph *sg, char *name, char *qname)
2239 : {
2240 : u32 id;
2241 : GF_XMLNS *ns;
2242 285 : if (!name) return GF_BAD_PARAM;
2243 :
2244 285 : id = gf_xml_get_namespace_id(name);
2245 :
2246 285 : if (!sg->ns) sg->ns = gf_list_new();
2247 :
2248 285 : GF_SAFEALLOC(ns, GF_XMLNS);
2249 285 : if (!ns) return GF_OUT_OF_MEM;
2250 :
2251 285 : ns->xmlns_id = id ? id : gf_crc_32(name, (u32) strlen(name));
2252 285 : ns->name = gf_strdup(name);
2253 :
2254 285 : ns->qname = qname ? gf_strdup(qname) : NULL;
2255 285 : return gf_list_insert(sg->ns, ns, 0);
2256 : }
2257 :
2258 198 : GF_Err gf_sg_remove_namespace(GF_SceneGraph *sg, char *ns_name, char *q_name)
2259 : {
2260 : u32 i, count;
2261 198 : if (!ns_name) return GF_OK;
2262 198 : count = sg->ns ? gf_list_count(sg->ns) : 0;
2263 308 : for (i=0; i<count; i++) {
2264 : Bool ok=0;
2265 308 : GF_XMLNS *ns = gf_list_get(sg->ns, i);
2266 308 : if (!q_name && !ns->qname)
2267 : ok = 1;
2268 208 : else if (q_name && ns->qname && !strcmp(ns->qname, q_name) )
2269 : ok = 1;
2270 :
2271 198 : if (ok && ns->name && !strcmp(ns->name, ns_name)) {
2272 198 : gf_list_rem(sg->ns, i);
2273 198 : gf_free(ns->name);
2274 198 : if (ns->qname) gf_free(ns->qname);
2275 198 : gf_free(ns);
2276 198 : return GF_OK;
2277 : }
2278 : }
2279 : return GF_OK;
2280 : }
2281 :
2282 5152 : GF_NamespaceType gf_sg_get_namespace_code(GF_SceneGraph *sg, char *qname)
2283 : {
2284 : u32 i, count;
2285 5152 : count = sg->ns ? gf_list_count(sg->ns) : 0;
2286 8336 : for (i=0; i<count; i++) {
2287 7372 : GF_XMLNS *ns = gf_list_get(sg->ns, i);
2288 7372 : if (!ns->qname && !qname)
2289 3853 : return ns->xmlns_id;
2290 :
2291 3519 : if (ns->qname && qname && !strcmp(ns->qname, qname))
2292 335 : return ns->xmlns_id;
2293 : }
2294 964 : if (qname) {
2295 240 : if (!strcmp(qname, "xml")) return GF_XMLNS_XML;
2296 : /*we could also add the basic namespaces in case this has been forgotten ?*/
2297 : }
2298 724 : return GF_XMLNS_UNDEFINED;
2299 : }
2300 :
2301 102 : GF_NamespaceType gf_sg_get_namespace_code_from_name(GF_SceneGraph *sg, char *name)
2302 : {
2303 : u32 i, count;
2304 102 : count = sg->ns ? gf_list_count(sg->ns) : 0;
2305 102 : for (i=0; i<count; i++) {
2306 102 : GF_XMLNS *ns = gf_list_get(sg->ns, i);
2307 102 : if (ns->name && name && !strcmp(ns->name, name))
2308 102 : return ns->xmlns_id;
2309 0 : if (!ns->name && !name)
2310 0 : return ns->xmlns_id;
2311 : }
2312 : return GF_XMLNS_UNDEFINED;
2313 : }
2314 :
2315 1410 : const char *gf_sg_get_namespace_qname(GF_SceneGraph *sg, GF_NamespaceType xmlns_id)
2316 : {
2317 : u32 i, count;
2318 1410 : count = sg->ns ? gf_list_count(sg->ns) : 0;
2319 2272 : for (i=0; i<count; i++) {
2320 1575 : GF_XMLNS *ns = gf_list_get(sg->ns, i);
2321 1575 : if (ns->xmlns_id == xmlns_id)
2322 713 : return ns->qname;
2323 : }
2324 697 : if (xmlns_id==GF_XMLNS_XML) return "xml";
2325 697 : return NULL;
2326 : }
2327 :
2328 :
2329 1 : const char *gf_sg_get_namespace(GF_SceneGraph *sg, GF_NamespaceType xmlns_id)
2330 : {
2331 : u32 i, count;
2332 1 : if (!sg) return NULL;
2333 1 : count = sg->ns ? gf_list_count(sg->ns) : 0;
2334 1 : for (i=0; i<count; i++) {
2335 0 : GF_XMLNS *ns = gf_list_get(sg->ns, i);
2336 0 : if (ns->xmlns_id == xmlns_id)
2337 0 : return ns->name;
2338 : }
2339 : return NULL;
2340 : }
2341 :
2342 :
2343 : #if 0 //unused
2344 : char *gf_node_dump_attribute(GF_Node *n, GF_FieldInfo *info)
2345 : {
2346 : #ifndef GPAC_DISABLE_SVG
2347 : if (gf_node_get_tag(n) >= GF_NODE_FIRST_DOM_NODE_TAG) {
2348 : return gf_svg_dump_attribute(n, info);
2349 : }
2350 : #endif
2351 :
2352 : #ifndef GPAC_DISABLE_VRML
2353 : return gf_node_vrml_dump_attribute(n, info);
2354 : #else
2355 : return NULL;
2356 : #endif
2357 : }
2358 : #endif
2359 :
2360 :
2361 : /*this is not a NodeReplace, thus only the given container is updated - pos is 0-based*/
2362 : GF_EXPORT
2363 970 : GF_Err gf_node_replace_child(GF_Node *node, GF_ChildNodeItem **container, s32 pos, GF_Node *newNode)
2364 : {
2365 : GF_ChildNodeItem *child, *prev;
2366 : u32 tag;
2367 : u32 cur_pos = 0;
2368 :
2369 970 : child = *container;
2370 : prev = NULL;
2371 13336 : while (child->next) {
2372 12347 : if ((pos<0) || (cur_pos!=(u32)pos)) {
2373 : prev = child;
2374 : child = child->next;
2375 11396 : cur_pos++;
2376 11396 : continue;
2377 : }
2378 : break;
2379 : }
2380 970 : tag = child->node->sgprivate->tag;
2381 970 : gf_node_unregister(child->node, node);
2382 970 : if (newNode) {
2383 945 : child->node = newNode;
2384 : #ifndef GPAC_DISABLE_VRML
2385 945 : if (tag==TAG_MPEG4_ColorTransform)
2386 0 : node->sgprivate->flags |= GF_SG_VRML_COLOR_DIRTY;
2387 : #endif
2388 : } else {
2389 25 : if (prev) prev->next = child->next;
2390 25 : else *container = child->next;
2391 25 : gf_free(child);
2392 : }
2393 970 : return GF_OK;
2394 : }
2395 :
2396 :
2397 : GF_EXPORT
2398 2807 : Bool gf_node_parent_of(GF_Node *node, GF_Node *target)
2399 : {
2400 : u32 i, count;
2401 : GF_FieldInfo info;
2402 2807 : if (!node) return 0;
2403 0 : if (node==target) return 1;
2404 :
2405 0 : if (node->sgprivate->tag>=GF_NODE_RANGE_LAST_VRML) {
2406 0 : GF_ChildNodeItem *child = ((GF_ParentNode*)node)->children;
2407 0 : while (child) {
2408 0 : if (gf_node_parent_of(child->node, target)) return 1;
2409 0 : child = child->next;
2410 : }
2411 : } else {
2412 0 : count = gf_node_get_field_count(node);
2413 0 : for (i=0; i<count; i++) {
2414 0 : gf_node_get_field(node, i, &info);
2415 0 : if (info.fieldType==GF_SG_VRML_SFNODE) {
2416 0 : if (gf_node_parent_of(*(GF_Node **)info.far_ptr, target)) return 1;
2417 : }
2418 0 : else if (info.fieldType==GF_SG_VRML_MFNODE) {
2419 0 : GF_ChildNodeItem *list = *(GF_ChildNodeItem **) info.far_ptr;
2420 0 : while (list) {
2421 0 : if (gf_node_parent_of(list->node, target)) return 1;
2422 0 : list = list->next;
2423 : }
2424 : }
2425 : }
2426 : }
2427 : return 0;
2428 : }
2429 :
2430 2 : GF_SceneGraph *gf_sg_get_parent(GF_SceneGraph *scene)
2431 : {
2432 2 : return scene ? scene->parent_scene : NULL;
2433 : }
2434 :
2435 :
2436 : #include <gpac/xml.h>
2437 :
2438 266 : static GF_Err gf_sg_load_dom_node(GF_SceneGraph *document, GF_XMLNode *n, GF_DOMFullNode *par)
2439 : {
2440 : u32 i, count;
2441 : GF_DOMFullAttribute *prev = NULL;
2442 : GF_DOMFullNode *node;
2443 :
2444 266 : if (!n) return GF_OK;
2445 266 : if (!par && document->RootNode) {
2446 : return GF_NON_COMPLIANT_BITSTREAM;
2447 : }
2448 : /*construct text / cdata node*/
2449 266 : if (n->type != GF_XML_NODE_TYPE) {
2450 : u32 len;
2451 : GF_DOMText *txt;
2452 : /*basic check, remove all empty text nodes*/
2453 166 : len = (u32) strlen(n->name);
2454 840 : for (i=0; i<len; i++) {
2455 701 : if (!strchr(" \n\r\t", n->name[i])) break;
2456 : }
2457 166 : if (i==len) return GF_OK;
2458 27 : txt = gf_dom_add_text_node((GF_Node *)par, gf_strdup(n->name) );
2459 27 : txt->type = (n->type==GF_XML_CDATA_TYPE) ? GF_DOM_TEXT_CDATA : GF_DOM_TEXT_REGULAR;
2460 27 : return GF_OK;
2461 : }
2462 : /*construct DOM node*/
2463 100 : node = (GF_DOMFullNode *) gf_node_new(document, TAG_DOMFullNode);
2464 100 : node->name = gf_strdup(n->name);
2465 100 : if (n->ns)
2466 0 : node->ns = gf_sg_get_namespace_code(document, n->ns);
2467 :
2468 100 : count = gf_list_count(n->attributes);
2469 378 : for (i=0; i<count; i++) {
2470 278 : GF_XMLAttribute *src_att = gf_list_get(n->attributes, i);
2471 : /* special case for 'xml:id' to be parsed as an ID
2472 : NOTE: we do not test for the 'id' attribute because without DTD we are not sure that it's an ID */
2473 278 : if (!stricmp(src_att->name, "xml:id")) {
2474 17 : u32 id = gf_sg_get_max_node_id(document) + 1;
2475 17 : gf_node_set_id((GF_Node *)node, id, src_att->value);
2476 : } else {
2477 : GF_DOMFullAttribute *att;
2478 261 : GF_SAFEALLOC(att, GF_DOMFullAttribute);
2479 261 : if (!att) {
2480 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[XHR] Fail to allocate DOM attribute\n"));
2481 0 : continue;
2482 : }
2483 261 : att->tag = TAG_DOM_ATT_any;
2484 261 : att->name = gf_strdup(src_att->name);
2485 261 : att->data_type = (u16) DOM_String_datatype;
2486 261 : att->data = gf_svg_create_attribute_value(att->data_type);
2487 261 : *((char **)att->data) = gf_strdup(src_att->value);
2488 261 : if (prev) prev->next = (GF_DOMAttribute*)att;
2489 64 : else node->attributes = (GF_DOMAttribute*)att;
2490 : prev = att;
2491 : }
2492 : }
2493 100 : gf_node_register((GF_Node*)node, (GF_Node*)par);
2494 100 : if (par) {
2495 92 : gf_node_list_add_child(&par->children, (GF_Node*)node);
2496 : } else {
2497 8 : document->RootNode = (GF_Node*)node;
2498 : }
2499 100 : count = gf_list_count(n->content);
2500 358 : for (i=0; i<count; i++) {
2501 258 : GF_XMLNode *child = gf_list_get(n->content, i);
2502 258 : GF_Err e = gf_sg_load_dom_node(document, child, node);
2503 258 : if (e) return e;
2504 : }
2505 : return GF_OK;
2506 : }
2507 :
2508 8 : GF_Err gf_sg_init_from_xml_node(GF_SceneGraph *document, GF_DOMXMLNODE root_node)
2509 : {
2510 8 : return gf_sg_load_dom_node(document, root_node, NULL);
2511 : }
2512 :
|