1 /*
2 * GPAC - Multimedia Framework C SDK
3 *
4 * Authors: Jean Le Feuvre
5 * Copyright (c) Telecom ParisTech 2005-2019
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
28 #ifndef GPAC_DISABLE_SVG
29 #include <gpac/events.h>
30 #include <gpac/nodes_svg.h>
31
32
33 #ifdef GPAC_HAS_QJS
34
35 #ifdef GPAC_CONFIG_ANDROID
36 #ifndef XP_UNIX
37 #define XP_UNIX
38 #endif
39 #endif
40
41 #include "qjs_common.h"
42
43 #define JSVAL_CHECK_STRING(_v) (JS_IsString(_v) || JS_IsNull(_v))
44
45
46 /*SVG uDOM classes*/
47 GF_JSClass svgElement;
48 GF_JSClass svgDocument;
49 GF_JSClass svg_globalClass;
50 GF_JSClass connectionClass;
51 GF_JSClass rgbClass;
52 GF_JSClass rectClass;
53 GF_JSClass pointClass;
54 GF_JSClass pathClass;
55 GF_JSClass matrixClass;
56
57 typedef struct
58 {
59 JSValue proto;
60 JSValue ctor;
61 } SVG_JSClass;
62
63
64 typedef struct __tag_svg_script_ctx
65 {
66 Bool (*script_execute)(struct __tag_scene_graph *sg, char *utf8_script, GF_DOM_Event *event);
67 Bool (*handler_execute)(GF_Node *n, GF_DOM_Event *event, GF_Node *observer, char *utf8_script);
68 u32 nb_scripts;
69 /*global script context for the scene*/
70 JSContext *js_ctx;
71 /*global object*/
72 JSValue global;
73 /*global event object - used to update the associated DOMEvent (JS private stack) when dispatching events*/
74 JSValue event;
75
76 Bool in_script;
77 Bool force_gc;
78 Bool use_strict;
79
80 /*SVG uDOM classes*/
81 SVG_JSClass svgElement;
82 SVG_JSClass svgDocument;
83 SVG_JSClass svg_globalClass;
84 SVG_JSClass connectionClass;
85 SVG_JSClass rgbClass;
86 SVG_JSClass rectClass;
87 SVG_JSClass pointClass;
88 SVG_JSClass pathClass;
89 SVG_JSClass matrixClass;
90 } GF_SVGJS;
91
svg_mark_gc(struct __tag_svg_script_ctx * svg_js)92 void svg_mark_gc(struct __tag_svg_script_ctx *svg_js)
93 {
94 if (svg_js)
95 svg_js->force_gc = 1;
96 }
97
svg_free_node_binding(struct __tag_svg_script_ctx * svg_js,GF_Node * node)98 void svg_free_node_binding(struct __tag_svg_script_ctx *svg_js, GF_Node *node)
99 {
100 struct _node_js_binding *js_binding = node->sgprivate->interact->js_binding;
101 if (!JS_IsUndefined(js_binding->obj)) {
102 JS_SetOpaque(js_binding->obj, NULL);
103 JS_FreeValue(svg_js->js_ctx, js_binding->obj);
104 js_binding->obj = JS_UNDEFINED;
105 //unregister after destroying JS obj since this is a recursive call and we trigger the GC, we must make sure
106 //all JS opaque is NULL before destroying the node
107 gf_node_unregister(node, NULL);
108 }
109
110 if (svg_js->in_script)
111 svg_js->force_gc = 1;
112 else
113 gf_js_call_gc(svg_js->js_ctx);
114 }
115
svg_exec_script(struct __tag_svg_script_ctx * svg_js,GF_SceneGraph * sg,const char * com)116 GF_Err svg_exec_script(struct __tag_svg_script_ctx *svg_js, GF_SceneGraph *sg, const char *com)
117 {
118 Bool ret = sg->svg_js->script_execute(sg, (char *)com, NULL);
119 return (ret == GF_TRUE ? GF_OK : GF_BAD_PARAM);
120 }
121
svgjs_handler_execute(struct __tag_svg_script_ctx * svg_js,GF_Node * hdl,GF_DOM_Event * event,GF_Node * observer,const char * iri)122 void svgjs_handler_execute(struct __tag_svg_script_ctx *svg_js, GF_Node *hdl, GF_DOM_Event *event, GF_Node *observer, const char *iri)
123 {
124 if (svg_js->handler_execute(hdl, event, observer, (char *) iri)) {
125 return;
126 } else {
127 GF_LOG(GF_LOG_WARNING, GF_LOG_INTERACT, ("[DOM Events] Error executing JavaScript event handler\n"));
128 return;
129 }
130 }
131 static Bool svg_script_execute_handler(GF_Node *node, GF_DOM_Event *event, GF_Node *observer, char *utf8_script);
132
133 void dom_node_set_textContent(GF_Node *n, char *text);
134
135 JSValue dom_node_get_sibling(JSContext *c, GF_Node *n, Bool is_prev, Bool elt_only);
136
137 #ifdef GPAC_ENABLE_HTML5_MEDIA
138 void html_media_init_js_api(GF_SceneGraph *scene);
139 #endif
140
141 #define _ScriptMessage(_sg, _msg) {\
142 GF_JSAPIParam par; \
143 par.info.e = GF_SCRIPT_INFO; \
144 par.info.msg = _msg; \
145 _sg->script_action(_sg->script_action_cbck, GF_JSAPI_OP_MESSAGE, NULL, &par);\
146 }
147
ScriptAction(GF_SceneGraph * scene,u32 type,GF_Node * node,GF_JSAPIParam * param)148 static GFINLINE Bool ScriptAction(GF_SceneGraph *scene, u32 type, GF_Node *node, GF_JSAPIParam *param)
149 {
150 if (scene->script_action)
151 return scene->script_action(scene->script_action_cbck, type, node, param);
152 return GF_FALSE;
153 }
154
155 static JSValue svg_new_path_object(JSContext *c, SVG_PathData *d);
156
157
158
159 /*note we are using float to avoid conversions fixed to/from JS native */
160 typedef struct
161 {
162 u32 r, g, b;
163 } rgbCI;
164
165
166 typedef struct
167 {
168 Float x, y, w, h;
169 /*if set, this is the svg.viewport uDOM object, its values are updated upon query*/
170 GF_SceneGraph *sg;
171 } rectCI;
172
173 typedef struct
174 {
175 Float x, y;
176 /*if set, this is the svg.currentTranslate uDOM object, its values are updated upon query*/
177 GF_SceneGraph *sg;
178 } pointCI;
179
180 typedef struct
181 {
182 Float x, y;
183 } ptCI;
184
185 typedef struct
186 {
187 u32 nb_coms;
188 u8 *tags;
189 ptCI *pts;
190 } pathCI;
191
svg_nav_to_location(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)192 static JSValue svg_nav_to_location(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
193 {
194 GF_JSAPIParam par;
195 GF_SceneGraph *sg = JS_GetOpaque(obj, svg_globalClass.class_id);
196 if ((argc!=1) || !sg)
197 return JS_EXCEPTION;
198
199 par.uri.url = (char *) JS_ToCString(c, argv[0]);
200 par.uri.nb_params = 0;
201 ScriptAction(sg, GF_JSAPI_OP_LOAD_URL, sg->RootNode, &par);
202 JS_FreeCString(c, par.uri.url);
203 return JS_UNDEFINED;
204 }
205
206 GF_Node *gf_sm_load_svg_from_string(GF_SceneGraph *sg, char *svg_str);
svg_parse_xml(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)207 static JSValue svg_parse_xml(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
208 {
209 GF_SceneGraph *sg;
210 GF_Node *node;
211 const char *str;
212
213 if (!JS_IsObject(argv[1])) {
214 return js_throw_err(c, GF_DOM_EXC_WRONG_DOCUMENT_ERR);
215 }
216
217 str = JS_ToCString(c, argv[0]);
218 if (!str) return JS_TRUE;
219 sg = dom_get_doc(c, argv[1]);
220
221 node = gf_sm_load_svg_from_string(sg, (char *) str);
222 JS_FreeCString(c, str);
223 return dom_element_construct(c, node);
224 }
225
svg_define_udom_exception(JSContext * c,JSValue global)226 static void svg_define_udom_exception(JSContext *c, JSValue global)
227 {
228 JSValue obj = JS_NewObject(c);
229 JS_SetPropertyStr(c, global, "GlobalException", obj);
230 #define DEFCONST(_name, _code)\
231 JS_SetPropertyStr(c, obj, _name, JS_NewInt32(c, _code));
232
233 DEFCONST("NOT_CONNECTED_ERR", 1)
234 DEFCONST("ENCODING_ERR", 2)
235 DEFCONST("DENIED_ERR", 3)
236 DEFCONST("UNKNOWN_ERR", 4)
237
238 obj = JS_NewObject(c);
239 JS_SetPropertyStr(c, global, "SVGException", obj);
240 DEFCONST("SVG_WRONG_TYPE_ERR", 0)
241 DEFCONST("SVG_INVALID_VALUE_ERR", 1)
242 DEFCONST("SVG_MATRIX_NOT_INVERTABLE", 2)
243
244 obj = JS_NewObject(c);
245 JS_SetPropertyStr(c, global, "SVGSVGElement", obj);
246 DEFCONST("NAV_AUTO", 1)
247 DEFCONST("NAV_NEXT", 2)
248 DEFCONST("NAV_PREV", 3)
249 DEFCONST("NAV_UP", 4)
250 DEFCONST("NAV_UP_RIGHT", 5)
251 DEFCONST("NAV_RIGHT", 6)
252 DEFCONST("NAV_DOWN_RIGHT", 7)
253 DEFCONST("NAV_DOWN", 8)
254 DEFCONST("NAV_DOWN_LEFT", 9)
255 DEFCONST("NAV_LEFT", 10)
256 DEFCONST("NAV_UP_LEFT", 11)
257 }
258
global_getProperty(JSContext * c,JSValueConst obj,int magic)259 static JSValue global_getProperty(JSContext *c, JSValueConst obj, int magic)
260 {
261 GF_SceneGraph *sg = JS_GetOpaque(obj, svg_globalClass.class_id);
262 if (!sg) return JS_EXCEPTION;
263
264 switch (magic) {
265 /*namespaceURI*/
266 case 0:
267 return JS_NULL;
268 /*parent*/
269 case 1:
270 if (sg->parent_scene && sg->parent_scene->svg_js)
271 return JS_DupValue(c, sg->parent_scene->svg_js->global);
272 return JS_NULL;
273 default:
274 return JS_UNDEFINED;
275 }
276 }
277
278 /*TODO - try to be more precise...*/
dom_imp_has_feature(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)279 static JSValue dom_imp_has_feature(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
280 {
281 JSValue ret = JS_FALSE;
282
283 if (argc) {
284 u32 len;
285 char sep;
286 char *fname = (char *) JS_ToCString(c, argv[0]);
287 if (!fname) return JS_TRUE;
288 while (strchr(" \t\n\r", fname[0])) fname++;
289 len = (u32) strlen(fname);
290 while (len && strchr(" \t\n\r", fname[len-1])) len--;
291 sep = fname[len];
292 fname[len] = 0;
293 if (!stricmp(fname, "xml")) ret = JS_TRUE;
294 else if (!stricmp(fname, "core")) ret = JS_TRUE;
295 else if (!stricmp(fname, "traversal")) ret = JS_TRUE;
296 else if (!stricmp(fname, "uievents")) ret = JS_TRUE;
297 else if (!stricmp(fname, "mouseevents")) ret = JS_TRUE;
298 else if (!stricmp(fname, "mutationevents")) ret = JS_TRUE;
299 else if (!stricmp(fname, "events")) ret = JS_TRUE;
300
301 fname[len] = sep;
302 JS_FreeCString(c, fname);
303 }
304 return ret;
305 }
306
get_corresponding_use(GF_Node * n)307 static GF_Node *get_corresponding_use(GF_Node *n)
308 {
309 u32 i, count;
310 if (!n || !n->sgprivate->scenegraph->use_stack) return NULL;
311
312 /*find current node in the use stack - if found, return the use element*/
313 count = gf_list_count(n->sgprivate->scenegraph->use_stack);
314 for (i=count; i>0; i-=2) {
315 GF_Node *t = (GF_Node *)gf_list_get(n->sgprivate->scenegraph->use_stack, i-2);
316 if (t==n) {
317 GF_Node *use = (GF_Node *)gf_list_get(n->sgprivate->scenegraph->use_stack, i-1);
318 GF_Node *par_use = get_corresponding_use(use);
319 return par_use ? par_use : use;
320 }
321 }
322 /*otherwise recursively get up the tree*/
323 return get_corresponding_use(gf_node_get_parent(n, 0));
324 }
325
svg_doc_getProperty(JSContext * c,JSValueConst obj,int magic)326 static JSValue svg_doc_getProperty(JSContext *c, JSValueConst obj, int magic)
327 {
328 GF_SceneGraph *sg = dom_get_doc(c, obj);
329 if (!sg) return JS_EXCEPTION;
330 switch (magic) {
331 case 0:/*global*/
332 return JS_GetGlobalObject(c);
333 }
334 return JS_UNDEFINED;
335 }
336
svg_element_getProperty(JSContext * c,JSValueConst obj,int magic)337 static JSValue svg_element_getProperty(JSContext *c, JSValueConst obj, int magic)
338 {
339 GF_JSAPIParam par;
340 GF_Node *n = dom_get_element(c, obj);
341 if (!n) return JS_TRUE;
342
343 switch (magic) {
344 case 0: /*id*/
345 {
346 const char *node_name = gf_node_get_name((GF_Node*)n);
347 if (node_name) {
348 return JS_NewString(c, node_name);
349 }
350 return JS_NULL;
351 }
352 case 5:/*currentScale*/
353 if (n->sgprivate->tag!=TAG_SVG_svg) return JS_EXCEPTION;
354 if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_GET_SCALE, (GF_Node *)n, &par)) {
355 return JS_NewFloat64(c, FIX2FLT(par.val) );
356 }
357 return JS_EXCEPTION;
358 case 6:/*currentRotate*/
359 if (n->sgprivate->tag!=TAG_SVG_svg) return JS_EXCEPTION;
360 if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_GET_ROTATION, (GF_Node *)n, &par)) {
361 return JS_NewFloat64(c, FIX2FLT(par.val) );
362 }
363 return JS_EXCEPTION;
364 case 7:/*currentTranslate*/
365 if (n->sgprivate->tag!=TAG_SVG_svg) return JS_EXCEPTION;
366 if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_GET_TRANSLATE, (GF_Node *)n, &par)) {
367 JSValue r = JS_NewObjectClass(c, pointClass.class_id);
368 pointCI *rc = (pointCI *)gf_malloc(sizeof(pointCI));
369 rc->x = FIX2FLT(par.pt.x);
370 rc->y = FIX2FLT(par.pt.y);
371 rc->sg = n->sgprivate->scenegraph;
372 JS_SetOpaque(r, rc);
373 return r;
374 }
375 return JS_EXCEPTION;
376 case 8:/*viewport*/
377 if (n->sgprivate->tag!=TAG_SVG_svg) return JS_EXCEPTION;
378 if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_GET_VIEWPORT, (GF_Node *)n, &par)) {
379 JSValue r = JS_NewObjectClass(c, rectClass.class_id);
380 rectCI *rc = (rectCI *)gf_malloc(sizeof(rectCI));
381 rc->x = FIX2FLT(par.rc.x);
382 rc->y = FIX2FLT(par.rc.y);
383 rc->w = FIX2FLT(par.rc.width);
384 rc->h = FIX2FLT(par.rc.height);
385 rc->sg = n->sgprivate->scenegraph;
386 JS_SetOpaque(r, rc);
387 return r;
388 }
389 return JS_EXCEPTION;
390 case 9:/*currentTime*/
391 return JS_NewFloat64(c, gf_node_get_scene_time((GF_Node *)n) );
392 case 10:/*isPaused*/
393 return JS_FALSE;
394 case 11:/*ownerSVGElement*/
395 while (1) {
396 GF_Node *n_par = gf_node_get_parent(n, 0);
397 if (!n_par) return JS_TRUE;
398 if (n_par->sgprivate->tag==TAG_SVG_svg) {
399 return dom_element_construct(c, n_par);
400 }
401 n = n_par;
402 }
403 return JS_NULL;
404 case 12:/*correspondingElement*/
405 /*if we can find a corresponding element for this node, then this is an SVGElementInstance*/
406 if (get_corresponding_use(n)) {
407 return dom_element_construct(c, n);
408 } else {
409 return dom_element_construct(c, NULL);
410 }
411 break;
412 case 13:/*correspondingUseElement*/
413 return dom_element_construct(c, get_corresponding_use(n));
414 default:
415 break;
416 }
417 return JS_UNDEFINED;
418 }
419
svg_element_setProperty(JSContext * c,JSValueConst obj,JSValueConst value,int magic)420 static JSValue svg_element_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
421 {
422 GF_JSAPIParam par;
423 Double d;
424 GF_Node *n = dom_get_element(c, obj);
425 if (!n) return JS_EXCEPTION;
426
427 switch (magic) {
428 case 0:/*id*/
429 if (JSVAL_CHECK_STRING(value)) {
430 const char *id = JS_ToCString(c, value);
431 if (id) {
432 GF_FieldInfo info;
433 u32 nid = gf_node_get_id(n);
434 if (!nid) nid = gf_sg_get_next_available_node_id(n->sgprivate->scenegraph);
435 gf_node_set_id(n, nid, id);
436 if (gf_node_get_attribute_by_tag(n, TAG_XML_ATT_id, GF_TRUE, GF_FALSE, &info)==GF_OK) {
437 if (*(DOM_String *)info.far_ptr) gf_free(*(DOM_String *)info.far_ptr);
438 *(DOM_String *)info.far_ptr = gf_strdup(id);
439 }
440 if (gf_node_get_attribute_by_tag(n, TAG_SVG_ATT_id, GF_TRUE, GF_FALSE, &info)==GF_OK) {
441 if (*(DOM_String *)info.far_ptr) gf_free(*(DOM_String *)info.far_ptr);
442 *(DOM_String *)info.far_ptr = gf_strdup(id);
443 }
444 JS_FreeCString(c, id);
445 }
446 }
447 return JS_TRUE;
448 /*currentScale*/
449 case 5:
450 if ((n->sgprivate->tag!=TAG_SVG_svg) || JS_ToFloat64(c, &d, value))
451 return JS_EXCEPTION;
452
453 par.val = FLT2FIX(d);
454 if (!par.val) {
455 return js_throw_err(c, GF_DOM_EXC_INVALID_ACCESS_ERR);
456 }
457 if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_SET_SCALE, (GF_Node *)n, &par)) {
458 return JS_TRUE;
459 }
460 return JS_FALSE;
461 /*currentRotate*/
462 case 6:
463 if ((n->sgprivate->tag!=TAG_SVG_svg) || JS_ToFloat64(c, &d, value))
464 return JS_EXCEPTION;
465
466 par.val = FLT2FIX(d);
467 if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_SET_ROTATION, (GF_Node *)n, &par)) {
468 return JS_TRUE;
469 }
470 return JS_FALSE;
471 /*currentTime*/
472 case 9:
473 if ((n->sgprivate->tag!=TAG_SVG_svg) || JS_ToFloat64(c, &d, value))
474 return JS_EXCEPTION;
475
476 par.time = d;
477 if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_SET_TIME, (GF_Node *)n, &par)) {
478 return JS_TRUE;
479 }
480 return JS_FALSE;
481 default:
482 break;
483 }
484 return JS_UNDEFINED;
485 }
486
svg_udom_smil_check_instance(JSContext * c,JSValue obj)487 static GF_Node *svg_udom_smil_check_instance(JSContext *c, JSValue obj)
488 {
489 GF_Node *n = dom_get_element(c, obj);
490 if (!n) return NULL;
491 switch (n->sgprivate->tag) {
492 case TAG_SVG_animate:
493 case TAG_SVG_animateColor:
494 case TAG_SVG_animateMotion:
495 case TAG_SVG_animateTransform:
496 case TAG_SVG_animation:
497 case TAG_SVG_audio:
498 case TAG_SVG_video:
499 case TAG_SVG_set:
500 case TAG_LSR_updates:
501 /*not sure about this one...*/
502 case TAG_SVG_discard:
503 return n;
504 }
505 return NULL;
506 }
507
508
509 /*TODO*/
svg_udom_smil_time_insert(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv,Bool is_end)510 static JSValue svg_udom_smil_time_insert(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool is_end)
511 {
512 GF_FieldInfo info;
513 u32 i, count;
514 Double offset;
515 GF_List *times;
516 SMIL_Time *newtime;
517
518 GF_Node *n = svg_udom_smil_check_instance(c, obj);
519 if (!n) return JS_UNDEFINED;
520
521 if (is_end) {
522 info.far_ptr = ((SVGTimedAnimBaseElement *)n)->timingp->end;
523 } else {
524 info.far_ptr = ((SVGTimedAnimBaseElement *)n)->timingp->begin;
525 }
526 if (!info.far_ptr) {
527 return JS_EXCEPTION;
528 }
529 times = *((GF_List **)info.far_ptr);
530 GF_SAFEALLOC(newtime, SMIL_Time);
531 if (!newtime) {
532 return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
533 }
534 newtime->type = GF_SMIL_TIME_EVENT_RESOLVED;
535
536 offset = 0;
537 if (argc)
538 JS_ToFloat64(c, &offset, argv[0]);
539
540 newtime->clock = gf_node_get_scene_time(n) + offset;
541
542 /*insert in sorted order*/
543 count = gf_list_count(times);
544 for (i=0; i<count; i++) {
545 SMIL_Time*t = (SMIL_Time*)gf_list_get(times, i);
546 if ( GF_SMIL_TIME_IS_CLOCK(t->type) ) {
547 if (t->clock > newtime->clock) break;
548 } else {
549 break;
550 }
551 }
552 gf_list_insert(times, newtime, i);
553
554 info.fieldType = SMIL_Times_datatype;
555 gf_node_changed(n, &info);
556 return JS_TRUE;
557 }
558
svg_udom_smil_begin(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)559 static JSValue svg_udom_smil_begin(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
560 {
561 return svg_udom_smil_time_insert(c, obj, argc, argv, GF_FALSE);
562 }
svg_udom_smil_end(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)563 static JSValue svg_udom_smil_end(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
564 {
565 return svg_udom_smil_time_insert(c, obj, argc, argv, GF_TRUE);
566 }
567
568 /*TODO*/
svg_udom_smil_pause(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)569 static JSValue svg_udom_smil_pause(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
570 {
571 u32 tag;
572 GF_Node *n = dom_get_element(c, obj);
573 if (!n) return JS_EXCEPTION;
574
575 tag = gf_node_get_tag(n);
576 if (gf_svg_is_animation_tag(tag)) {
577 /* pausing an animation element (set, animate ...) should pause the main time line ? */
578 gf_smil_timing_pause(n);
579 } else if (gf_svg_is_timing_tag(tag)) {
580 ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_PAUSE_SVG, n, NULL);
581 } else if ((tag==TAG_SVG_svg) && (n->sgprivate->scenegraph->RootNode==n)) {
582 ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_PAUSE_SVG, n, NULL);
583 } else {
584 return JS_FALSE;
585 }
586 return JS_TRUE;
587 }
588 /*TODO*/
svg_udom_smil_resume(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)589 static JSValue svg_udom_smil_resume(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
590 {
591 u32 tag;
592 GF_Node *n = dom_get_element(c, obj);
593 if (!n) return JS_EXCEPTION;
594
595 tag = gf_node_get_tag(n);
596 if (gf_svg_is_animation_tag(tag)) {
597 /* resuming an animation element (set, animate ...) should resume the main time line ? */
598 gf_smil_timing_resume(n);
599 } else if (gf_svg_is_timing_tag(tag)) {
600 ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_RESUME_SVG, n, NULL);
601 } else if ((tag==TAG_SVG_svg) && (n->sgprivate->scenegraph->RootNode==n)) {
602 ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_RESUME_SVG, n, NULL);
603 } else {
604 return JS_FALSE;
605 }
606 return JS_TRUE;
607 }
608
svg_udom_smil_restart(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)609 static JSValue svg_udom_smil_restart(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
610 {
611 u32 tag;
612 GF_Node *n = dom_get_element(c, obj);
613 if (!n) return JS_EXCEPTION;
614
615 tag = gf_node_get_tag(n);
616 if ((tag==TAG_SVG_svg) && (n->sgprivate->scenegraph->RootNode==n)) {
617 ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_RESTART_SVG, n, NULL);
618 } else {
619 return JS_FALSE;
620 }
621 return JS_TRUE;
622 }
623
svg_udom_smil_set_speed(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)624 static JSValue svg_udom_smil_set_speed(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
625 {
626 u32 tag;
627 Double speed = 1.0;
628 GF_Node *n = dom_get_element(c, obj);
629
630 if (!n || !argc || JS_ToFloat64(c, &speed, argv[0]) ) {
631 return JS_EXCEPTION;
632 }
633 tag = gf_node_get_tag(n);
634 if ((tag==TAG_SVG_svg) && (n->sgprivate->scenegraph->RootNode==n)) {
635 GF_JSAPIParam par;
636 memset(&par, 0, sizeof(GF_JSAPIParam));
637 par.val = FLT2FIX(speed);
638 ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_SET_SCENE_SPEED, n, &par);
639 } else {
640 return JS_TRUE;
641 }
642 return JS_UNDEFINED;
643 }
644
svg_udom_get_trait(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)645 static JSValue svg_udom_get_trait(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
646 {
647 char *attValue;
648 const char *name;
649 GF_Err e;
650 JSValue ret;
651 GF_FieldInfo info;
652 GF_Node *n = dom_get_element(c, obj);
653 if (!n) return JS_EXCEPTION;
654
655 //ns = NULL;
656 name = NULL;
657 if (! JSVAL_CHECK_STRING(argv[0]) ) return JS_TRUE;
658 if (argc==2) {
659 //ns = JS_ToCString(c, argv[0]);
660 name = JS_ToCString(c, argv[1]);
661 } else if (argc==1) {
662 name = JS_ToCString(c, argv[0]);
663 } else return JS_EXCEPTION;
664
665 if (!name) {
666 //JS_FreeCString(c, ns);
667 return JS_EXCEPTION;
668 }
669 if (!strcmp(name, "#text")) {
670 char *res = gf_dom_flatten_textContent(n);
671 ret = JS_NewString(c, res);
672 gf_free(res);
673 //JS_FreeCString(c, ns);
674 JS_FreeCString(c, name);
675 return ret;
676 }
677 e = gf_node_get_field_by_name(n, (char *) name, &info);
678
679 //JS_FreeCString(c, ns);
680 JS_FreeCString(c, name);
681
682 if (e!=GF_OK) return JS_EXCEPTION;
683
684 switch (info.fieldType) {
685 /* inheritable floats */
686 case SVG_FontSize_datatype:
687 case SVG_Color_datatype:
688 case SVG_Paint_datatype:
689 /* inheritable float and unit */
690 case SVG_Length_datatype:
691 case SVG_Coordinate_datatype:
692 /*Number*/
693 case SVG_Number_datatype:
694
695 /*all string traits*/
696 case SVG_Boolean_datatype:
697 case SVG_FillRule_datatype:
698 case SVG_StrokeLineJoin_datatype:
699 case SVG_StrokeLineCap_datatype:
700 case SVG_FontStyle_datatype:
701 case SVG_FontWeight_datatype:
702 case SVG_FontVariant_datatype:
703 case SVG_TextAnchor_datatype:
704 case SVG_Display_datatype:
705 case SVG_Visibility_datatype:
706 case SVG_GradientUnit_datatype:
707 case SVG_PreserveAspectRatio_datatype:
708 case XML_Space_datatype:
709 case XMLEV_Propagate_datatype:
710 case XMLEV_DefaultAction_datatype:
711 case XMLEV_Phase_datatype:
712 case SMIL_SyncBehavior_datatype:
713 case SMIL_SyncTolerance_datatype:
714 case SMIL_AttributeType_datatype:
715 case SMIL_CalcMode_datatype:
716 case SMIL_Additive_datatype:
717 case SMIL_Accumulate_datatype:
718 case SMIL_Restart_datatype:
719 case SMIL_Fill_datatype:
720 case SVG_Overflow_datatype:
721 case SVG_ZoomAndPan_datatype:
722 case SVG_DisplayAlign_datatype:
723 case SVG_TextAlign_datatype:
724 case SVG_PointerEvents_datatype:
725 case SVG_RenderingHint_datatype:
726 case SVG_VectorEffect_datatype:
727 case SVG_PlaybackOrder_datatype:
728 case SVG_TimelineBegin_datatype:
729 /*end of string traits*/
730 /*DOM string traits*/
731 case SVG_FontFamily_datatype:
732 case XMLRI_datatype:
733 case DOM_String_datatype:
734 case SVG_ContentType_datatype:
735 case SVG_LanguageID_datatype:
736 case SVG_Focus_datatype:
737 case SVG_ID_datatype:
738 case SVG_GradientOffset_datatype:
739 /*end of DOM string traits*/
740 attValue = gf_svg_dump_attribute(n, &info);
741 ret = JS_NewString(c, attValue);
742 if (attValue) gf_free(attValue);
743 return ret;
744
745 #if 0
746 /*SVGT 1.2 default traits*/
747 case SMIL_KeyTimes_datatype:
748 case SMIL_KeyPoints_datatype:
749 case SMIL_KeySplines_datatype:
750 case SVG_Coordinates_datatype:
751 case SVG_StrokeDashArray_datatype:
752 case SVG_Points_datatype:
753 case SVG_Motion_datatype:
754 /*end SVGT 1.2 default traits*/
755
756 /*unimplemented/unnkown/FIXME traits*/
757 case SMIL_SyncTolerance_datatype:
758 case SVG_TransformType_datatype:
759 case SVG_TransformList_datatype:
760 case SMIL_AnimateValue_datatype:
761 case SMIL_AnimateValues_datatype:
762 case SMIL_AttributeName_datatype:
763 case SMIL_Times_datatype:
764 case SMIL_Duration_datatype:
765 case SMIL_RepeatCount_datatype:
766 default:
767 /*end unimplemented/unnkown/FIXME traits*/
768 return JS_EXCEPTION;
769 #endif
770 }
771 return JS_NULL;
772 }
773
svg_udom_get_float_trait(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)774 static JSValue svg_udom_get_float_trait(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
775 {
776 const char *szName;
777 GF_FieldInfo info;
778 GF_Err e;
779 GF_Node *n = dom_get_element(c, obj);
780 if (!n) return JS_EXCEPTION;
781
782 if ((argc!=1) || !JS_IsString(argv[0])) return JS_EXCEPTION;
783 szName = JS_ToCString(c, argv[0]);
784 if (!szName) return JS_EXCEPTION;
785
786 e = gf_node_get_attribute_by_name(n, (char *) szName, 0, GF_TRUE, GF_TRUE, &info);
787 JS_FreeCString(c, szName);
788 if (e != GF_OK) return JS_EXCEPTION;
789
790 switch (info.fieldType) {
791 /* inheritable floats */
792 case SVG_Number_datatype:
793 case SVG_FontSize_datatype:
794 case SVG_Length_datatype:
795 case SVG_Coordinate_datatype:
796 {
797 SVG_Number *l = (SVG_Number *)info.far_ptr;
798 if (l->type==SVG_NUMBER_AUTO || l->type==SVG_NUMBER_INHERIT) return JS_TRUE;
799 return JS_NewFloat64(c, FIX2FLT(l->value));
800 }
801 case SVG_Clock_datatype:
802 return JS_NewFloat64(c, *(SVG_Clock*)info.far_ptr );
803 default:
804 return JS_NULL;
805 }
806 return JS_NULL;
807 }
808
svg_udom_get_matrix_trait(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)809 static JSValue svg_udom_get_matrix_trait(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
810 {
811 const char *szName;
812 GF_FieldInfo info;
813 GF_Err e;
814 GF_Node *n = dom_get_element(c, obj);
815 if (!n) return JS_EXCEPTION;
816
817 if ((argc!=1) || !JS_IsString(argv[0])) return JS_EXCEPTION;
818 szName = JS_ToCString(c, argv[0]);
819
820 e = gf_node_get_field_by_name(n, (char *) szName, &info);
821 JS_FreeCString(c, szName);
822 if (e != GF_OK) return JS_EXCEPTION;
823
824 if (info.fieldType==SVG_Transform_datatype) {
825 GF_Matrix2D *mx = (GF_Matrix2D *)gf_malloc(sizeof(GF_Matrix2D));
826 if (!mx) return JS_EXCEPTION;
827 JSValue mO = JS_NewObjectClass(c, matrixClass.class_id);
828 gf_mx2d_init(*mx);
829 gf_mx2d_copy(*mx, ((SVG_Transform*)info.far_ptr)->mat);
830
831 JS_SetOpaque(mO, mx);
832 return mO;
833 }
834 return JS_NULL;
835 }
836
svg_udom_get_rect_trait(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)837 static JSValue svg_udom_get_rect_trait(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
838 {
839 const char *szName;
840 GF_FieldInfo info;
841 GF_Err e;
842 GF_Node *n = dom_get_element(c, obj);
843 if (!n) return JS_EXCEPTION;
844
845 if ((argc!=1) || !JS_IsString(argv[0])) return JS_EXCEPTION;
846 szName = JS_ToCString(c, argv[0]);
847
848 e = gf_node_get_field_by_name(n, (char *) szName, &info);
849 JS_FreeCString(c, szName);
850 if (e != GF_OK) return JS_EXCEPTION;
851
852 if (info.fieldType==SVG_ViewBox_datatype) {
853 JSValue newObj;
854 rectCI *rc;
855 SVG_ViewBox *v = (SVG_ViewBox *)info.far_ptr;
856 GF_SAFEALLOC(rc, rectCI);
857 if (!rc) {
858 return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
859 }
860 newObj = JS_NewObjectClass(c, rectClass.class_id);
861 rc->x = FIX2FLT(v->x);
862 rc->y = FIX2FLT(v->y);
863 rc->w = FIX2FLT(v->width);
864 rc->h = FIX2FLT(v->height);
865 JS_SetOpaque(newObj, rc);
866 return newObj;
867 }
868 return JS_NULL;
869 }
870
svg_udom_get_path_trait(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)871 static JSValue svg_udom_get_path_trait(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
872 {
873 const char *szName;
874 GF_FieldInfo info;
875 GF_Err e;
876 GF_Node *n = dom_get_element(c, obj);
877 if (!n) return JS_EXCEPTION;
878
879 if ((argc!=1) || !JS_IsString(argv[0])) return JS_EXCEPTION;
880 szName = JS_ToCString(c, argv[0]);
881
882 e = gf_node_get_field_by_name(n, (char *) szName, &info);
883 JS_FreeCString(c, szName);
884 if (e != GF_OK) return JS_EXCEPTION;
885
886 if (info.fieldType==SVG_PathData_datatype) {
887 return svg_new_path_object(c, (SVG_PathData *)info.far_ptr);
888 }
889 return JS_NULL;
890 }
891
svg_udom_get_rgb_color_trait(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)892 static JSValue svg_udom_get_rgb_color_trait(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
893 {
894 const char *szName;
895 GF_FieldInfo info;
896 rgbCI *rgb;
897 GF_Err e;
898 JSValue newObj;
899
900 GF_Node *n = dom_get_element(c, obj);
901 if (!n) return JS_EXCEPTION;
902
903 if ((argc!=1) || !JS_IsString(argv[0])) return JS_EXCEPTION;
904 szName = JS_ToCString(c, argv[0]);
905
906 e = gf_node_get_field_by_name(n, (char *) szName, &info);
907 JS_FreeCString(c, szName);
908 if (e != GF_OK) return JS_EXCEPTION;
909
910 switch (info.fieldType) {
911 case SVG_Color_datatype:
912 {
913 SVG_Color *col = (SVG_Color *)info.far_ptr;
914 if (col->type == SVG_COLOR_CURRENTCOLOR) return JS_UNDEFINED;
915 if (col->type == SVG_COLOR_INHERIT) return JS_UNDEFINED;
916
917 GF_SAFEALLOC(rgb, rgbCI);
918 if (!rgb) {
919 return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
920 }
921 newObj = JS_NewObjectClass(c, rgbClass.class_id);
922 rgb->r = (u8) (255*FIX2FLT(col->red)) ;
923 rgb->g = (u8) (255*FIX2FLT(col->green)) ;
924 rgb->b = (u8) (255*FIX2FLT(col->blue)) ;
925 JS_SetOpaque(newObj, rgb);
926 return newObj;
927 }
928 break;
929 case SVG_Paint_datatype:
930 {
931 SVG_Paint *paint = (SVG_Paint *)info.far_ptr;
932 if ((1) || paint->type==SVG_PAINT_COLOR) {
933 GF_SAFEALLOC(rgb, rgbCI);
934 if (!rgb) {
935 return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
936 }
937 newObj = JS_NewObjectClass(c, rgbClass.class_id);
938 rgb->r = (u8) (255*FIX2FLT(paint->color.red) );
939 rgb->g = (u8) (255*FIX2FLT(paint->color.green) );
940 rgb->b = (u8) (255*FIX2FLT(paint->color.blue) );
941 JS_SetOpaque(newObj, rgb);
942 return newObj;
943 }
944 return JS_TRUE;
945 }
946 }
947 return JS_NULL;
948 }
949
svg_udom_set_trait(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)950 static JSValue svg_udom_set_trait(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
951 {
952 const char *ns, *name, *val;
953 GF_Err e;
954 GF_FieldInfo info;
955 GF_Node *n = dom_get_element(c, obj);
956 if (!n) return JS_EXCEPTION;
957
958 val = ns = name = NULL;
959 if (!JSVAL_CHECK_STRING(argv[0])) return JS_EXCEPTION;
960 if (argc==3) {
961 if (!JSVAL_CHECK_STRING(argv[1])) return JS_EXCEPTION;
962 if (!JSVAL_CHECK_STRING(argv[2])) return JS_EXCEPTION;
963 ns = JS_ToCString(c, argv[0]);
964 name = JS_ToCString(c, argv[1]);
965 val = JS_ToCString(c, argv[2]);
966 } else if (argc==2) {
967 name = JS_ToCString(c, argv[0]);
968 val = JS_ToCString(c, argv[1]);
969 } else {
970 return JS_EXCEPTION;
971 }
972 if (!name) {
973 JS_FreeCString(c, ns);
974 JS_FreeCString(c, val);
975 return JS_EXCEPTION;
976 }
977 if (!strcmp(name, "#text")) {
978 if (val) dom_node_set_textContent(n, (char *) val);
979 JS_FreeCString(c, ns);
980 JS_FreeCString(c, name);
981 JS_FreeCString(c, val);
982 return JS_UNDEFINED;
983 }
984 e = gf_node_get_field_by_name(n, (char *) name, &info);
985 JS_FreeCString(c, ns);
986 JS_FreeCString(c, name);
987
988 if (!val || (e!=GF_OK)) {
989 JS_FreeCString(c, val);
990 return JS_EXCEPTION;
991 }
992 e = gf_svg_parse_attribute(n, &info, (char *) val, 0);
993 JS_FreeCString(c, val);
994
995 if (e) return js_throw_err(c, GF_DOM_EXC_INVALID_ACCESS_ERR);
996 dom_node_changed(n, GF_FALSE, &info);
997 return JS_UNDEFINED;
998 }
999
svg_udom_set_float_trait(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1000 static JSValue svg_udom_set_float_trait(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1001 {
1002 GF_FieldInfo info;
1003 Double d;
1004 GF_Err e;
1005 const char *szName;
1006
1007 GF_Node *n = dom_get_element(c, obj);
1008 if (!n) return JS_EXCEPTION;
1009 if (argc!=2) return JS_EXCEPTION;
1010 if (!JS_IsString(argv[0])) return JS_EXCEPTION;
1011 if (!JS_IsNumber(argv[1]) || JS_ToFloat64(c, &d, argv[1])) return JS_EXCEPTION;
1012
1013 szName = JS_ToCString(c, argv[0]);
1014 e = gf_node_get_field_by_name(n, (char *) szName, &info);
1015 JS_FreeCString(c, szName);
1016 if (e != GF_OK) return JS_EXCEPTION;
1017
1018 switch (info.fieldType) {
1019 /* inheritable floats */
1020 case SVG_FontSize_datatype:
1021 case SVG_Length_datatype:
1022 case SVG_Coordinate_datatype:
1023 case SVG_Number_datatype:
1024 {
1025 SVG_Number *l = (SVG_Number *)info.far_ptr;
1026 l->type=SVG_NUMBER_VALUE;
1027 l->value = FLT2FIX(d);
1028 break;
1029 }
1030 case SVG_Numbers_datatype:
1031 case SVG_Coordinates_datatype:
1032 {
1033 SVG_Number *val;
1034 SVG_Coordinates *l = (SVG_Coordinates *)info.far_ptr;
1035 while (gf_list_count(*l)) {
1036 val = (SVG_Number *)gf_list_get(*l, 0);
1037 gf_list_rem(*l, 0);
1038 if (val) gf_free(val);
1039 }
1040 GF_SAFEALLOC(val, SVG_Coordinate);
1041 if (!val) {
1042 return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
1043 }
1044 val->type=SVG_NUMBER_VALUE;
1045 val->value = FLT2FIX(d);
1046 gf_list_add(*l, val);
1047 break;
1048 }
1049 default:
1050 return JS_FALSE;
1051 }
1052 dom_node_changed(n, GF_FALSE, &info);
1053 return JS_TRUE;
1054 }
1055
svg_udom_set_matrix_trait(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1056 static JSValue svg_udom_set_matrix_trait(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1057 {
1058 const char *szName;
1059 GF_FieldInfo info;
1060 GF_Matrix2D *mx;
1061 GF_Err e;
1062
1063 GF_Node *n = dom_get_element(c, obj);
1064 if (!n) return JS_TRUE;
1065
1066 if (argc!=2) return JS_EXCEPTION;
1067 if (!JS_IsString(argv[0])) return JS_EXCEPTION;
1068 if (JS_IsNull(argv[1]) || !JS_IsObject(argv[1])) return JS_EXCEPTION;
1069
1070 mx = JS_GetOpaque(argv[1], matrixClass.class_id);
1071 if (!mx) return JS_EXCEPTION;
1072
1073 szName = JS_ToCString(c, argv[0]);
1074 e = gf_node_get_field_by_name(n, (char *) szName, &info);
1075 JS_FreeCString(c, szName);
1076 if (e != GF_OK) return JS_EXCEPTION;
1077
1078 if (info.fieldType==SVG_Transform_datatype) {
1079 gf_mx2d_copy(((SVG_Transform*)info.far_ptr)->mat, *mx);
1080 dom_node_changed(n, GF_FALSE, NULL);
1081 return JS_TRUE;
1082 }
1083 return JS_FALSE;
1084 }
1085
svg_udom_set_rect_trait(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1086 static JSValue svg_udom_set_rect_trait(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1087 {
1088 const char *szName;
1089 GF_FieldInfo info;
1090 rectCI *rc;
1091 GF_Err e;
1092 GF_Node *n = dom_get_element(c, obj);
1093 if (!n) return JS_EXCEPTION;
1094
1095 if (argc!=2) return JS_EXCEPTION;
1096 if (!JS_IsString(argv[0])) return JS_TRUE;
1097 if (JS_IsNull(argv[1]) || !JS_IsObject(argv[1])) return JS_EXCEPTION;
1098
1099 rc = JS_GetOpaque(argv[1], rectClass.class_id);
1100 if (!rc) return JS_EXCEPTION;
1101
1102 szName = JS_ToCString(c, argv[0]);
1103 e = gf_node_get_field_by_name(n, (char *) szName, &info);
1104 JS_FreeCString(c, szName);
1105 if (e != GF_OK) return JS_EXCEPTION;
1106
1107 if (info.fieldType==SVG_ViewBox_datatype) {
1108 SVG_ViewBox *v = (SVG_ViewBox *)info.far_ptr;
1109 v->x = FLT2FIX(rc->x);
1110 v->y = FLT2FIX(rc->y);
1111 v->width = FLT2FIX(rc->w);
1112 v->height = FLT2FIX(rc->h);
1113 dom_node_changed(n, GF_FALSE, NULL);
1114 return JS_TRUE;
1115 }
1116 return JS_FALSE;
1117 }
1118
svg_udom_set_path_trait(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1119 static JSValue svg_udom_set_path_trait(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1120 {
1121 pathCI *path;
1122 GF_FieldInfo info;
1123 const char *szName;
1124 GF_Err e;
1125 GF_Node *n = dom_get_element(c, obj);
1126 if (!n) return JS_EXCEPTION;
1127
1128 if (argc!=2) return JS_EXCEPTION;
1129 if (!JS_IsString(argv[0])) return JS_EXCEPTION;
1130 if (JS_IsNull(argv[1]) || !JS_IsObject(argv[1])) return JS_EXCEPTION;
1131 path = JS_GetOpaque( argv[1], pathClass.class_id);
1132 if (!path) return JS_EXCEPTION;
1133
1134 szName = JS_ToCString(c, argv[0]);
1135 e = gf_node_get_field_by_name(n, (char *) szName, &info);
1136 JS_FreeCString(c, szName);
1137 if (e != GF_OK) return JS_EXCEPTION;
1138
1139 if (info.fieldType==SVG_PathData_datatype) {
1140 #if USE_GF_PATH
1141 #else
1142 u32 i;
1143 u32 nb_pts;
1144 SVG_PathData *d = (SVG_PathData *)info.far_ptr;
1145 while (gf_list_count(d->commands)) {
1146 u8 *t = gf_list_get(d->commands, 0);
1147 gf_list_rem(d->commands, 0);
1148 gf_free(t);
1149 }
1150 while (gf_list_count(d->points)) {
1151 SVG_Point *t = gf_list_get(d->points, 0);
1152 gf_list_rem(d->points, 0);
1153 gf_free(t);
1154 }
1155 nb_pts = 0;
1156 for (i=0; i<path->nb_coms; i++) {
1157 u8 *t = gf_malloc(sizeof(u8));
1158 *t = path->tags[i];
1159 gf_list_add(d->commands, t);
1160 switch (*t) {
1161 case 0:
1162 case 1:
1163 nb_pts++;
1164 break;
1165 case 2:
1166 nb_pts+=3;
1167 break;
1168 case 4:
1169 nb_pts+=2;
1170 break;
1171 }
1172 }
1173 for (i=0; i<nb_pts; i++) {
1174 SVG_Point *t = gf_malloc(sizeof(SVG_Point));
1175 t->x = FLT2FIX(path->pts[i].x);
1176 t->y = FLT2FIX(path->pts[i].y);
1177 gf_list_add(d->points, t);
1178 }
1179 dom_node_changed(n, 0, NULL);
1180 return JS_TRUE;
1181 #endif
1182 }
1183 return JS_FALSE;
1184 }
1185
svg_udom_set_rgb_color_trait(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1186 static JSValue svg_udom_set_rgb_color_trait(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1187 {
1188 GF_FieldInfo info;
1189 rgbCI *rgb;
1190 GF_Err e;
1191 const char *szName;
1192 GF_Node *n = dom_get_element(c, obj);
1193 if (!n) return JS_EXCEPTION;
1194
1195 if (argc!=2) return JS_EXCEPTION;
1196 if (!JS_IsString(argv[0])) return JS_EXCEPTION;
1197 if (!JS_IsObject(argv[1])) return JS_EXCEPTION;
1198 rgb = JS_GetOpaque(argv[1], rgbClass.class_id);
1199 if (!rgb) return JS_EXCEPTION;
1200
1201 szName = JS_ToCString(c, argv[0]);
1202 e = gf_node_get_field_by_name(n, (char *) szName, &info);
1203 JS_FreeCString(c, szName);
1204 if (e != GF_OK) return JS_EXCEPTION;
1205
1206 switch (info.fieldType) {
1207 case SVG_Color_datatype:
1208 {
1209 SVG_Color *col = (SVG_Color *)info.far_ptr;
1210 col->type = SVG_COLOR_RGBCOLOR;
1211 col->red = FLT2FIX(rgb->r / 255.0f);
1212 col->green = FLT2FIX(rgb->g / 255.0f);
1213 col->blue = FLT2FIX(rgb->b / 255.0f);
1214 dom_node_changed(n, GF_FALSE, &info);
1215 return JS_TRUE;
1216 }
1217 case SVG_Paint_datatype:
1218 {
1219 SVG_Paint *paint = (SVG_Paint *)info.far_ptr;
1220 paint->type = SVG_PAINT_COLOR;
1221 paint->color.type = SVG_COLOR_RGBCOLOR;
1222 paint->color.red = FLT2FIX(rgb->r / 255.0f);
1223 paint->color.green = FLT2FIX(rgb->g / 255.0f);
1224 paint->color.blue = FLT2FIX(rgb->b / 255.0f);
1225 dom_node_changed(n, GF_FALSE, &info);
1226 return JS_TRUE;
1227 }
1228 }
1229 return JS_FALSE;
1230 }
1231
svg_get_bbox(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv,Bool get_screen)1232 static JSValue svg_get_bbox(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool get_screen)
1233 {
1234 GF_JSAPIParam par;
1235 GF_Node *n = dom_get_element(c, obj);
1236 if (!n || argc) return JS_EXCEPTION;
1237
1238 par.bbox.is_set = GF_FALSE;
1239 if (ScriptAction(n->sgprivate->scenegraph, get_screen ? GF_JSAPI_OP_GET_SCREEN_BBOX : GF_JSAPI_OP_GET_LOCAL_BBOX, (GF_Node *)n, &par) ) {
1240 if (par.bbox.is_set) {
1241 rectCI *rc = (rectCI *)gf_malloc(sizeof(rectCI));
1242 if (!rc) return JS_EXCEPTION;
1243 JSValue rO = JS_NewObjectClass(c, rectClass.class_id);
1244 rc->sg = NULL;
1245 rc->x = FIX2FLT(par.bbox.min_edge.x);
1246 /*BBox is in 3D coord system style*/
1247 rc->y = FIX2FLT(par.bbox.min_edge.y);
1248 rc->w = FIX2FLT(par.bbox.max_edge.x - par.bbox.min_edge.x);
1249 rc->h = FIX2FLT(par.bbox.max_edge.y - par.bbox.min_edge.y);
1250 JS_SetOpaque(rO, rc);
1251 return rO;
1252 } else {
1253 return JS_NULL;
1254 }
1255 return JS_TRUE;
1256 }
1257 return JS_FALSE;
1258 }
1259
svg_udom_get_local_bbox(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1260 static JSValue svg_udom_get_local_bbox(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1261 {
1262 return svg_get_bbox(c, obj, argc, argv, GF_FALSE);
1263 }
svg_udom_get_screen_bbox(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1264 static JSValue svg_udom_get_screen_bbox(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1265 {
1266 return svg_get_bbox(c, obj, argc, argv, GF_TRUE);
1267 }
1268
svg_udom_get_screen_ctm(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1269 static JSValue svg_udom_get_screen_ctm(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1270 {
1271 GF_JSAPIParam par;
1272 GF_Node *n = dom_get_element(c, obj);
1273 if (!n || argc) return JS_EXCEPTION;
1274
1275 if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_GET_TRANSFORM, (GF_Node *)n, &par)) {
1276 GF_Matrix2D *mx = (GF_Matrix2D *)gf_malloc(sizeof(GF_Matrix2D));
1277 if (!mx) return JS_EXCEPTION;
1278 JSValue mO = JS_NewObjectClass(c, matrixClass.class_id);
1279 gf_mx2d_from_mx(mx, &par.mx);
1280 JS_SetOpaque(mO, mx);
1281 return mO;
1282 }
1283 return JS_EXCEPTION;
1284 }
1285
svg_udom_create_matrix_components(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1286 static JSValue svg_udom_create_matrix_components(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1287 {
1288 GF_Matrix2D *mx;
1289 JSValue mat;
1290 Double v;
1291 GF_Node *n = dom_get_element(c, obj);
1292 if (!n) return JS_EXCEPTION;
1293 if (argc!=6) return JS_EXCEPTION;
1294
1295 GF_SAFEALLOC(mx, GF_Matrix2D)
1296 if (!mx) return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
1297
1298 JS_ToFloat64(c, &v, argv[0]);
1299 mx->m[0] = FLT2FIX(v);
1300 JS_ToFloat64(c, &v, argv[1]);
1301 mx->m[3] = FLT2FIX(v);
1302 JS_ToFloat64(c, &v, argv[2]);
1303 mx->m[1] = FLT2FIX(v);
1304 JS_ToFloat64(c, &v, argv[3]);
1305 mx->m[4] = FLT2FIX(v);
1306 JS_ToFloat64(c, &v, argv[4]);
1307 mx->m[2] = FLT2FIX(v);
1308 JS_ToFloat64(c, &v, argv[5]);
1309 mx->m[5] = FLT2FIX(v);
1310 mat = JS_NewObjectClass(c, matrixClass.class_id);
1311 JS_SetOpaque(mat, mx);
1312 return mat;
1313 }
1314
svg_udom_create_rect(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1315 static JSValue svg_udom_create_rect(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1316 {
1317 rectCI *rc;
1318 JSValue r;
1319 GF_Node *n = dom_get_element(c, obj);
1320 if (!n || argc) return JS_EXCEPTION;
1321
1322 GF_SAFEALLOC(rc, rectCI);
1323 if (!rc) return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
1324 r = JS_NewObjectClass(c, rectClass.class_id);
1325 JS_SetOpaque(r, rc);
1326 return r;
1327 }
1328
svg_udom_create_point(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1329 static JSValue svg_udom_create_point(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1330 {
1331 pointCI *pt;
1332 JSValue r;
1333 GF_Node *n = dom_get_element(c, obj);
1334 if (!n || argc) return JS_EXCEPTION;
1335
1336 GF_SAFEALLOC(pt, pointCI);
1337 if (!pt) return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
1338 r = JS_NewObjectClass(c, pointClass.class_id);
1339 JS_SetOpaque(r, pt);
1340 return r;
1341 }
1342
svg_udom_create_path(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1343 static JSValue svg_udom_create_path(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1344 {
1345 pathCI *path;
1346 JSValue p;
1347 GF_Node *n = dom_get_element(c, obj);
1348 if (!n || argc) return JS_EXCEPTION;
1349
1350 GF_SAFEALLOC(path, pathCI);
1351 if (!path) return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
1352 p = JS_NewObjectClass(c, pathClass.class_id);
1353 JS_SetOpaque(p, path);
1354 return p;
1355 }
1356
svg_udom_create_color(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1357 static JSValue svg_udom_create_color(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1358 {
1359 rgbCI *col;
1360 JSValue p;
1361 GF_Node *n = dom_get_element(c, obj);
1362 if (!n|| (argc!=3)) return JS_EXCEPTION;
1363
1364 GF_SAFEALLOC(col, rgbCI);
1365 if (!col) return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
1366
1367 JS_ToInt32(c, &col->r, argv[0]);
1368 JS_ToInt32(c, &col->g, argv[1]);
1369 JS_ToInt32(c, &col->b, argv[2]);
1370 p = JS_NewObjectClass(c, rgbClass.class_id);
1371 JS_SetOpaque(p, col);
1372 return p;
1373 }
1374
svg_path_get_total_length(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1375 static JSValue svg_path_get_total_length(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1376 {
1377 Double length = 0;
1378 GF_FieldInfo info;
1379
1380 GF_Node *n = (GF_Node *)dom_get_element(c, obj);
1381 if (!n) return JS_EXCEPTION;
1382 if (n->sgprivate->tag != TAG_SVG_path) return JS_EXCEPTION;
1383
1384 gf_node_get_field_by_name(n, "d", &info);
1385 if (info.fieldType == SVG_PathData_datatype) {
1386 #if USE_GF_PATH
1387 GF_Path *p = (GF_Path *)info.far_ptr;
1388 GF_PathIterator *path_it = gf_path_iterator_new(p);
1389 if (path_it) {
1390 Fixed len = gf_path_iterator_get_length(path_it);
1391 length = FIX2FLT(len);
1392 gf_path_iterator_del(path_it);
1393 }
1394 #endif
1395 }
1396 return JS_NewFloat64(c, length);
1397 }
1398
svg_udom_move_focus(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1399 static JSValue svg_udom_move_focus(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1400 {
1401 GF_JSAPIParam par;
1402 GF_Node *n = dom_get_element(c, obj);
1403 if (!n) return JS_EXCEPTION;
1404 if ((argc!=1) || !JS_IsObject(argv[0])) return JS_EXCEPTION;
1405
1406 JS_ToInt32(c, &par.opt, argv[1]);
1407 if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_SET_FOCUS, (GF_Node *)n, &par))
1408 return JS_TRUE;
1409 return JS_FALSE;
1410 }
1411
svg_udom_set_focus(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1412 static JSValue svg_udom_set_focus(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1413 {
1414 GF_JSAPIParam par;
1415 GF_Node *n = dom_get_element(c, obj);
1416 if (!n) return JS_EXCEPTION;
1417 if ((argc!=1) || !JS_IsObject(argv[0])) return JS_EXCEPTION;
1418
1419 par.node = dom_get_element(c, argv[0]);
1420 /*NOT IN THE GRAPH*/
1421 if (!par.node || !par.node->sgprivate->num_instances) return JS_EXCEPTION;
1422 if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_SET_FOCUS, (GF_Node *)n, &par))
1423 return JS_TRUE;
1424 return JS_TRUE;
1425 }
1426
svg_udom_get_focus(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1427 static JSValue svg_udom_get_focus(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1428 {
1429 GF_JSAPIParam par;
1430 GF_Node *n = dom_get_element(c, obj);
1431 if (!n || argc) return JS_EXCEPTION;
1432
1433 if (!ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_GET_FOCUS, (GF_Node *)n, &par))
1434 return JS_EXCEPTION;
1435
1436 if (par.node) {
1437 return dom_element_construct(c, par.node);
1438 }
1439 return JS_NULL;
1440 }
1441
svg_udom_get_time(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1442 static JSValue svg_udom_get_time(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1443 {
1444 GF_Node *n = dom_get_element(c, obj);
1445 if (!n) return JS_EXCEPTION;
1446
1447 return JS_NewFloat64(c, gf_node_get_scene_time(n) );
1448 }
1449
1450
svg_connection_create(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1451 static JSValue svg_connection_create(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1452 {
1453 return js_throw_err(c, GF_DOM_EXC_NOT_SUPPORTED_ERR);
1454 }
1455
baseCI_finalize(JSRuntime * rt,JSValue obj)1456 static void baseCI_finalize(JSRuntime *rt, JSValue obj)
1457 {
1458 /*avoids GCC warning*/
1459 void *data = JS_GetOpaque_Nocheck(obj);
1460 if (data) gf_free(data);
1461 }
1462
rgb_getProperty(JSContext * c,JSValueConst obj,int magic)1463 static JSValue rgb_getProperty(JSContext *c, JSValueConst obj, int magic)
1464 {
1465 rgbCI *col = (rgbCI *) JS_GetOpaque(obj, rgbClass.class_id);
1466 if (!col) return JS_EXCEPTION;
1467 switch (magic) {
1468 case 0: return JS_NewInt32(c, col->r);
1469 case 1: return JS_NewInt32(c, col->g);
1470 case 2: return JS_NewInt32(c, col->b);
1471 default:
1472 return JS_EXCEPTION;
1473 }
1474 }
rgb_setProperty(JSContext * c,JSValueConst obj,JSValueConst value,int magic)1475 static JSValue rgb_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
1476 {
1477 rgbCI *col = (rgbCI *) JS_GetOpaque(obj, rgbClass.class_id);
1478 if (!col) return JS_EXCEPTION;
1479
1480 switch (magic) {
1481 case 0: return JS_ToInt32(c, &col->r, value) ? JS_EXCEPTION : JS_TRUE;
1482 case 1: return JS_ToInt32(c, &col->g, value) ? JS_EXCEPTION : JS_TRUE;
1483 case 2: return JS_ToInt32(c, &col->b, value) ? JS_EXCEPTION : JS_TRUE;
1484 default:
1485 return JS_EXCEPTION;
1486 }
1487 }
1488
rect_getProperty(JSContext * c,JSValueConst obj,int magic)1489 static JSValue rect_getProperty(JSContext *c, JSValueConst obj, int magic)
1490 {
1491 rectCI *rc = (rectCI *) JS_GetOpaque(obj, rectClass.class_id);
1492 if (!rc) return JS_EXCEPTION;
1493 if (rc->sg) {
1494 GF_JSAPIParam par;
1495 if (!ScriptAction(rc->sg, GF_JSAPI_OP_GET_VIEWPORT, rc->sg->RootNode, &par)) {
1496 return JS_EXCEPTION;
1497 }
1498 rc->x = FIX2FLT(par.rc.x);
1499 rc->y = FIX2FLT(par.rc.y);
1500 rc->w = FIX2FLT(par.rc.width);
1501 rc->h = FIX2FLT(par.rc.height);
1502 }
1503 switch (magic) {
1504 case 0: return JS_NewFloat64(c, rc->x);
1505 case 1: return JS_NewFloat64(c, rc->y);
1506 case 2: return JS_NewFloat64(c, rc->w);
1507 case 3: return JS_NewFloat64(c, rc->h);
1508 default:
1509 return JS_EXCEPTION;
1510 }
1511 }
1512
rect_setProperty(JSContext * c,JSValueConst obj,JSValueConst value,int magic)1513 static JSValue rect_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
1514 {
1515 Double d;
1516 rectCI *rc = (rectCI *) JS_GetOpaque(obj, rectClass.class_id);
1517 if (!rc) return JS_EXCEPTION;
1518 if (JS_ToFloat64(c, &d, value)) return JS_EXCEPTION;
1519 switch (magic) {
1520 case 0:
1521 rc->x = (Float) d;
1522 return JS_TRUE;
1523 case 1:
1524 rc->y = (Float) d;
1525 return JS_TRUE;
1526 case 2:
1527 rc->w = (Float) d;
1528 return JS_TRUE;
1529 case 3:
1530 rc->h = (Float) d;
1531 return JS_TRUE;
1532 default:
1533 return JS_EXCEPTION;
1534 }
1535 }
1536
point_getProperty(JSContext * c,JSValueConst obj,int magic)1537 static JSValue point_getProperty(JSContext *c, JSValueConst obj, int magic)
1538 {
1539 pointCI *pt = (pointCI *) JS_GetOpaque(obj, pointClass.class_id);
1540 if (!pt) return JS_EXCEPTION;
1541
1542 if (pt->sg) {
1543 GF_JSAPIParam par;
1544 if (!ScriptAction(pt->sg, GF_JSAPI_OP_GET_TRANSLATE, pt->sg->RootNode, &par)) {
1545 return JS_EXCEPTION;
1546 }
1547 pt->x = FIX2FLT(par.pt.x);
1548 pt->y = FIX2FLT(par.pt.y);
1549 }
1550 switch (magic) {
1551 case 0: return JS_NewFloat64(c, pt->x);
1552 case 1: return JS_NewFloat64(c, pt->y);
1553 default: return JS_EXCEPTION;
1554 }
1555 }
1556
point_setProperty(JSContext * c,JSValueConst obj,JSValueConst value,int magic)1557 static JSValue point_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
1558 {
1559 pointCI *pt = (pointCI *) JS_GetOpaque(obj, pointClass.class_id);
1560 if (!pt) return JS_EXCEPTION;
1561
1562 Double d;
1563 if (JS_ToFloat64(c, &d, value)) return JS_EXCEPTION;
1564 switch (magic) {
1565 case 0:
1566 pt->x = (Float) d;
1567 break;
1568 case 1:
1569 pt->y = (Float) d;
1570 break;
1571 default:
1572 return JS_EXCEPTION;
1573 }
1574 if (pt->sg) {
1575 GF_JSAPIParam par;
1576 par.pt.x = FLT2FIX(pt->x);
1577 par.pt.y = FLT2FIX(pt->y);
1578 ScriptAction(pt->sg, GF_JSAPI_OP_SET_TRANSLATE, pt->sg->RootNode, &par);
1579 }
1580 return JS_UNDEFINED;
1581 }
1582
svg_new_path_object(JSContext * c,SVG_PathData * d)1583 static JSValue svg_new_path_object(JSContext *c, SVG_PathData *d)
1584 {
1585 #if USE_GF_PATH
1586 return JS_NULL;
1587 #else
1588 JSValue obj;
1589 pathCI *p;
1590 GF_SAFEALLOC(p, pathCI);
1591 if (!p) return JS_EXCEPTION;
1592 if (d) {
1593 u32 i, count;
1594 p->nb_coms = gf_list_count(d->commands);
1595 p->tags = gf_malloc(sizeof(u8) * p->nb_coms);
1596 for (i=0; i<p->nb_coms; i++) p->tags[i] = * (u8 *) gf_list_get(d->commands, i);
1597 count = gf_list_count(d->points);
1598 p->pts = gf_malloc(sizeof(pointCI) * count);
1599 for (i=0; i<count; i++) {
1600 GF_Point2D *pt = gf_list_get(d->commands, i);
1601 p->pts[i].x = FIX2FLT(pt->x);
1602 p->pts[i].y = FIX2FLT(pt->y);
1603 }
1604 }
1605 obj = JS_NewObjectClass(c, pathClass.class_id);
1606 JS_SetOpaque(obj, p);
1607 return obj;
1608 #endif
1609 }
1610
pathCI_finalize(JSRuntime * rt,JSValue obj)1611 static void pathCI_finalize(JSRuntime *rt, JSValue obj)
1612 {
1613 pathCI *p = (pathCI *) JS_GetOpaque(obj, pathClass.class_id);
1614 if (p) {
1615 if (p->pts) gf_free(p->pts);
1616 if (p->tags) gf_free(p->tags);
1617 gf_free(p);
1618 }
1619 }
1620
path_getProperty(JSContext * c,JSValueConst obj,int magic)1621 static JSValue path_getProperty(JSContext *c, JSValueConst obj, int magic)
1622 {
1623 pathCI *p = (pathCI *) JS_GetOpaque(obj, pathClass.class_id);
1624 if (!p) return JS_EXCEPTION;
1625 switch (magic) {
1626 case 0: return JS_NewInt32(c, p->nb_coms);
1627 default:
1628 return JS_EXCEPTION;
1629 }
1630 }
1631
svg_path_get_segment(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1632 static JSValue svg_path_get_segment(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1633 {
1634 u32 idx;
1635 pathCI *p = (pathCI *) JS_GetOpaque(obj, pathClass.class_id);
1636 if (!p) return JS_EXCEPTION;
1637 if ((argc!=1) || JS_ToInt32(c, &idx, argv[0])) return JS_EXCEPTION;
1638 if (idx>=p->nb_coms) return JS_TRUE;
1639 switch (p->tags[idx]) {
1640 case 0: return JS_NewInt32(c, 77);/* Move To */
1641 case 1: return JS_NewInt32(c, 76);/* Line To */
1642 case 2:/* Curve To */
1643 case 3:/* next Curve To */
1644 return JS_NewInt32(c, 67);
1645 case 4:/* Quad To */
1646 case 5:/* next Quad To */
1647 return JS_NewInt32(c, 81);
1648 case 6:
1649 return JS_NewInt32(c, 90);/* Close */
1650 }
1651 return JS_EXCEPTION;
1652 }
1653
svg_path_get_segment_param(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1654 static JSValue svg_path_get_segment_param(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1655 {
1656 u32 i, idx, param_idx, pt_idx;
1657 ptCI *pt;
1658 pathCI *p = (pathCI *) JS_GetOpaque(obj, pathClass.class_id);
1659 if (!p) return JS_EXCEPTION;
1660
1661 if ((argc!=2) || !JS_IsInteger(argv[0]) || !JS_IsInteger(argv[1])) return JS_EXCEPTION;
1662 if (JS_ToInt32(c, &idx, argv[0])) return JS_EXCEPTION;
1663 if (JS_ToInt32(c, ¶m_idx, argv[1])) return JS_EXCEPTION;
1664 if (idx>=p->nb_coms) return JS_TRUE;
1665 pt_idx = 0;
1666 for (i=0; i<idx; i++) {
1667 switch (p->tags[i]) {
1668 case 0:
1669 pt_idx++;
1670 break;
1671 case 1:
1672 pt_idx++;
1673 break;
1674 case 2:
1675 pt_idx+=3;
1676 break;
1677 case 3:
1678 pt_idx+=2;
1679 break;
1680 case 4:
1681 pt_idx+=2;
1682 break;
1683 case 5:
1684 pt_idx+=1;
1685 break;
1686 }
1687 }
1688 switch (p->tags[idx]) {
1689 case 0:
1690 case 1:
1691 if (param_idx>1) return JS_TRUE;
1692 pt = &p->pts[pt_idx];
1693 return JS_NewFloat64(c, param_idx ? pt->y : pt->x);
1694 case 2:/* Curve To */
1695 if (param_idx>5) return JS_TRUE;
1696 pt = &p->pts[pt_idx + (param_idx/2) ];
1697 return JS_NewFloat64(c, (param_idx%2) ? pt->y : pt->x);
1698 case 3:/* Next Curve To */
1699 if (param_idx>5) return JS_TRUE;
1700 if (param_idx<2) {
1701 pt = &p->pts[pt_idx - 1];
1702 return JS_NewFloat64(c, param_idx ? pt->y : pt->x);
1703 }
1704 param_idx-=2;
1705 pt = &p->pts[pt_idx + (param_idx/2)];
1706 return JS_NewFloat64(c, (param_idx%2) ? pt->y : pt->x);
1707
1708 case 4:/* Quad To */
1709 if (param_idx>3) return JS_TRUE;
1710 pt = &p->pts[pt_idx + (param_idx/2) ];
1711 return JS_NewFloat64(c, (param_idx%2) ? pt->y : pt->x);
1712
1713 case 5:/* Next Quad To */
1714 if (param_idx>3) return JS_TRUE;
1715 if (param_idx<2) {
1716 pt = &p->pts[pt_idx - 1];
1717 return JS_NewFloat64(c, param_idx ? pt->y : pt->x);
1718 } else {
1719 param_idx-=2;
1720 pt = &p->pts[pt_idx];
1721 return JS_NewFloat64(c, param_idx ? pt->y : pt->x);
1722 }
1723 return JS_TRUE;
1724 /*spec is quite obscur here*/
1725 case 6:
1726 return JS_NewFloat64(c, 0);
1727 }
1728 return JS_EXCEPTION;
1729 }
1730
svg_path_realloc_pts(pathCI * p,u32 nb_pts)1731 static u32 svg_path_realloc_pts(pathCI *p, u32 nb_pts)
1732 {
1733 u32 i, orig_pts;
1734 orig_pts = 0;
1735 for (i=0; i<p->nb_coms; i++) {
1736 switch (p->tags[i]) {
1737 case 0:
1738 orig_pts++;
1739 break;
1740 case 1:
1741 orig_pts++;
1742 break;
1743 case 2:
1744 orig_pts+=3;
1745 break;
1746 case 3:
1747 orig_pts+=2;
1748 break;
1749 case 4:
1750 orig_pts+=2;
1751 break;
1752 case 5:
1753 orig_pts+=1;
1754 break;
1755 }
1756 }
1757 p->pts = (ptCI *)gf_realloc(p->pts, sizeof(ptCI)*(nb_pts+orig_pts));
1758 return orig_pts;
1759 }
1760
svg_path_move_to(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1761 static JSValue svg_path_move_to(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1762 {
1763 pathCI *p;
1764 Double x, y;
1765 u32 nb_pts;
1766
1767 p = (pathCI *) JS_GetOpaque(obj, pathClass.class_id);
1768 if (!p || (argc!=2)) return JS_EXCEPTION;
1769
1770 if (JS_ToFloat64(c, &x, argv[0])) return JS_EXCEPTION;
1771 if (JS_ToFloat64(c, &y, argv[1])) return JS_EXCEPTION;
1772 nb_pts = svg_path_realloc_pts(p, 1);
1773 p->pts[nb_pts].x = (Float) x;
1774 p->pts[nb_pts].y = (Float) y;
1775 p->tags = (u8 *)gf_realloc(p->tags, sizeof(u8)*(p->nb_coms+1) );
1776 p->tags[p->nb_coms] = 0;
1777 p->nb_coms++;
1778 return JS_TRUE;
1779 }
1780
svg_path_line_to(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1781 static JSValue svg_path_line_to(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1782 {
1783 pathCI *p;
1784 Double x, y;
1785 u32 nb_pts;
1786 p = (pathCI *) JS_GetOpaque(obj, pathClass.class_id);
1787 if (!p || (argc!=2)) return JS_EXCEPTION;
1788
1789 if (JS_ToFloat64(c, &x, argv[0])) return JS_EXCEPTION;
1790 if (JS_ToFloat64(c, &y, argv[1])) return JS_EXCEPTION;
1791
1792 nb_pts = svg_path_realloc_pts(p, 1);
1793 p->pts[nb_pts].x = (Float) x;
1794 p->pts[nb_pts].y = (Float) y;
1795 p->tags = (u8 *)gf_realloc(p->tags, sizeof(u8)*(p->nb_coms+1) );
1796 p->tags[p->nb_coms] = 1;
1797 p->nb_coms++;
1798 return JS_TRUE;
1799 }
1800
svg_path_quad_to(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1801 static JSValue svg_path_quad_to(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1802 {
1803 pathCI *p;
1804 Double x1, y1, x2, y2;
1805 u32 nb_pts;
1806
1807 p = (pathCI *) JS_GetOpaque(obj, pathClass.class_id);
1808 if (!p || (argc!=4)) return JS_EXCEPTION;
1809
1810 if (JS_ToFloat64(c, &x1, argv[0])) return JS_EXCEPTION;
1811 if (JS_ToFloat64(c, &y1, argv[1])) return JS_EXCEPTION;
1812 if (JS_ToFloat64(c, &x2, argv[2])) return JS_EXCEPTION;
1813 if (JS_ToFloat64(c, &y2, argv[3])) return JS_EXCEPTION;
1814 nb_pts = svg_path_realloc_pts(p, 2);
1815 p->pts[nb_pts].x = (Float) x1;
1816 p->pts[nb_pts].y = (Float) y1;
1817 p->pts[nb_pts+1].x = (Float) x2;
1818 p->pts[nb_pts+1].y = (Float) y2;
1819 p->tags = (u8 *)gf_realloc(p->tags, sizeof(u8)*(p->nb_coms+1) );
1820 p->tags[p->nb_coms] = 4;
1821 p->nb_coms++;
1822 return JS_TRUE;
1823 }
1824
svg_path_curve_to(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1825 static JSValue svg_path_curve_to(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1826 {
1827 pathCI *p;
1828 Double x1, y1, x2, y2, x, y;
1829 u32 nb_pts;
1830
1831 p = (pathCI *) JS_GetOpaque(obj, pathClass.class_id);
1832 if (!p || (argc!=6)) return JS_EXCEPTION;
1833
1834 if (JS_ToFloat64(c, &x1, argv[0])) return JS_EXCEPTION;
1835 if (JS_ToFloat64(c, &y1, argv[1])) return JS_EXCEPTION;
1836 if (JS_ToFloat64(c, &x2, argv[2])) return JS_EXCEPTION;
1837 if (JS_ToFloat64(c, &y2, argv[3])) return JS_EXCEPTION;
1838 if (JS_ToFloat64(c, &x, argv[4])) return JS_EXCEPTION;
1839 if (JS_ToFloat64(c, &y, argv[5])) return JS_EXCEPTION;
1840 nb_pts = svg_path_realloc_pts(p, 3);
1841 p->pts[nb_pts].x = (Float) x1;
1842 p->pts[nb_pts].y = (Float) y1;
1843 p->pts[nb_pts+1].x = (Float) x2;
1844 p->pts[nb_pts+1].y = (Float) y2;
1845 p->pts[nb_pts+2].x = (Float) x;
1846 p->pts[nb_pts+2].y = (Float) y;
1847 p->tags = (u8 *)gf_realloc(p->tags, sizeof(u8)*(p->nb_coms+1) );
1848 p->tags[p->nb_coms] = 2;
1849 p->nb_coms++;
1850 return JS_TRUE;
1851 }
1852
svg_path_close(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1853 static JSValue svg_path_close(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1854 {
1855 pathCI *p = (pathCI *) JS_GetOpaque(obj, pathClass.class_id);
1856 if (!p) return JS_EXCEPTION;
1857
1858 p->tags = (u8 *)gf_realloc(p->tags, sizeof(u8)*(p->nb_coms+1) );
1859 p->tags[p->nb_coms] = 6;
1860 p->nb_coms++;
1861 return JS_TRUE;
1862 }
1863
1864
matrix_getProperty(JSContext * c,JSValueConst obj,int magic)1865 static JSValue matrix_getProperty(JSContext *c, JSValueConst obj, int magic)
1866 {
1867 GF_Matrix2D *mx = (GF_Matrix2D *) JS_GetOpaque(obj, matrixClass.class_id);
1868 if (!mx) return JS_EXCEPTION;
1869
1870 switch (magic) {
1871 case 0: return JS_NewFloat64(c, FIX2FLT(mx->m[0]));
1872 case 1: return JS_NewFloat64(c, FIX2FLT(mx->m[3]));
1873 case 2: return JS_NewFloat64(c, FIX2FLT(mx->m[1]));
1874 case 3: return JS_NewFloat64(c, FIX2FLT(mx->m[4]));
1875 case 4: return JS_NewFloat64(c, FIX2FLT(mx->m[2]));
1876 case 5: return JS_NewFloat64(c, FIX2FLT(mx->m[5]));
1877 default:
1878 return JS_EXCEPTION;
1879 }
1880 }
1881
matrix_setProperty(JSContext * c,JSValueConst obj,JSValueConst value,int magic)1882 static JSValue matrix_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
1883 {
1884 Double d;
1885 GF_Matrix2D *mx = (GF_Matrix2D *) JS_GetOpaque(obj, matrixClass.class_id);
1886 if (!mx) return JS_EXCEPTION;
1887 if (JS_ToFloat64(c, &d, value)) return JS_EXCEPTION;
1888
1889 switch (magic) {
1890 case 0:
1891 mx->m[0] = FLT2FIX(d);
1892 break;
1893 case 1:
1894 mx->m[3] = FLT2FIX(d);
1895 break;
1896 case 2:
1897 mx->m[1] = FLT2FIX(d);
1898 break;
1899 case 3:
1900 mx->m[4] = FLT2FIX(d);
1901 break;
1902 case 4:
1903 mx->m[2] = FLT2FIX(d);
1904 break;
1905 case 5:
1906 mx->m[5] = FLT2FIX(d);
1907 break;
1908 default:
1909 break;
1910 }
1911 return JS_EXCEPTION;
1912 }
1913
svg_mx2d_get_component(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1914 static JSValue svg_mx2d_get_component(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1915 {
1916 u32 comp;
1917 GF_Matrix2D *mx = (GF_Matrix2D *) JS_GetOpaque(obj, matrixClass.class_id);
1918 if (!mx || (argc!=1)) return JS_EXCEPTION;
1919 if (JS_ToInt32(c, &comp, argv[0])) return JS_EXCEPTION;
1920
1921 switch (comp) {
1922 case 0: return JS_NewFloat64(c, FIX2FLT(mx->m[0]));
1923 case 1: return JS_NewFloat64(c, FIX2FLT(mx->m[3]));
1924 case 2: return JS_NewFloat64(c, FIX2FLT(mx->m[1]));
1925 case 3: return JS_NewFloat64(c, FIX2FLT(mx->m[4]));
1926 case 4: return JS_NewFloat64(c, FIX2FLT(mx->m[2]));
1927 case 5: return JS_NewFloat64(c, FIX2FLT(mx->m[5]));
1928 }
1929 return JS_EXCEPTION;
1930 }
1931
svg_mx2d_multiply(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1932 static JSValue svg_mx2d_multiply(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1933 {
1934 GF_Matrix2D *mx1, *mx2;
1935 mx1 = (GF_Matrix2D *) JS_GetOpaque(obj, matrixClass.class_id);
1936 if (!mx1 || (argc!=1)) return JS_EXCEPTION;
1937 mx2 = (GF_Matrix2D *) JS_GetOpaque(argv[0], matrixClass.class_id);
1938 if (!mx2) return JS_EXCEPTION;
1939
1940 gf_mx2d_add_matrix(mx1, mx2);
1941 return JS_DupValue(c, obj);
1942 }
1943
svg_mx2d_inverse(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1944 static JSValue svg_mx2d_inverse(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1945 {
1946 GF_Matrix2D *mx = (GF_Matrix2D *) JS_GetOpaque(obj, matrixClass.class_id);
1947 if (!mx) return JS_EXCEPTION;
1948 gf_mx2d_inverse(mx);
1949 return JS_DupValue(c, obj);
1950 }
1951
svg_mx2d_translate(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1952 static JSValue svg_mx2d_translate(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1953 {
1954 Double x, y;
1955 GF_Matrix2D *mx1, mx2;
1956 mx1 = (GF_Matrix2D *) JS_GetOpaque(obj, matrixClass.class_id);
1957 if (!mx1 || (argc!=2)) return JS_EXCEPTION;
1958
1959 if (JS_ToFloat64(c, &x, argv[0]) || JS_ToFloat64(c, &y, argv[1])) return JS_EXCEPTION;
1960
1961 gf_mx2d_init(mx2);
1962 mx2.m[2] = FLT2FIX(x);
1963 mx2.m[5] = FLT2FIX(y);
1964 gf_mx2d_pre_multiply(mx1, &mx2);
1965 return JS_DupValue(c, obj);
1966 }
1967
svg_mx2d_scale(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1968 static JSValue svg_mx2d_scale(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1969 {
1970 Double scale;
1971 GF_Matrix2D *mx1, mx2;
1972 mx1 = (GF_Matrix2D *) JS_GetOpaque(obj, matrixClass.class_id);
1973 if (!mx1 || (argc!=2)) return JS_EXCEPTION;
1974 if (!JS_ToFloat64(c, &scale, argv[0])) return JS_EXCEPTION;
1975
1976 gf_mx2d_init(mx2);
1977 mx2.m[0] = mx2.m[4] = FLT2FIX(scale);
1978 gf_mx2d_pre_multiply(mx1, &mx2);
1979 return JS_DupValue(c, obj);
1980 }
1981
svg_mx2d_rotate(JSContext * c,JSValueConst obj,int argc,JSValueConst * argv)1982 static JSValue svg_mx2d_rotate(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1983 {
1984 Double angle;
1985 GF_Matrix2D *mx1, mx2;
1986
1987 mx1 = (GF_Matrix2D *) JS_GetOpaque(obj, matrixClass.class_id);
1988 if (!mx1 || (argc!=2)) return JS_EXCEPTION;
1989 if (!JS_ToFloat64(c, &angle, argv[0])) return JS_EXCEPTION;
1990
1991 gf_mx2d_init(mx2);
1992 gf_mx2d_add_rotation(&mx2, 0, 0, gf_mulfix(FLT2FIX(angle/180), GF_PI));
1993 gf_mx2d_pre_multiply(mx1, &mx2);
1994 return JS_DupValue(c, obj);
1995 }
1996
svg_udom_new_rect(JSContext * c,Fixed x,Fixed y,Fixed width,Fixed height)1997 JSValue svg_udom_new_rect(JSContext *c, Fixed x, Fixed y, Fixed width, Fixed height)
1998 {
1999 rectCI *rc = (rectCI *)gf_malloc(sizeof(rectCI));
2000 if (!rc) return JS_EXCEPTION;
2001 JSValue r = JS_NewObjectClass(c, rectClass.class_id);
2002 rc->x = FIX2FLT(x);
2003 rc->y = FIX2FLT(y);
2004 rc->w = FIX2FLT(width);
2005 rc->h = FIX2FLT(height);
2006 rc->sg = NULL;
2007 JS_SetOpaque(r, rc);
2008 return r;
2009 }
2010
svg_udom_new_point(JSContext * c,Fixed x,Fixed y)2011 JSValue svg_udom_new_point(JSContext *c, Fixed x, Fixed y)
2012 {
2013 pointCI *pt = (pointCI *)gf_malloc(sizeof(pointCI));
2014 if (!pt) return JS_EXCEPTION;
2015 JSValue p = JS_NewObjectClass(c, pointClass.class_id);
2016 pt->x = FIX2FLT(x);
2017 pt->y = FIX2FLT(y);
2018 pt->sg = NULL;
2019 JS_SetOpaque(p, pt);
2020 return p;
2021 }
2022
2023 #ifdef GPAC_ENABLE_HTML5_MEDIA
2024 void *html_get_element_class(GF_Node *n);
2025 #endif
2026
svg_get_element_class(GF_Node * n)2027 JSClassID svg_get_element_class(GF_Node *n)
2028 {
2029 if (!n) return 0;
2030 if ((n->sgprivate->tag>=GF_NODE_RANGE_FIRST_SVG) && (n->sgprivate->tag<=GF_NODE_RANGE_LAST_SVG)) {
2031 #ifdef GPAC_ENABLE_HTML5_MEDIA
2032 if (n->sgprivate->tag == TAG_SVG_video || n->sgprivate->tag == TAG_SVG_audio) {
2033 assert(0);
2034 return html_get_element_class(n);
2035 }
2036 #endif
2037 return svgElement.class_id;
2038 }
2039 return 0;
2040 }
svg_get_document_class(GF_SceneGraph * sg)2041 JSClassID svg_get_document_class(GF_SceneGraph *sg)
2042 {
2043 GF_Node *n = sg->RootNode;
2044 if (!n) return 0;
2045 if ((n->sgprivate->tag>=GF_NODE_RANGE_FIRST_SVG) && (n->sgprivate->tag<=GF_NODE_RANGE_LAST_SVG))
2046 return svgDocument.class_id;
2047 return 0;
2048 }
2049
is_svg_document_class(JSContext * c,JSValue obj)2050 Bool is_svg_document_class(JSContext *c, JSValue obj)
2051 {
2052 void *ptr = JS_GetOpaque(obj, svgDocument.class_id);
2053 if (ptr) return GF_TRUE;
2054 return GF_FALSE;
2055 }
2056
is_svg_element_class(JSContext * c,JSValue obj)2057 Bool is_svg_element_class(JSContext *c, JSValue obj)
2058 {
2059 void *ptr = JS_GetOpaque(obj, svgElement.class_id);
2060 if (ptr) return GF_TRUE;
2061 return GF_FALSE;
2062 }
2063
2064 #define SETUP_JSCLASS(_class, _name, _proto_funcs, _construct, _finalize, _proto_class_id) \
2065 if (!_class.class_id) {\
2066 JS_NewClassID(&(_class.class_id)); \
2067 _class.class.class_name = _name; \
2068 _class.class.finalizer = _finalize;\
2069 JS_NewClass(jsrt, _class.class_id, &(_class.class));\
2070 }\
2071 scene->svg_js->_class.proto = JS_NewObjectClass(c, _proto_class_id ? _proto_class_id : _class.class_id);\
2072 JS_SetPropertyFunctionList(c, scene->svg_js->_class.proto, _proto_funcs, countof(_proto_funcs));\
2073 JS_SetClassProto(c, _class.class_id, scene->svg_js->_class.proto);\
2074 if (_construct) {\
2075 scene->svg_js->_class.ctor = JS_NewCFunction2(c, _construct, _name, 1, JS_CFUNC_constructor, 0);\
2076 JS_SetPropertyStr(c, global, _name, scene->svg_js->_class.ctor);\
2077 }\
2078
2079
2080 static const JSCFunctionListEntry globalFuncs[] =
2081 {
2082 JS_CGETSET_MAGIC_DEF("connected", global_getProperty, NULL, 0),
2083 JS_CGETSET_MAGIC_DEF("parent", global_getProperty, NULL, 1),
2084 JS_CFUNC_DEF("createConnection", 0, svg_connection_create),
2085 JS_CFUNC_DEF("gotoLocation", 1, svg_nav_to_location),
2086 JS_CFUNC_DEF("alert", 0, js_print),
2087 JS_CFUNC_DEF("print", 0, js_print),
2088 JS_CFUNC_DEF("hasFeature", 2, dom_imp_has_feature),
2089 JS_CFUNC_DEF("parseXML", 0, svg_parse_xml),
2090 };
2091
2092 static const JSCFunctionListEntry documentFuncs[] =
2093 {
2094 JS_CGETSET_MAGIC_DEF("defaultView", svg_doc_getProperty, NULL, 0),
2095 };
2096
2097 static const JSCFunctionListEntry svg_elementFuncs[] =
2098 {
2099 JS_CGETSET_MAGIC_DEF("id", svg_element_getProperty, svg_element_setProperty, 0),
2100 /*svgSVGElement interface*/
2101 JS_CGETSET_MAGIC_DEF("currentScale", svg_element_getProperty, svg_element_setProperty, 5),
2102 JS_CGETSET_MAGIC_DEF("currentRotate", svg_element_getProperty, svg_element_setProperty, 6),
2103 JS_CGETSET_MAGIC_DEF("currentTranslate", svg_element_getProperty, svg_element_setProperty, 7),
2104 JS_CGETSET_MAGIC_DEF("viewport", svg_element_getProperty, NULL, 8),
2105 JS_CGETSET_MAGIC_DEF("currentTime", svg_element_getProperty, svg_element_setProperty, 9),
2106 /*timeControl interface*/
2107 JS_CGETSET_MAGIC_DEF("isPaused", svg_element_getProperty, NULL, 10),
2108 /*old SVG1.1 stuff*/
2109 JS_CGETSET_MAGIC_DEF("ownerSVGElement", svg_element_getProperty, NULL, 11),
2110 /*SVGElementInstance*/
2111 JS_CGETSET_MAGIC_DEF("correspondingElement", svg_element_getProperty, NULL, 12),
2112 JS_CGETSET_MAGIC_DEF("correspondingUseElement", svg_element_getProperty, NULL, 13),
2113
2114 /*trait access interface*/
2115 JS_CFUNC_DEF("getTrait", 1, svg_udom_get_trait),
2116 JS_CFUNC_DEF("getTraitNS", 2, svg_udom_get_trait),
2117 JS_CFUNC_DEF("getFloatTrait", 1, svg_udom_get_float_trait),
2118 JS_CFUNC_DEF("getMatrixTrait", 1, svg_udom_get_matrix_trait),
2119 JS_CFUNC_DEF("getRectTrait", 1, svg_udom_get_rect_trait),
2120 JS_CFUNC_DEF("getPathTrait", 1, svg_udom_get_path_trait),
2121 JS_CFUNC_DEF("getRGBColorTrait", 1, svg_udom_get_rgb_color_trait),
2122 /*FALLBACK TO BASE-VALUE FOR NOW - WILL NEED EITHER DOM TREE-CLONING OR A FAKE RENDER
2123 PASS FOR EACH PRESENTATION VALUE ACCESS*/
2124 JS_CFUNC_DEF("getPresentationTrait", 1, svg_udom_get_trait),
2125 JS_CFUNC_DEF("getPresentationTraitNS", 2, svg_udom_get_trait),
2126 JS_CFUNC_DEF("getFloatPresentationTrait", 1, svg_udom_get_float_trait),
2127 JS_CFUNC_DEF("getMatrixPresentationTrait", 1, svg_udom_get_matrix_trait),
2128 JS_CFUNC_DEF("getRectPresentationTrait", 1, svg_udom_get_rect_trait),
2129 JS_CFUNC_DEF("getPathPresentationTrait", 1, svg_udom_get_path_trait),
2130 JS_CFUNC_DEF("getRGBColorPresentationTrait", 1, svg_udom_get_rgb_color_trait),
2131 JS_CFUNC_DEF("setTrait", 2, svg_udom_set_trait),
2132 JS_CFUNC_DEF("setTraitNS", 3, svg_udom_set_trait),
2133 JS_CFUNC_DEF("setFloatTrait", 2, svg_udom_set_float_trait),
2134 JS_CFUNC_DEF("setMatrixTrait", 2, svg_udom_set_matrix_trait),
2135 JS_CFUNC_DEF("setRectTrait", 2, svg_udom_set_rect_trait),
2136 JS_CFUNC_DEF("setPathTrait", 2, svg_udom_set_path_trait),
2137 JS_CFUNC_DEF("setRGBColorTrait", 2, svg_udom_set_rgb_color_trait),
2138 /*locatable interface*/
2139 JS_CFUNC_DEF("getBBox", 0, svg_udom_get_local_bbox),
2140 JS_CFUNC_DEF("getScreenCTM", 0, svg_udom_get_screen_ctm),
2141 JS_CFUNC_DEF("getScreenBBox", 0, svg_udom_get_screen_bbox),
2142 /*svgSVGElement interface*/
2143 JS_CFUNC_DEF("createSVGMatrixComponents", 0, svg_udom_create_matrix_components),
2144 JS_CFUNC_DEF("createSVGRect", 0, svg_udom_create_rect),
2145 JS_CFUNC_DEF("createSVGPath", 0, svg_udom_create_path),
2146 JS_CFUNC_DEF("createSVGRGBColor", 0, svg_udom_create_color),
2147 JS_CFUNC_DEF("createSVGPoint", 0, svg_udom_create_point),
2148 JS_CFUNC_DEF("moveFocus", 0, svg_udom_move_focus),
2149 JS_CFUNC_DEF("setFocus", 0, svg_udom_set_focus),
2150 JS_CFUNC_DEF("getCurrentFocusedObject", 0, svg_udom_get_focus),
2151 JS_CFUNC_DEF("getCurrentTime", 0, svg_udom_get_time),
2152
2153 /*timeControl interface*/
2154 JS_CFUNC_DEF("beginElementAt", 1, svg_udom_smil_begin),
2155 JS_CFUNC_DEF("beginElement", 0, svg_udom_smil_begin),
2156 JS_CFUNC_DEF("endElementAt", 1, svg_udom_smil_end),
2157 JS_CFUNC_DEF("endElement", 0, svg_udom_smil_end),
2158 JS_CFUNC_DEF("pauseElement", 0, svg_udom_smil_pause),
2159 JS_CFUNC_DEF("resumeElement", 0, svg_udom_smil_resume),
2160 JS_CFUNC_DEF("restartElement", 0, svg_udom_smil_restart),
2161 JS_CFUNC_DEF("setSpeed", 0, svg_udom_smil_set_speed),
2162 JS_CFUNC_DEF("getTotalLength", 0, svg_path_get_total_length)
2163 };
2164
2165 /*RGBColor class*/
2166 static const JSCFunctionListEntry rgb_Funcs[] =
2167 {
2168 JS_CGETSET_MAGIC_DEF("red", rgb_getProperty, rgb_setProperty, 0),
2169 JS_CGETSET_MAGIC_DEF("green", rgb_getProperty, rgb_setProperty, 1),
2170 JS_CGETSET_MAGIC_DEF("blue", rgb_getProperty, rgb_setProperty, 2),
2171 };
2172
2173 /*SVGRect class*/
2174 static const JSCFunctionListEntry rect_Funcs[] =
2175 {
2176 JS_CGETSET_MAGIC_DEF("x", rect_getProperty, rect_setProperty, 0),
2177 JS_CGETSET_MAGIC_DEF("y", rect_getProperty, rect_setProperty, 1),
2178 JS_CGETSET_MAGIC_DEF("width", rect_getProperty, rect_setProperty, 2),
2179 JS_CGETSET_MAGIC_DEF("height", rect_getProperty, rect_setProperty, 3),
2180 };
2181
2182 /*SVGPoint class*/
2183 static const JSCFunctionListEntry point_Funcs[] =
2184 {
2185 JS_CGETSET_MAGIC_DEF("x", point_getProperty, point_setProperty, 0),
2186 JS_CGETSET_MAGIC_DEF("y", point_getProperty, point_setProperty, 1)
2187 };
2188
2189 /*SVGMatrix class*/
2190 static const JSCFunctionListEntry matrix_Funcs[] =
2191 {
2192 JS_CGETSET_MAGIC_DEF("a", matrix_getProperty, matrix_setProperty, 0),
2193 JS_CGETSET_MAGIC_DEF("b", matrix_getProperty, matrix_setProperty, 1),
2194 JS_CGETSET_MAGIC_DEF("c", matrix_getProperty, matrix_setProperty, 2),
2195 JS_CGETSET_MAGIC_DEF("d", matrix_getProperty, matrix_setProperty, 3),
2196 JS_CGETSET_MAGIC_DEF("e", matrix_getProperty, matrix_setProperty, 4),
2197 JS_CGETSET_MAGIC_DEF("f", matrix_getProperty, matrix_setProperty, 5),
2198
2199 JS_CFUNC_DEF("getComponent", 1, svg_mx2d_get_component),
2200 JS_CFUNC_DEF("mMultiply", 1, svg_mx2d_multiply),
2201 JS_CFUNC_DEF("inverse", 0, svg_mx2d_inverse),
2202 JS_CFUNC_DEF("mTranslate", 2, svg_mx2d_translate),
2203 JS_CFUNC_DEF("mScale", 1, svg_mx2d_scale),
2204 JS_CFUNC_DEF("mRotate", 1, svg_mx2d_rotate),
2205 };
2206
2207 /*SVGPath class*/
2208 static const JSCFunctionListEntry path_Funcs[] =
2209 {
2210 JS_CGETSET_MAGIC_DEF("numberOfSegments", path_getProperty, NULL, 0),
2211 JS_CFUNC_DEF("getSegment", 1, svg_path_get_segment),
2212 JS_CFUNC_DEF("getSegmentParam", 2, svg_path_get_segment_param),
2213 JS_CFUNC_DEF("moveTo", 2, svg_path_move_to),
2214 JS_CFUNC_DEF("lineTo", 2, svg_path_line_to),
2215 JS_CFUNC_DEF("quadTo", 4, svg_path_quad_to),
2216 JS_CFUNC_DEF("curveTo", 6, svg_path_curve_to),
2217 JS_CFUNC_DEF("close", 0, svg_path_close),
2218 };
2219
2220 JSClassID dom_js_get_element_proto(struct JSContext *c);
2221 JSClassID dom_js_get_document_proto(JSContext *c);
2222
2223 /*defines a new global object "document" of type Document*/
2224 void dom_js_define_document(struct JSContext *c, JSValue global, GF_SceneGraph *doc);
2225
2226 void domDocument_gc_mark(JSRuntime *rt, JSValueConst obj, JS_MarkFunc *mark_func);
2227 void domElement_gc_mark(JSRuntime *rt, JSValueConst obj, JS_MarkFunc *mark_func);
2228
svg_init_js_api(GF_SceneGraph * scene)2229 static void svg_init_js_api(GF_SceneGraph *scene)
2230 {
2231 JSContext *c = scene->svg_js->js_ctx;
2232 JSRuntime *jsrt = JS_GetRuntime(c);
2233 JSValue global = JS_GetGlobalObject(scene->svg_js->js_ctx);
2234
2235 SETUP_JSCLASS(svg_globalClass, "Window", globalFuncs, NULL, NULL, 0);
2236 scene->svg_js->global = JS_NewObjectClass(c, svg_globalClass.class_id);
2237 JS_SetOpaque(scene->svg_js->global, scene);
2238 JS_SetPropertyStr(c, global, "Window", scene->svg_js->global);
2239
2240 JS_SetPropertyStr(c, global, "alert", JS_NewCFunction(c, js_print, "alert", 1));
2241
2242 /*initialize DOM core */
2243 dom_js_load(scene, scene->svg_js->js_ctx);
2244
2245 qjs_module_init_xhr_global(c, global);
2246
2247 svg_define_udom_exception(scene->svg_js->js_ctx, scene->svg_js->global);
2248 JSValue console = JS_NewObject(c);
2249 JS_SetPropertyStr(c, console, "log", JS_NewCFunction(c, js_print, "print", 1));
2250 JS_SetPropertyStr(c, global, "console", console);
2251
2252 svgDocument.class.gc_mark = domDocument_gc_mark;
2253 SETUP_JSCLASS(svgDocument, "SVGDocument", documentFuncs, NULL, dom_document_finalize, dom_js_get_document_proto(c));
2254 svgElement.class.gc_mark = domElement_gc_mark;
2255 SETUP_JSCLASS(svgElement, "SVGElement", svg_elementFuncs, NULL, dom_element_finalize, dom_js_get_element_proto(c));
2256
2257 SETUP_JSCLASS(rgbClass, "SVGRGBColor", rgb_Funcs, NULL, baseCI_finalize, 0);
2258 SETUP_JSCLASS(rectClass, "SVGRect", rect_Funcs, NULL, baseCI_finalize, 0);
2259 SETUP_JSCLASS(pointClass, "SVGPoint", point_Funcs, NULL, baseCI_finalize, 0);
2260 SETUP_JSCLASS(matrixClass, "SVGMatrix", matrix_Funcs, NULL, baseCI_finalize, 0);
2261
2262 SETUP_JSCLASS(pathClass, "SVGPath", path_Funcs, NULL, pathCI_finalize, 0);
2263
2264
2265 JS_SetPropertyStr(c, scene->svg_js->pathClass.proto, "MOVE_TO", JS_NewInt32(c, 77));
2266 JS_SetPropertyStr(c, scene->svg_js->pathClass.proto, "LINE_TO", JS_NewInt32(c, 76));
2267 JS_SetPropertyStr(c, scene->svg_js->pathClass.proto, "CURVE_TO", JS_NewInt32(c, 67));
2268 JS_SetPropertyStr(c, scene->svg_js->pathClass.proto, "QUAD_TO", JS_NewInt32(c, 81));
2269 JS_SetPropertyStr(c, scene->svg_js->pathClass.proto, "CLOSE", JS_NewInt32(c, 90));
2270
2271 /*we have our own constructors*/
2272 scene->get_element_class = svg_get_element_class;
2273 scene->get_document_class = svg_get_document_class;
2274
2275 /*create document object*/
2276 dom_js_define_document(scene->svg_js->js_ctx, global, scene);
2277 /*create event object, and remember it*/
2278 scene->svg_js->event = dom_js_define_event(scene->svg_js->js_ctx);
2279
2280 JS_FreeValue(c, global);
2281 }
2282
2283 GF_DOM_Event *dom_get_evt_private(JSValue v);
2284
svg_script_get_context(GF_SceneGraph * sg)2285 JSContext *svg_script_get_context(GF_SceneGraph *sg)
2286 {
2287 return sg->svg_js ? sg->svg_js->js_ctx : NULL;
2288 }
2289
svg_script_execute(GF_SceneGraph * sg,char * utf8_script,GF_DOM_Event * event)2290 Bool svg_script_execute(GF_SceneGraph *sg, char *utf8_script, GF_DOM_Event *event)
2291 {
2292 char szFuncName[1024];
2293 JSValue ret;
2294 Bool ok=GF_TRUE;
2295 GF_DOM_Event *prev_event = NULL;
2296 char *sep = strchr(utf8_script, '(');
2297
2298 if (!sep) {
2299 strcpy(szFuncName, utf8_script);
2300 strcat(szFuncName, "(evt)");
2301 utf8_script = szFuncName;
2302 }
2303
2304 gf_js_lock(sg->svg_js->js_ctx, GF_TRUE);
2305
2306 prev_event = dom_get_evt_private(sg->svg_js->event);
2307 JS_SetOpaque(sg->svg_js->event, event);
2308 ret = JS_Eval(sg->svg_js->js_ctx, utf8_script, (u32) strlen(utf8_script), "inline script", sg->svg_js->use_strict ? JS_EVAL_TYPE_MODULE : JS_EVAL_TYPE_GLOBAL);
2309 JS_SetOpaque(sg->svg_js->event, prev_event);
2310
2311 #if 0
2312 //to check, what was the purpose of this ?
2313 if (ret==JS_FALSE) {
2314 char *sep = strchr(utf8_script, '(');
2315 if (sep) {
2316 sep[0] = 0;
2317 ret = JS_LookupProperty(sg->svg_js->js_ctx, sg->svg_js->global, utf8_script, &rval);
2318 sep[0] = '(';
2319 }
2320 }
2321 #endif
2322
2323 if (JS_IsException(ret)) {
2324 js_dump_error(sg->svg_js->js_ctx);
2325 ok=GF_FALSE;
2326 }
2327 JS_FreeValue(sg->svg_js->js_ctx, ret);
2328
2329 if (sg->svg_js->force_gc) {
2330 gf_js_call_gc(sg->svg_js->js_ctx);
2331 sg->svg_js->force_gc = GF_FALSE;
2332 }
2333 js_do_loop(sg->svg_js->js_ctx);
2334 gf_js_lock(sg->svg_js->js_ctx, GF_FALSE);
2335
2336 return ok;
2337 }
2338
2339 #ifdef GPAC_ENABLE_HTML5_MEDIA
2340 void html_media_js_api_del();
2341 #endif
2342
gf_svg_script_context_del(GF_SVGJS * svg_js,GF_SceneGraph * scenegraph)2343 void gf_svg_script_context_del(GF_SVGJS *svg_js, GF_SceneGraph *scenegraph)
2344 {
2345 gf_sg_js_dom_pre_destroy(JS_GetRuntime(svg_js->js_ctx), scenegraph, NULL);
2346 gf_js_delete_context(svg_js->js_ctx);
2347 dom_js_unload();
2348 #ifdef GPAC_ENABLE_HTML5_MEDIA
2349 /* HTML */
2350 html_media_js_api_del();
2351 #endif
2352
2353 gf_free(svg_js);
2354 scenegraph->svg_js = NULL;
2355
2356 }
2357
svg_script_predestroy(GF_Node * n,void * eff,Bool is_destroy)2358 static void svg_script_predestroy(GF_Node *n, void *eff, Bool is_destroy)
2359 {
2360 if (is_destroy) {
2361 GF_SVGJS *svg_js = n->sgprivate->scenegraph->svg_js;
2362 /*unregister script from parent scene (cf base_scenegraph::sg_reset) */
2363 gf_list_del_item(n->sgprivate->scenegraph->scripts, n);
2364
2365 if (svg_js->nb_scripts) {
2366 svg_js->nb_scripts--;
2367
2368 /*detach this script from our object cache*/
2369 gf_sg_js_dom_pre_destroy(JS_GetRuntime(svg_js->js_ctx), n->sgprivate->scenegraph, n);
2370
2371 if (!svg_js->nb_scripts) {
2372 gf_svg_script_context_del(svg_js, n->sgprivate->scenegraph);
2373 }
2374 }
2375 }
2376 }
2377
JSScript_CreateSVGContext(GF_SceneGraph * sg)2378 GF_Err JSScript_CreateSVGContext(GF_SceneGraph *sg)
2379 {
2380 GF_SVGJS *svg_js;
2381
2382 if (sg->svg_js) {
2383 /* the JS/SVG context is already created, no need to do anything */
2384 return GF_OK;
2385 }
2386
2387 GF_SAFEALLOC(svg_js, GF_SVGJS);
2388 if (!svg_js) {
2389 return GF_OUT_OF_MEM;
2390 }
2391 /*create new ecmascript context*/
2392 svg_js->js_ctx = gf_js_create_context();
2393 if (!svg_js->js_ctx) {
2394 gf_free(svg_js);
2395 return GF_SCRIPT_ERROR;
2396 }
2397
2398 gf_js_lock(svg_js->js_ctx, GF_TRUE);
2399
2400 sg->svg_js = svg_js;
2401 /*load SVG & DOM APIs*/
2402 svg_init_js_api(sg);
2403
2404 #ifdef GPAC_ENABLE_HTML5_MEDIA
2405 /* HTML */
2406 html_media_init_js_api(sg);
2407 #endif
2408
2409
2410 svg_js->script_execute = svg_script_execute;
2411 svg_js->handler_execute = svg_script_execute_handler;
2412
2413 gf_js_lock(svg_js->js_ctx, GF_FALSE);
2414
2415 return GF_OK;
2416 }
2417
svg_get_text_child(GF_Node * node)2418 GF_DOMText *svg_get_text_child(GF_Node *node)
2419 {
2420 GF_ChildNodeItem *child;
2421 GF_DOMText *txt;
2422 txt = NULL;
2423 child = ((SVG_Element*)node)->children;
2424 if (! child) return NULL;
2425 while (child) {
2426 txt = (GF_DOMText*)child->node;
2427 if ((txt->sgprivate->tag==TAG_DOMText) && txt->textContent) return txt;
2428 txt = NULL;
2429 child = child->next;
2430 }
2431 return NULL;
2432 }
2433
svg_js_load_script(GF_Node * script,char * file)2434 static Bool svg_js_load_script(GF_Node *script, char *file)
2435 {
2436 GF_Err e;
2437 u8 *jsscript;
2438 u32 fsize;
2439 Bool success = GF_TRUE;
2440 JSValue ret;
2441 GF_SVGJS *svg_js;
2442 u32 flags = JS_EVAL_TYPE_GLOBAL;
2443 char *abs_url = NULL;
2444
2445 svg_js = script->sgprivate->scenegraph->svg_js;
2446 if (!strnicmp(file, "file://", 7)) file += 7;
2447
2448 if (!gf_file_exists(file)) {
2449 GF_JSAPIParam par;
2450 GF_SceneGraph *scene = script->sgprivate->scenegraph;
2451 par.uri.url = file;
2452 if (scene->script_action && scene->script_action(scene->script_action_cbck, GF_JSAPI_OP_RESOLVE_XLINK, script, &par))
2453 abs_url = (char *) par.uri.url;
2454
2455 if (abs_url || !gf_file_exists(abs_url)) {
2456 if (abs_url) gf_free(abs_url);
2457 return GF_FALSE;
2458 }
2459 }
2460
2461 e = gf_file_load_data(abs_url ? abs_url : file, &jsscript, &fsize);
2462 if (abs_url) gf_free(abs_url);
2463
2464 if (e!=GF_OK) return GF_FALSE;
2465
2466 /*for handler, only load code*/
2467 if (script->sgprivate->tag==TAG_SVG_handler) {
2468 GF_DOMText *txt = gf_dom_add_text_node(script, jsscript);
2469 txt->type = GF_DOM_TEXT_INSERTED;
2470 return GF_TRUE;
2471 }
2472
2473 gf_js_lock(svg_js->js_ctx, GF_TRUE);
2474
2475 if (!gf_opts_get_bool("core", "no-js-mods") && JS_DetectModule((const char *) jsscript, fsize )) {
2476 flags = JS_EVAL_TYPE_MODULE;
2477 svg_js->use_strict = GF_TRUE;
2478 }
2479
2480 ret = JS_Eval(svg_js->js_ctx, jsscript, sizeof(char)*fsize, file, flags);
2481 if (JS_IsException(ret)) {
2482 js_dump_error(svg_js->js_ctx);
2483 success=GF_FALSE;
2484 }
2485 JS_FreeValue(svg_js->js_ctx, ret);
2486 if (svg_js->force_gc) {
2487 gf_js_call_gc(svg_js->js_ctx);
2488 svg_js->force_gc = GF_FALSE;
2489 }
2490 gf_js_lock(svg_js->js_ctx, GF_FALSE);
2491
2492 gf_dom_listener_process_add(script->sgprivate->scenegraph);
2493
2494 gf_free(jsscript);
2495 return success;
2496 }
2497
2498 #include <gpac/download.h>
2499 #include <gpac/network.h>
2500
2501
JSScript_LoadSVG(GF_Node * node)2502 void JSScript_LoadSVG(GF_Node *node)
2503 {
2504 GF_DOMText *txt;
2505 GF_SVGJS *svg_js;
2506 GF_FieldInfo href_info;
2507
2508 if (!node->sgprivate->scenegraph->svg_js) {
2509 if (JSScript_CreateSVGContext(node->sgprivate->scenegraph) != GF_OK) return;
2510 }
2511
2512 /*register script with parent scene (cf base_scenegraph::sg_reset) */
2513 gf_list_add(node->sgprivate->scenegraph->scripts, node);
2514
2515 svg_js = node->sgprivate->scenegraph->svg_js;
2516 if (!node->sgprivate->UserCallback) {
2517 svg_js->nb_scripts++;
2518 node->sgprivate->UserCallback = svg_script_predestroy;
2519 }
2520 /*if href download the script file*/
2521 if (gf_node_get_attribute_by_tag(node, TAG_XLINK_ATT_href, GF_FALSE, GF_FALSE, &href_info) == GF_OK) {
2522 GF_DownloadManager *dnld_man;
2523 GF_JSAPIParam par;
2524 char *url;
2525 GF_Err e;
2526 XMLRI *xmlri = (XMLRI *)href_info.far_ptr;
2527
2528 /* getting a download manager */
2529 par.dnld_man = NULL;
2530 ScriptAction(node->sgprivate->scenegraph, GF_JSAPI_OP_GET_DOWNLOAD_MANAGER, NULL, &par);
2531 dnld_man = par.dnld_man;
2532
2533
2534 /* resolve the uri of the script*/
2535 par.uri.nb_params = 0;
2536 par.uri.url = xmlri->string;
2537 ScriptAction(node->sgprivate->scenegraph, GF_JSAPI_OP_RESOLVE_URI, node, &par);
2538 url = (char *)par.uri.url;
2539
2540 /* if the file is local, we don't need to download it */
2541 if (!strstr(url, "://") || !strnicmp(url, "file://", 7)) {
2542 svg_js_load_script(node, url);
2543 } else if (dnld_man) {
2544 /*fetch the remote script synchronously and load it - cf section on script processing in SVG specs*/
2545 GF_DownloadSession *sess = gf_dm_sess_new(dnld_man, url, GF_NETIO_SESSION_NOT_THREADED, NULL, NULL, &e);
2546 if (sess) {
2547 e = gf_dm_sess_process(sess);
2548 if (e==GF_OK) {
2549 const char *szCache = gf_dm_sess_get_cache_name(sess);
2550 if (!svg_js_load_script(node, (char *) szCache))
2551 e = GF_SCRIPT_ERROR;
2552 }
2553 gf_dm_sess_del(sess);
2554 }
2555 if (e) {
2556 par.info.e = e;
2557 par.info.msg = "Cannot fetch script";
2558 ScriptAction(node->sgprivate->scenegraph, GF_JSAPI_OP_MESSAGE, NULL, &par);
2559 }
2560 }
2561 gf_free(url);
2562 }
2563 /*for scripts only, execute*/
2564 else if (node->sgprivate->tag == TAG_SVG_script) {
2565 JSValue ret;
2566 u32 txtlen;
2567 u32 flags = JS_EVAL_TYPE_GLOBAL;
2568
2569 txt = svg_get_text_child(node);
2570 if (!txt) return;
2571 txtlen = (u32) strlen(txt->textContent);
2572
2573 if (!gf_opts_get_bool("core", "no-js-mods") && JS_DetectModule((const char *) txt, txtlen )) {
2574 flags = JS_EVAL_TYPE_MODULE;
2575 svg_js->use_strict = GF_TRUE;
2576 }
2577
2578 ret = JS_Eval(svg_js->js_ctx, txt->textContent, (u32) strlen(txt->textContent), "inline_script", flags);
2579 if (JS_IsException(ret)) {
2580 js_dump_error(svg_js->js_ctx);
2581 }
2582 JS_FreeValue(svg_js->js_ctx, ret);
2583 gf_dom_listener_process_add(node->sgprivate->scenegraph);
2584 js_do_loop(svg_js->js_ctx);
2585 }
2586 }
2587
2588
2589 #ifdef _DEBUG
2590 //#define DUMP_DEF_AND_ROOT
2591 #endif
2592
2593 #ifdef DUMP_DEF_AND_ROOT
dump_root(const char * name,void * rp,void * data)2594 void dump_root(const char *name, void *rp, void *data)
2595 {
2596 if (name[0]=='_') fprintf(stderr, "\t%s\n", name);
2597 }
2598 #endif
2599
2600 /* Executes JavaScript code in response to an event being triggered
2601 The code to be executed (stored in a GF_DOMHandler struct) is either:
2602 - text content not yet passed to the JS engine
2603 - text contained in a node's text content not yet parsed (node)
2604 - text, outside of a node, obtained by some external means (XHR, ...) - utf8_script
2605 - already in the JS engine, in the form of:
2606 - an anonymous function (js_fun_val)
2607 - a named function (js_fun)
2608 */
svg_script_execute_handler(GF_Node * node,GF_DOM_Event * event,GF_Node * observer,char * utf8_script)2609 static Bool svg_script_execute_handler(GF_Node *node, GF_DOM_Event *event, GF_Node *observer, char *utf8_script)
2610 {
2611 GF_DOMText *txt = NULL;
2612 GF_SVGJS *svg_js;
2613 JSValue __this;
2614 JSValue ret;
2615 u32 flags = JS_EVAL_TYPE_GLOBAL;
2616 Bool success=GF_TRUE;
2617 GF_DOM_Event *prev_event = NULL;
2618 GF_DOMHandler *hdl = (GF_DOMHandler *)node;
2619
2620 /*LASeR hack for encoding scripts without handler - node is a listener in this case, not a handler*/
2621 if (utf8_script) {
2622 if (!node) return GF_FALSE;
2623 hdl = NULL;
2624 } else {
2625 if (JS_IsUndefined(hdl->js_data->fun_val) && JS_IsUndefined(hdl->js_data->evt_listen_obj)) {
2626 txt = svg_get_text_child(node);
2627 if (!txt) return GF_FALSE;
2628 }
2629 /*not sure about this (cf test struct-use-205-t.svg)*/
2630 //if (!node->sgprivate->parents) return GF_FALSE;
2631 }
2632
2633 svg_js = node->sgprivate->scenegraph->svg_js;
2634
2635 #ifndef GPAC_DISABLE_LOG
2636 if (gf_log_tool_level_on(GF_LOG_SCRIPT, GF_LOG_DEBUG)) {
2637 char *content, *_content = NULL;
2638 if (utf8_script) {
2639 content = utf8_script;
2640 } else if (!JS_IsUndefined(hdl->js_data->fun_val)) {
2641 content = _content = (char *) JS_ToCString(svg_js->js_ctx, hdl->js_data->fun_val);
2642 } else if (txt) {
2643 content = txt->textContent;
2644 } else {
2645 content = "unknown";
2646 }
2647 GF_LOG(GF_LOG_DEBUG, GF_LOG_SCRIPT, ("[DOM Events ] Executing script code from handler: %s\n", content) );
2648 JS_FreeCString(svg_js->js_ctx, _content);
2649 }
2650 #endif
2651
2652 gf_js_lock(svg_js->js_ctx, GF_TRUE);
2653 prev_event = dom_get_evt_private(svg_js->event);
2654 /*break loops*/
2655 if (prev_event && (prev_event->type==event->type) && (prev_event->target==event->target)) {
2656 gf_js_lock(svg_js->js_ctx, GF_FALSE);
2657 return GF_FALSE;
2658 }
2659 JS_SetOpaque(svg_js->event, event);
2660
2661 svg_js->in_script = GF_TRUE;
2662 if (svg_js->use_strict)
2663 flags = JS_EVAL_TYPE_MODULE;
2664
2665 /*if an observer is being specified, use it*/
2666 if (hdl && hdl->js_data && !JS_IsUndefined(hdl->js_data->evt_listen_obj)) __this = hdl->js_data->evt_listen_obj;
2667 /*compile the jsfun if any - 'this' is the associated observer*/
2668 else __this = observer ? dom_element_construct(svg_js->js_ctx, observer) : svg_js->global;
2669
2670 if (txt && hdl && hdl->js_data && !JS_IsUndefined(hdl->js_data->fun_val)) {
2671 hdl->js_data->fun_val = JS_EvalWithTarget(svg_js->js_ctx, __this, txt->textContent, strlen(txt->textContent), "handler", flags|JS_EVAL_FLAG_COMPILE_ONLY);
2672 }
2673
2674 if (utf8_script) {
2675 ret = JS_EvalWithTarget(svg_js->js_ctx, __this, utf8_script, (u32) strlen(utf8_script), "inline script", flags);
2676 }
2677 else if (hdl && hdl->js_data
2678 && (!JS_IsUndefined(hdl->js_data->fun_val) || !JS_IsUndefined(hdl->js_data->evt_listen_obj) )
2679 ) {
2680 JSValue evt;
2681 JSValue argv[1];
2682 evt = gf_dom_new_event(svg_js->js_ctx);
2683 JS_SetOpaque(evt, event);
2684 argv[0] = evt;
2685
2686 if (!JS_IsUndefined(hdl->js_data->fun_val) ) {
2687 ret = JS_Call(svg_js->js_ctx, hdl->js_data->fun_val, __this, 1, argv);
2688 } else {
2689 JSValue fun = JS_GetPropertyStr(svg_js->js_ctx, hdl->js_data->evt_listen_obj, "hanldeEvent");
2690 ret = JS_Call(svg_js->js_ctx, fun, hdl->js_data->evt_listen_obj, 1, argv);
2691 JS_FreeValue(svg_js->js_ctx, fun);
2692 }
2693 } else if (txt) {
2694 JSValue fun = JS_GetPropertyStr(svg_js->js_ctx, svg_js->global, txt->textContent);
2695 if (!JS_IsUndefined(fun)) {
2696 ret = JS_NULL;
2697 if (svg_script_execute(node->sgprivate->scenegraph, txt->textContent, event)) {
2698 success = GF_FALSE;
2699 }
2700 }
2701 else {
2702 ret = JS_EvalWithTarget(svg_js->js_ctx, __this, txt->textContent, (u32) strlen(txt->textContent), "internal", flags);
2703 }
2704 JS_FreeValue(svg_js->js_ctx, fun);
2705 } else {
2706 ret = JS_NULL;
2707 }
2708 if (JS_IsException(ret)) {
2709 js_dump_error(svg_js->js_ctx);
2710 success = GF_FALSE;
2711 }
2712 JS_FreeValue(svg_js->js_ctx, ret);
2713
2714 JS_SetOpaque(svg_js->event, prev_event);
2715 if (txt && hdl && hdl->js_data) hdl->js_data->fun_val = JS_UNDEFINED;
2716
2717 while (svg_js->force_gc) {
2718 svg_js->force_gc = GF_FALSE;
2719 gf_js_call_gc(svg_js->js_ctx);
2720 }
2721 svg_js->in_script = GF_FALSE;
2722
2723 /*check any pending exception if outer-most event*/
2724 if (!prev_event) {
2725 js_do_loop(svg_js->js_ctx);
2726 }
2727
2728 gf_js_lock(svg_js->js_ctx, GF_FALSE);
2729
2730 #ifdef DUMP_DEF_AND_ROOT
2731 if ((event->type==GF_EVENT_CLICK) || (event->type==GF_EVENT_MOUSEOVER)) {
2732 NodeIDedItem *reg_node;
2733 fprintf(stderr, "Node registry\n");
2734 reg_node = node->sgprivate->scenegraph->id_node;
2735 while (reg_node) {
2736 fprintf(stderr, "\t%s\n", reg_node->NodeName);
2737 reg_node = reg_node->next;
2738 }
2739
2740 fprintf(stderr, "\n\nNamed roots:\n");
2741 JS_DumpNamedRoots(JS_GetRuntime(svg_js->js_ctx), dump_root, NULL);
2742 }
2743 #endif
2744
2745 if (!success) {
2746 GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("SVG: Invalid event handler script\n" ));
2747 return GF_FALSE;
2748 }
2749 return GF_TRUE;
2750 }
2751
2752 #endif
2753
2754 #endif
2755