LCOV - code coverage report
Current view: top level - scenegraph - svg_js.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 198 1286 15.4 %
Date: 2021-04-29 23:48:07 Functions: 18 89 20.2 %

          Line data    Source code
       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             : 
      92           2 : void svg_mark_gc(struct __tag_svg_script_ctx *svg_js)
      93             : {
      94           2 :         if (svg_js)
      95           0 :                 svg_js->force_gc = 1;
      96           2 : }
      97             : 
      98          28 : void svg_free_node_binding(struct __tag_svg_script_ctx *svg_js, GF_Node *node)
      99             : {
     100          28 :         struct _node_js_binding *js_binding = node->sgprivate->interact->js_binding;
     101          56 :         if (!JS_IsUndefined(js_binding->obj)) {
     102          28 :                 JS_SetOpaque(js_binding->obj, NULL);
     103          28 :                 JS_FreeValue(svg_js->js_ctx, js_binding->obj);
     104          28 :                 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          28 :                 gf_node_unregister(node, NULL);
     108             :         }
     109             : 
     110          28 :         if (svg_js->in_script)
     111           0 :                 svg_js->force_gc = 1;
     112             :         else
     113          28 :                 gf_js_call_gc(svg_js->js_ctx);
     114          28 : }
     115             : 
     116           0 : GF_Err svg_exec_script(struct __tag_svg_script_ctx *svg_js, GF_SceneGraph *sg, const char *com)
     117             : {
     118           0 :         Bool ret = sg->svg_js->script_execute(sg, (char *)com, NULL);
     119           0 :         return (ret == GF_TRUE ? GF_OK : GF_BAD_PARAM);
     120             : }
     121             : 
     122           0 : 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           0 :         if (svg_js->handler_execute(hdl, event, observer, (char *) iri)) {
     125             :                 return;
     126             :         } else {
     127           0 :                 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             : 
     148             : static GFINLINE Bool ScriptAction(GF_SceneGraph *scene, u32 type, GF_Node *node, GF_JSAPIParam *param)
     149             : {
     150           4 :         if (scene->script_action)
     151           4 :                 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             : 
     192           0 : static JSValue svg_nav_to_location(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
     193             : {
     194             :         GF_JSAPIParam par;
     195           0 :         GF_SceneGraph *sg = JS_GetOpaque(obj, svg_globalClass.class_id);
     196           0 :         if ((argc!=1) || !sg)
     197           0 :                 return JS_EXCEPTION;
     198             : 
     199           0 :         par.uri.url = (char *) JS_ToCString(c, argv[0]);
     200           0 :         par.uri.nb_params = 0;
     201           0 :         ScriptAction(sg, GF_JSAPI_OP_LOAD_URL, sg->RootNode, &par);
     202           0 :         JS_FreeCString(c, par.uri.url);
     203           0 :         return JS_UNDEFINED;
     204             : }
     205             : 
     206             : GF_Node *gf_sm_load_svg_from_string(GF_SceneGraph *sg, char *svg_str);
     207           0 : 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           0 :         if (!JS_IsObject(argv[1])) {
     214           0 :                 return js_throw_err(c, GF_DOM_EXC_WRONG_DOCUMENT_ERR);
     215             :         }
     216             : 
     217             :         str = JS_ToCString(c, argv[0]);
     218           0 :         if (!str) return JS_TRUE;
     219           0 :         sg = dom_get_doc(c, argv[1]);
     220             : 
     221           0 :         node = gf_sm_load_svg_from_string(sg, (char *) str);
     222           0 :         JS_FreeCString(c, str);
     223           0 :         return dom_element_construct(c, node);
     224             : }
     225             : 
     226           3 : static void svg_define_udom_exception(JSContext *c, JSValue global)
     227             : {
     228           3 :         JSValue obj = JS_NewObject(c);
     229           3 :         JS_SetPropertyStr(c, global, "GlobalException", obj);
     230             : #define DEFCONST(_name, _code)\
     231             :                 JS_SetPropertyStr(c, obj, _name, JS_NewInt32(c, _code));
     232             : 
     233           3 :         DEFCONST("NOT_CONNECTED_ERR", 1)
     234           3 :         DEFCONST("ENCODING_ERR", 2)
     235           3 :         DEFCONST("DENIED_ERR", 3)
     236           3 :         DEFCONST("UNKNOWN_ERR", 4)
     237             : 
     238           3 :         obj = JS_NewObject(c);
     239           3 :         JS_SetPropertyStr(c, global, "SVGException", obj);
     240           3 :         DEFCONST("SVG_WRONG_TYPE_ERR", 0)
     241           3 :         DEFCONST("SVG_INVALID_VALUE_ERR", 1)
     242           3 :         DEFCONST("SVG_MATRIX_NOT_INVERTABLE", 2)
     243             : 
     244           3 :         obj = JS_NewObject(c);
     245           3 :         JS_SetPropertyStr(c, global, "SVGSVGElement", obj);
     246           3 :         DEFCONST("NAV_AUTO", 1)
     247           3 :         DEFCONST("NAV_NEXT", 2)
     248           3 :         DEFCONST("NAV_PREV", 3)
     249           3 :         DEFCONST("NAV_UP", 4)
     250           3 :         DEFCONST("NAV_UP_RIGHT", 5)
     251           3 :         DEFCONST("NAV_RIGHT", 6)
     252           3 :         DEFCONST("NAV_DOWN_RIGHT", 7)
     253           3 :         DEFCONST("NAV_DOWN", 8)
     254           3 :         DEFCONST("NAV_DOWN_LEFT", 9)
     255           3 :         DEFCONST("NAV_LEFT", 10)
     256           3 :         DEFCONST("NAV_UP_LEFT", 11)
     257           3 : }
     258             : 
     259           0 : static JSValue global_getProperty(JSContext *c, JSValueConst obj, int magic)
     260             : {
     261           0 :         GF_SceneGraph *sg = JS_GetOpaque(obj, svg_globalClass.class_id);
     262           0 :         if (!sg) return JS_EXCEPTION;
     263             : 
     264           0 :         switch (magic) {
     265             :         /*namespaceURI*/
     266           0 :         case 0:
     267           0 :                 return JS_NULL;
     268             :         /*parent*/
     269           0 :         case 1:
     270           0 :                 if (sg->parent_scene && sg->parent_scene->svg_js)
     271             :                         return JS_DupValue(c, sg->parent_scene->svg_js->global);
     272           0 :                 return JS_NULL;
     273           0 :         default:
     274           0 :                 return JS_UNDEFINED;
     275             :         }
     276             : }
     277             : 
     278             : /*TODO - try to be more precise...*/
     279           0 : static JSValue dom_imp_has_feature(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
     280             : {
     281           0 :         JSValue ret = JS_FALSE;
     282             : 
     283           0 :         if (argc) {
     284             :                 u32 len;
     285             :                 char sep;
     286             :                 char *fname = (char *) JS_ToCString(c, argv[0]);
     287           0 :                 if (!fname) return JS_TRUE;
     288           0 :                 while (strchr(" \t\n\r", fname[0])) fname++;
     289           0 :                 len = (u32) strlen(fname);
     290           0 :                 while (len && strchr(" \t\n\r", fname[len-1])) len--;
     291           0 :                 sep = fname[len];
     292           0 :                 fname[len] = 0;
     293           0 :                 if (!stricmp(fname, "xml")) ret = JS_TRUE;
     294           0 :                 else if (!stricmp(fname, "core")) ret = JS_TRUE;
     295           0 :                 else if (!stricmp(fname, "traversal")) ret = JS_TRUE;
     296           0 :                 else if (!stricmp(fname, "uievents")) ret = JS_TRUE;
     297           0 :                 else if (!stricmp(fname, "mouseevents")) ret = JS_TRUE;
     298           0 :                 else if (!stricmp(fname, "mutationevents")) ret = JS_TRUE;
     299           0 :                 else if (!stricmp(fname, "events")) ret = JS_TRUE;
     300             : 
     301           0 :                 fname[len] = sep;
     302           0 :                 JS_FreeCString(c, fname);
     303             :         }
     304           0 :         return ret;
     305             : }
     306             : 
     307           0 : static GF_Node *get_corresponding_use(GF_Node *n)
     308             : {
     309             :         u32 i, count;
     310           0 :         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           0 :         count = gf_list_count(n->sgprivate->scenegraph->use_stack);
     314           0 :         for (i=count; i>0; i-=2) {
     315           0 :                 GF_Node *t = (GF_Node *)gf_list_get(n->sgprivate->scenegraph->use_stack, i-2);
     316           0 :                 if (t==n) {
     317           0 :                         GF_Node *use = (GF_Node *)gf_list_get(n->sgprivate->scenegraph->use_stack, i-1);
     318           0 :                         GF_Node *par_use = get_corresponding_use(use);
     319           0 :                         return par_use ? par_use : use;
     320             :                 }
     321             :         }
     322             :         /*otherwise recursively get up the tree*/
     323           0 :         return get_corresponding_use(gf_node_get_parent(n, 0));
     324             : }
     325             : 
     326           0 : static JSValue svg_doc_getProperty(JSContext *c, JSValueConst obj, int magic)
     327             : {
     328           0 :         GF_SceneGraph *sg = dom_get_doc(c, obj);
     329           0 :         if (!sg) return JS_EXCEPTION;
     330           0 :         switch (magic) {
     331           0 :         case 0:/*global*/
     332           0 :                 return JS_GetGlobalObject(c);
     333             :         }
     334           0 :         return JS_UNDEFINED;
     335             : }
     336             : 
     337           0 : static JSValue svg_element_getProperty(JSContext *c, JSValueConst obj, int magic)
     338             : {
     339             :         GF_JSAPIParam par;
     340           0 :         GF_Node *n = dom_get_element(c, obj);
     341           0 :         if (!n) return JS_TRUE;
     342             : 
     343           0 :         switch (magic) {
     344           0 :         case 0: /*id*/
     345             :         {
     346           0 :                 const char *node_name = gf_node_get_name((GF_Node*)n);
     347           0 :                 if (node_name) {
     348           0 :                         return JS_NewString(c, node_name);
     349             :                 }
     350           0 :                 return JS_NULL;
     351             :         }
     352           0 :         case 5:/*currentScale*/
     353           0 :                 if (n->sgprivate->tag!=TAG_SVG_svg) return JS_EXCEPTION;
     354           0 :                 if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_GET_SCALE, (GF_Node *)n, &par)) {
     355           0 :                         return JS_NewFloat64(c, FIX2FLT(par.val) );
     356             :                 }
     357           0 :                 return JS_EXCEPTION;
     358           0 :         case 6:/*currentRotate*/
     359           0 :                 if (n->sgprivate->tag!=TAG_SVG_svg) return JS_EXCEPTION;
     360           0 :                 if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_GET_ROTATION, (GF_Node *)n, &par)) {
     361           0 :                         return JS_NewFloat64(c, FIX2FLT(par.val) );
     362             :                 }
     363           0 :                 return JS_EXCEPTION;
     364           0 :         case 7:/*currentTranslate*/
     365           0 :                 if (n->sgprivate->tag!=TAG_SVG_svg) return JS_EXCEPTION;
     366           0 :                 if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_GET_TRANSLATE, (GF_Node *)n, &par)) {
     367           0 :                         JSValue r = JS_NewObjectClass(c, pointClass.class_id);
     368           0 :                         pointCI *rc = (pointCI *)gf_malloc(sizeof(pointCI));
     369           0 :                         rc->x = FIX2FLT(par.pt.x);
     370           0 :                         rc->y = FIX2FLT(par.pt.y);
     371           0 :                         rc->sg = n->sgprivate->scenegraph;
     372           0 :                         JS_SetOpaque(r, rc);
     373           0 :                         return r;
     374             :                 }
     375           0 :                 return JS_EXCEPTION;
     376           0 :         case 8:/*viewport*/
     377           0 :                 if (n->sgprivate->tag!=TAG_SVG_svg) return JS_EXCEPTION;
     378           0 :                 if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_GET_VIEWPORT, (GF_Node *)n, &par)) {
     379           0 :                         JSValue r = JS_NewObjectClass(c, rectClass.class_id);
     380           0 :                         rectCI *rc = (rectCI *)gf_malloc(sizeof(rectCI));
     381           0 :                         rc->x = FIX2FLT(par.rc.x);
     382           0 :                         rc->y = FIX2FLT(par.rc.y);
     383           0 :                         rc->w = FIX2FLT(par.rc.width);
     384           0 :                         rc->h = FIX2FLT(par.rc.height);
     385           0 :                         rc->sg = n->sgprivate->scenegraph;
     386           0 :                         JS_SetOpaque(r, rc);
     387           0 :                         return r;
     388             :                 }
     389           0 :                 return JS_EXCEPTION;
     390           0 :         case 9:/*currentTime*/
     391           0 :                 return JS_NewFloat64(c, gf_node_get_scene_time((GF_Node *)n) );
     392           0 :         case 10:/*isPaused*/
     393           0 :                 return JS_FALSE;
     394           0 :         case 11:/*ownerSVGElement*/
     395             :                 while (1) {
     396           0 :                         GF_Node *n_par = gf_node_get_parent(n, 0);
     397           0 :                         if (!n_par) return JS_TRUE;
     398           0 :                         if (n_par->sgprivate->tag==TAG_SVG_svg) {
     399           0 :                                 return dom_element_construct(c, n_par);
     400             :                         }
     401             :                         n = n_par;
     402             :                 }
     403             :                 return JS_NULL;
     404           0 :         case 12:/*correspondingElement*/
     405             :                 /*if we can find a corresponding element for this node, then this is an SVGElementInstance*/
     406           0 :                 if (get_corresponding_use(n)) {
     407           0 :                         return dom_element_construct(c, n);
     408             :                 } else {
     409           0 :                         return dom_element_construct(c, NULL);
     410             :                 }
     411             :                 break;
     412           0 :         case 13:/*correspondingUseElement*/
     413           0 :                 return dom_element_construct(c, get_corresponding_use(n));
     414             :         default:
     415             :                 break;
     416             :         }
     417           0 :         return JS_UNDEFINED;
     418             : }
     419             : 
     420           0 : static JSValue svg_element_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
     421             : {
     422             :         GF_JSAPIParam par;
     423             :         Double d;
     424           0 :         GF_Node *n = dom_get_element(c, obj);
     425           0 :         if (!n) return JS_EXCEPTION;
     426             : 
     427           0 :         switch (magic) {
     428           0 :         case 0:/*id*/
     429           0 :                 if (JSVAL_CHECK_STRING(value)) {
     430             :                         const char *id = JS_ToCString(c, value);
     431           0 :                         if (id) {
     432             :                                 GF_FieldInfo info;
     433           0 :                                 u32 nid = gf_node_get_id(n);
     434           0 :                                 if (!nid) nid = gf_sg_get_next_available_node_id(n->sgprivate->scenegraph);
     435           0 :                                 gf_node_set_id(n, nid, id);
     436           0 :                                 if (gf_node_get_attribute_by_tag(n, TAG_XML_ATT_id, GF_TRUE, GF_FALSE, &info)==GF_OK) {
     437           0 :                                         if (*(DOM_String *)info.far_ptr) gf_free(*(DOM_String *)info.far_ptr);
     438           0 :                                         *(DOM_String *)info.far_ptr = gf_strdup(id);
     439             :                                 }
     440           0 :                                 if (gf_node_get_attribute_by_tag(n, TAG_SVG_ATT_id, GF_TRUE, GF_FALSE, &info)==GF_OK) {
     441           0 :                                         if (*(DOM_String *)info.far_ptr) gf_free(*(DOM_String *)info.far_ptr);
     442           0 :                                         *(DOM_String *)info.far_ptr = gf_strdup(id);
     443             :                                 }
     444           0 :                                 JS_FreeCString(c, id);
     445             :                         }
     446             :                 }
     447           0 :                 return JS_TRUE;
     448             :                 /*currentScale*/
     449           0 :         case 5:
     450           0 :                 if ((n->sgprivate->tag!=TAG_SVG_svg) || JS_ToFloat64(c, &d, value))
     451           0 :                         return JS_EXCEPTION;
     452             : 
     453           0 :                 par.val = FLT2FIX(d);
     454           0 :                 if (!par.val) {
     455           0 :                         return js_throw_err(c, GF_DOM_EXC_INVALID_ACCESS_ERR);
     456             :                 }
     457           0 :                 if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_SET_SCALE, (GF_Node *)n, &par)) {
     458           0 :                         return JS_TRUE;
     459             :                 }
     460           0 :                 return JS_FALSE;
     461             :                 /*currentRotate*/
     462           0 :         case 6:
     463           0 :                 if ((n->sgprivate->tag!=TAG_SVG_svg) || JS_ToFloat64(c, &d, value))
     464           0 :                         return JS_EXCEPTION;
     465             : 
     466           0 :                 par.val = FLT2FIX(d);
     467           0 :                 if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_SET_ROTATION, (GF_Node *)n, &par)) {
     468           0 :                         return JS_TRUE;
     469             :                 }
     470           0 :                 return JS_FALSE;
     471             :                 /*currentTime*/
     472           0 :         case 9:
     473           0 :                 if ((n->sgprivate->tag!=TAG_SVG_svg) || JS_ToFloat64(c, &d, value))
     474           0 :                         return JS_EXCEPTION;
     475             : 
     476           0 :                 par.time = d;
     477           0 :                 if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_SET_TIME, (GF_Node *)n, &par)) {
     478           0 :                         return JS_TRUE;
     479             :                 }
     480           0 :                 return JS_FALSE;
     481             :         default:
     482             :                 break;
     483             :         }
     484           0 :         return JS_UNDEFINED;
     485             : }
     486             : 
     487           0 : static GF_Node *svg_udom_smil_check_instance(JSContext *c, JSValue obj)
     488             : {
     489           0 :         GF_Node *n = dom_get_element(c, obj);
     490           0 :         if (!n) return NULL;
     491           0 :         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           0 :         return NULL;
     506             : }
     507             : 
     508             : 
     509             : /*TODO*/
     510           0 : 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           0 :         GF_Node *n = svg_udom_smil_check_instance(c, obj);
     519           0 :         if (!n) return JS_UNDEFINED;
     520             : 
     521           0 :         if (is_end) {
     522           0 :                 info.far_ptr = ((SVGTimedAnimBaseElement *)n)->timingp->end;
     523             :         } else {
     524           0 :                 info.far_ptr = ((SVGTimedAnimBaseElement *)n)->timingp->begin;
     525             :         }
     526           0 :         if (!info.far_ptr) {
     527           0 :                 return JS_EXCEPTION;
     528             :         }
     529           0 :         times = *((GF_List **)info.far_ptr);
     530           0 :         GF_SAFEALLOC(newtime, SMIL_Time);
     531           0 :         if (!newtime) {
     532           0 :                 return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
     533             :         }
     534           0 :         newtime->type = GF_SMIL_TIME_EVENT_RESOLVED;
     535             : 
     536           0 :         offset = 0;
     537           0 :         if (argc)
     538           0 :                 JS_ToFloat64(c, &offset, argv[0]);
     539             : 
     540           0 :         newtime->clock = gf_node_get_scene_time(n) + offset;
     541             : 
     542             :         /*insert in sorted order*/
     543           0 :         count = gf_list_count(times);
     544           0 :         for (i=0; i<count; i++) {
     545           0 :                 SMIL_Time*t = (SMIL_Time*)gf_list_get(times, i);
     546           0 :                 if ( GF_SMIL_TIME_IS_CLOCK(t->type) ) {
     547           0 :                         if (t->clock > newtime->clock) break;
     548             :                 } else {
     549             :                         break;
     550             :                 }
     551             :         }
     552           0 :         gf_list_insert(times, newtime, i);
     553             : 
     554           0 :         info.fieldType = SMIL_Times_datatype;
     555           0 :         gf_node_changed(n, &info);
     556           0 :         return JS_TRUE;
     557             : }
     558             : 
     559           0 : static JSValue svg_udom_smil_begin(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
     560             : {
     561           0 :         return svg_udom_smil_time_insert(c, obj, argc, argv, GF_FALSE);
     562             : }
     563           0 : static JSValue svg_udom_smil_end(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
     564             : {
     565           0 :         return svg_udom_smil_time_insert(c, obj, argc, argv, GF_TRUE);
     566             : }
     567             : 
     568             : /*TODO*/
     569           0 : static JSValue svg_udom_smil_pause(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
     570             : {
     571             :         u32 tag;
     572           0 :         GF_Node *n = dom_get_element(c, obj);
     573           0 :         if (!n) return JS_EXCEPTION;
     574             : 
     575           0 :         tag = gf_node_get_tag(n);
     576           0 :         if (gf_svg_is_animation_tag(tag)) {
     577             :                 /* pausing an animation element (set, animate ...) should pause the main time line ? */
     578           0 :                 gf_smil_timing_pause(n);
     579           0 :         } else if (gf_svg_is_timing_tag(tag)) {
     580           0 :                 ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_PAUSE_SVG, n, NULL);
     581           0 :         } else if ((tag==TAG_SVG_svg) && (n->sgprivate->scenegraph->RootNode==n)) {
     582           0 :                 ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_PAUSE_SVG, n, NULL);
     583             :         } else {
     584           0 :                 return JS_FALSE;
     585             :         }
     586           0 :         return JS_TRUE;
     587             : }
     588             : /*TODO*/
     589           0 : static JSValue svg_udom_smil_resume(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
     590             : {
     591             :         u32 tag;
     592           0 :         GF_Node *n = dom_get_element(c, obj);
     593           0 :         if (!n) return JS_EXCEPTION;
     594             : 
     595           0 :         tag = gf_node_get_tag(n);
     596           0 :         if (gf_svg_is_animation_tag(tag)) {
     597             :                 /* resuming an animation element (set, animate ...) should resume the main time line ? */
     598           0 :                 gf_smil_timing_resume(n);
     599           0 :         } else if (gf_svg_is_timing_tag(tag)) {
     600           0 :                 ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_RESUME_SVG, n, NULL);
     601           0 :         } else if ((tag==TAG_SVG_svg) && (n->sgprivate->scenegraph->RootNode==n)) {
     602           0 :                 ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_RESUME_SVG, n, NULL);
     603             :         } else {
     604           0 :                 return JS_FALSE;
     605             :         }
     606           0 :         return JS_TRUE;
     607             : }
     608             : 
     609           0 : static JSValue svg_udom_smil_restart(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
     610             : {
     611             :         u32 tag;
     612           0 :         GF_Node *n = dom_get_element(c, obj);
     613           0 :         if (!n) return JS_EXCEPTION;
     614             : 
     615           0 :         tag = gf_node_get_tag(n);
     616           0 :         if ((tag==TAG_SVG_svg) && (n->sgprivate->scenegraph->RootNode==n)) {
     617           0 :                 ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_RESTART_SVG, n, NULL);
     618             :         } else {
     619           0 :                 return JS_FALSE;
     620             :         }
     621           0 :         return JS_TRUE;
     622             : }
     623             : 
     624           0 : static JSValue svg_udom_smil_set_speed(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
     625             : {
     626             :         u32 tag;
     627           0 :         Double speed = 1.0;
     628           0 :         GF_Node *n = dom_get_element(c, obj);
     629             : 
     630           0 :         if (!n || !argc || JS_ToFloat64(c, &speed, argv[0]) ) {
     631           0 :                 return JS_EXCEPTION;
     632             :         }
     633           0 :         tag = gf_node_get_tag(n);
     634           0 :         if ((tag==TAG_SVG_svg) && (n->sgprivate->scenegraph->RootNode==n)) {
     635             :                 GF_JSAPIParam par;
     636             :                 memset(&par, 0, sizeof(GF_JSAPIParam));
     637           0 :                 par.val = FLT2FIX(speed);
     638           0 :                 ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_SET_SCENE_SPEED, n, &par);
     639             :         } else {
     640           0 :                 return JS_TRUE;
     641             :         }
     642           0 :         return JS_UNDEFINED;
     643             : }
     644             : 
     645           0 : 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           0 :         GF_Node *n = dom_get_element(c, obj);
     653           0 :         if (!n) return JS_EXCEPTION;
     654             : 
     655             :         //ns = NULL;
     656             :         name = NULL;
     657           0 :         if (! JSVAL_CHECK_STRING(argv[0]) ) return JS_TRUE;
     658           0 :         if (argc==2) {
     659             :                 //ns = JS_ToCString(c, argv[0]);
     660             :                 name = JS_ToCString(c, argv[1]);
     661           0 :         } else if (argc==1) {
     662             :                 name = JS_ToCString(c, argv[0]);
     663           0 :         } else return JS_EXCEPTION;
     664             : 
     665           0 :         if (!name) {
     666             :                 //JS_FreeCString(c, ns);
     667           0 :                 return JS_EXCEPTION;
     668             :         }
     669           0 :         if (!strcmp(name, "#text")) {
     670           0 :                 char *res = gf_dom_flatten_textContent(n);
     671           0 :                 ret = JS_NewString(c, res);
     672           0 :                 gf_free(res);
     673             :                 //JS_FreeCString(c, ns);
     674           0 :                 JS_FreeCString(c, name);
     675           0 :                 return ret;
     676             :         }
     677           0 :         e = gf_node_get_field_by_name(n, (char *) name, &info);
     678             : 
     679             :         //JS_FreeCString(c, ns);
     680           0 :         JS_FreeCString(c, name);
     681             : 
     682           0 :         if (e!=GF_OK) return JS_EXCEPTION;
     683             : 
     684           0 :         switch (info.fieldType) {
     685             :         /* inheritable floats */
     686           0 :         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           0 :                 attValue = gf_svg_dump_attribute(n, &info);
     741           0 :                 ret = JS_NewString(c, attValue);
     742           0 :                 if (attValue) gf_free(attValue);
     743           0 :                 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           0 :         return JS_NULL;
     772             : }
     773             : 
     774           0 : 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           0 :         GF_Node *n = dom_get_element(c, obj);
     780           0 :         if (!n) return JS_EXCEPTION;
     781             : 
     782           0 :         if ((argc!=1) || !JS_IsString(argv[0])) return JS_EXCEPTION;
     783             :         szName = JS_ToCString(c, argv[0]);
     784           0 :         if (!szName) return JS_EXCEPTION;
     785             : 
     786           0 :         e = gf_node_get_attribute_by_name(n, (char *) szName, 0, GF_TRUE, GF_TRUE, &info);
     787           0 :         JS_FreeCString(c, szName);
     788           0 :         if (e != GF_OK) return JS_EXCEPTION;
     789             : 
     790           0 :         switch (info.fieldType) {
     791             :         /* inheritable floats */
     792           0 :         case SVG_Number_datatype:
     793             :         case SVG_FontSize_datatype:
     794             :         case SVG_Length_datatype:
     795             :         case SVG_Coordinate_datatype:
     796             :         {
     797           0 :                 SVG_Number *l = (SVG_Number *)info.far_ptr;
     798           0 :                 if (l->type==SVG_NUMBER_AUTO || l->type==SVG_NUMBER_INHERIT) return JS_TRUE;
     799           0 :                 return JS_NewFloat64(c, FIX2FLT(l->value));
     800             :         }
     801           0 :         case SVG_Clock_datatype:
     802           0 :                 return JS_NewFloat64(c, *(SVG_Clock*)info.far_ptr );
     803           0 :         default:
     804           0 :                 return JS_NULL;
     805             :         }
     806             :         return JS_NULL;
     807             : }
     808             : 
     809           0 : 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           0 :         GF_Node *n = dom_get_element(c, obj);
     815           0 :         if (!n) return JS_EXCEPTION;
     816             : 
     817           0 :         if ((argc!=1) || !JS_IsString(argv[0])) return JS_EXCEPTION;
     818             :         szName = JS_ToCString(c, argv[0]);
     819             : 
     820           0 :         e = gf_node_get_field_by_name(n, (char *) szName, &info);
     821           0 :         JS_FreeCString(c, szName);
     822           0 :         if (e != GF_OK) return JS_EXCEPTION;
     823             : 
     824           0 :         if (info.fieldType==SVG_Transform_datatype) {
     825           0 :                 GF_Matrix2D *mx = (GF_Matrix2D *)gf_malloc(sizeof(GF_Matrix2D));
     826           0 :                 if (!mx) return JS_EXCEPTION;
     827           0 :                 JSValue mO = JS_NewObjectClass(c, matrixClass.class_id);
     828           0 :                 gf_mx2d_init(*mx);
     829           0 :                 gf_mx2d_copy(*mx, ((SVG_Transform*)info.far_ptr)->mat);
     830             : 
     831           0 :                 JS_SetOpaque(mO, mx);
     832           0 :                 return mO;
     833             :         }
     834           0 :         return JS_NULL;
     835             : }
     836             : 
     837           2 : 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           2 :         GF_Node *n = dom_get_element(c, obj);
     843           2 :         if (!n) return JS_EXCEPTION;
     844             : 
     845           4 :         if ((argc!=1) || !JS_IsString(argv[0])) return JS_EXCEPTION;
     846             :         szName = JS_ToCString(c, argv[0]);
     847             : 
     848           2 :         e = gf_node_get_field_by_name(n, (char *) szName, &info);
     849           2 :         JS_FreeCString(c, szName);
     850           2 :         if (e != GF_OK) return JS_EXCEPTION;
     851             : 
     852           2 :         if (info.fieldType==SVG_ViewBox_datatype) {
     853             :                 JSValue newObj;
     854             :                 rectCI *rc;
     855           2 :                 SVG_ViewBox *v = (SVG_ViewBox *)info.far_ptr;
     856           2 :                 GF_SAFEALLOC(rc, rectCI);
     857           2 :                 if (!rc) {
     858           0 :                         return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
     859             :                 }
     860           2 :                 newObj = JS_NewObjectClass(c, rectClass.class_id);
     861           2 :                 rc->x = FIX2FLT(v->x);
     862           2 :                 rc->y = FIX2FLT(v->y);
     863           2 :                 rc->w = FIX2FLT(v->width);
     864           2 :                 rc->h = FIX2FLT(v->height);
     865           2 :                 JS_SetOpaque(newObj, rc);
     866           2 :                 return newObj;
     867             :         }
     868           0 :         return JS_NULL;
     869             : }
     870             : 
     871           0 : 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           0 :         GF_Node *n = dom_get_element(c, obj);
     877           0 :         if (!n) return JS_EXCEPTION;
     878             : 
     879           0 :         if ((argc!=1) || !JS_IsString(argv[0])) return JS_EXCEPTION;
     880             :         szName = JS_ToCString(c, argv[0]);
     881             : 
     882           0 :         e = gf_node_get_field_by_name(n, (char *) szName, &info);
     883           0 :         JS_FreeCString(c, szName);
     884           0 :         if (e != GF_OK) return JS_EXCEPTION;
     885             : 
     886           0 :         if (info.fieldType==SVG_PathData_datatype) {
     887             :                 return svg_new_path_object(c, (SVG_PathData *)info.far_ptr);
     888             :         }
     889           0 :         return JS_NULL;
     890             : }
     891             : 
     892           0 : 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           0 :         GF_Node *n = dom_get_element(c, obj);
     901           0 :         if (!n) return JS_EXCEPTION;
     902             : 
     903           0 :         if ((argc!=1) || !JS_IsString(argv[0])) return JS_EXCEPTION;
     904             :         szName = JS_ToCString(c, argv[0]);
     905             : 
     906           0 :         e = gf_node_get_field_by_name(n, (char *) szName, &info);
     907           0 :         JS_FreeCString(c, szName);
     908           0 :         if (e != GF_OK) return JS_EXCEPTION;
     909             : 
     910           0 :         switch (info.fieldType) {
     911           0 :         case SVG_Color_datatype:
     912             :         {
     913           0 :                 SVG_Color *col = (SVG_Color *)info.far_ptr;
     914           0 :                 if (col->type == SVG_COLOR_CURRENTCOLOR) return JS_UNDEFINED;
     915           0 :                 if (col->type == SVG_COLOR_INHERIT) return JS_UNDEFINED;
     916             : 
     917           0 :                 GF_SAFEALLOC(rgb, rgbCI);
     918           0 :                 if (!rgb) {
     919           0 :                         return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
     920             :                 }
     921           0 :                 newObj = JS_NewObjectClass(c, rgbClass.class_id);
     922           0 :                 rgb->r = (u8) (255*FIX2FLT(col->red)) ;
     923           0 :                 rgb->g = (u8) (255*FIX2FLT(col->green)) ;
     924           0 :                 rgb->b = (u8) (255*FIX2FLT(col->blue)) ;
     925           0 :                 JS_SetOpaque(newObj, rgb);
     926           0 :                 return newObj;
     927             :         }
     928             :         break;
     929           0 :         case SVG_Paint_datatype:
     930             :         {
     931           0 :                 SVG_Paint *paint = (SVG_Paint *)info.far_ptr;
     932             :                 if ((1) || paint->type==SVG_PAINT_COLOR) {
     933           0 :                         GF_SAFEALLOC(rgb, rgbCI);
     934           0 :                         if (!rgb) {
     935           0 :                                 return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
     936             :                         }
     937           0 :                         newObj = JS_NewObjectClass(c, rgbClass.class_id);
     938           0 :                         rgb->r = (u8) (255*FIX2FLT(paint->color.red) );
     939           0 :                         rgb->g = (u8) (255*FIX2FLT(paint->color.green) );
     940           0 :                         rgb->b = (u8) (255*FIX2FLT(paint->color.blue) );
     941           0 :                         JS_SetOpaque(newObj, rgb);
     942           0 :                         return newObj;
     943             :                 }
     944             :                 return JS_TRUE;
     945             :         }
     946             :         }
     947           0 :         return JS_NULL;
     948             : }
     949             : 
     950           0 : 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           0 :         GF_Node *n = dom_get_element(c, obj);
     956           0 :         if (!n) return JS_EXCEPTION;
     957             : 
     958             :         val = ns = name = NULL;
     959           0 :         if (!JSVAL_CHECK_STRING(argv[0])) return JS_EXCEPTION;
     960           0 :         if (argc==3) {
     961           0 :                 if (!JSVAL_CHECK_STRING(argv[1])) return JS_EXCEPTION;
     962           0 :                 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           0 :         } else if (argc==2) {
     967             :                 name = JS_ToCString(c, argv[0]);
     968             :                 val = JS_ToCString(c, argv[1]);
     969             :         } else {
     970           0 :                 return JS_EXCEPTION;
     971             :         }
     972           0 :         if (!name) {
     973           0 :                 JS_FreeCString(c, ns);
     974           0 :                 JS_FreeCString(c, val);
     975           0 :                 return JS_EXCEPTION;
     976             :         }
     977           0 :         if (!strcmp(name, "#text")) {
     978           0 :                 if (val) dom_node_set_textContent(n, (char *) val);
     979           0 :                 JS_FreeCString(c, ns);
     980           0 :                 JS_FreeCString(c, name);
     981           0 :                 JS_FreeCString(c, val);
     982           0 :                 return JS_UNDEFINED;
     983             :         }
     984           0 :         e = gf_node_get_field_by_name(n, (char *) name, &info);
     985           0 :         JS_FreeCString(c, ns);
     986           0 :         JS_FreeCString(c, name);
     987             : 
     988           0 :         if (!val || (e!=GF_OK)) {
     989           0 :                 JS_FreeCString(c, val);
     990           0 :                 return JS_EXCEPTION;
     991             :         }
     992           0 :         e = gf_svg_parse_attribute(n, &info, (char *) val, 0);
     993           0 :         JS_FreeCString(c, val);
     994             : 
     995           0 :         if (e) return js_throw_err(c, GF_DOM_EXC_INVALID_ACCESS_ERR);
     996           0 :         dom_node_changed(n, GF_FALSE, &info);
     997           0 :         return JS_UNDEFINED;
     998             : }
     999             : 
    1000           0 : 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           0 :         GF_Node *n = dom_get_element(c, obj);
    1008           0 :         if (!n) return JS_EXCEPTION;
    1009           0 :         if (argc!=2) return JS_EXCEPTION;
    1010           0 :         if (!JS_IsString(argv[0])) return JS_EXCEPTION;
    1011           0 :         if (!JS_IsNumber(argv[1]) || JS_ToFloat64(c, &d, argv[1])) return JS_EXCEPTION;
    1012             : 
    1013             :         szName = JS_ToCString(c, argv[0]);
    1014           0 :         e = gf_node_get_field_by_name(n, (char *) szName, &info);
    1015           0 :         JS_FreeCString(c, szName);
    1016           0 :         if (e != GF_OK) return JS_EXCEPTION;
    1017             : 
    1018           0 :         switch (info.fieldType) {
    1019             :         /* inheritable floats */
    1020           0 :         case SVG_FontSize_datatype:
    1021             :         case SVG_Length_datatype:
    1022             :         case SVG_Coordinate_datatype:
    1023             :         case SVG_Number_datatype:
    1024             :         {
    1025           0 :                 SVG_Number *l = (SVG_Number *)info.far_ptr;
    1026           0 :                 l->type=SVG_NUMBER_VALUE;
    1027           0 :                 l->value = FLT2FIX(d);
    1028           0 :                 break;
    1029             :         }
    1030           0 :         case SVG_Numbers_datatype:
    1031             :         case SVG_Coordinates_datatype:
    1032             :         {
    1033             :                 SVG_Number *val;
    1034           0 :                 SVG_Coordinates *l = (SVG_Coordinates *)info.far_ptr;
    1035           0 :                 while (gf_list_count(*l)) {
    1036           0 :                         val = (SVG_Number *)gf_list_get(*l, 0);
    1037           0 :                         gf_list_rem(*l, 0);
    1038           0 :                         if (val) gf_free(val);
    1039             :                 }
    1040           0 :                 GF_SAFEALLOC(val, SVG_Coordinate);
    1041           0 :                 if (!val) {
    1042           0 :                         return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
    1043             :                 }
    1044           0 :                 val->type=SVG_NUMBER_VALUE;
    1045           0 :                 val->value = FLT2FIX(d);
    1046           0 :                 gf_list_add(*l, val);
    1047           0 :                 break;
    1048             :         }
    1049           0 :         default:
    1050           0 :                 return JS_FALSE;
    1051             :         }
    1052           0 :         dom_node_changed(n, GF_FALSE, &info);
    1053           0 :         return JS_TRUE;
    1054             : }
    1055             : 
    1056           0 : 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           0 :         GF_Node *n = dom_get_element(c, obj);
    1064           0 :         if (!n) return JS_TRUE;
    1065             : 
    1066           0 :         if (argc!=2) return JS_EXCEPTION;
    1067           0 :         if (!JS_IsString(argv[0])) return JS_EXCEPTION;
    1068           0 :         if (JS_IsNull(argv[1]) || !JS_IsObject(argv[1])) return JS_EXCEPTION;
    1069             : 
    1070           0 :         mx = JS_GetOpaque(argv[1], matrixClass.class_id);
    1071           0 :         if (!mx) return JS_EXCEPTION;
    1072             : 
    1073             :         szName = JS_ToCString(c, argv[0]);
    1074           0 :         e = gf_node_get_field_by_name(n, (char *) szName, &info);
    1075           0 :         JS_FreeCString(c, szName);
    1076           0 :         if (e != GF_OK) return JS_EXCEPTION;
    1077             : 
    1078           0 :         if (info.fieldType==SVG_Transform_datatype) {
    1079           0 :                 gf_mx2d_copy(((SVG_Transform*)info.far_ptr)->mat, *mx);
    1080           0 :                 dom_node_changed(n, GF_FALSE, NULL);
    1081           0 :                 return JS_TRUE;
    1082             :         }
    1083           0 :         return JS_FALSE;
    1084             : }
    1085             : 
    1086           0 : 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           0 :         GF_Node *n = dom_get_element(c, obj);
    1093           0 :         if (!n) return JS_EXCEPTION;
    1094             : 
    1095           0 :         if (argc!=2) return JS_EXCEPTION;
    1096           0 :         if (!JS_IsString(argv[0])) return JS_TRUE;
    1097           0 :         if (JS_IsNull(argv[1]) || !JS_IsObject(argv[1])) return JS_EXCEPTION;
    1098             : 
    1099           0 :         rc = JS_GetOpaque(argv[1], rectClass.class_id);
    1100           0 :         if (!rc) return JS_EXCEPTION;
    1101             : 
    1102             :         szName = JS_ToCString(c, argv[0]);
    1103           0 :         e = gf_node_get_field_by_name(n, (char *) szName, &info);
    1104           0 :         JS_FreeCString(c, szName);
    1105           0 :         if (e != GF_OK) return JS_EXCEPTION;
    1106             : 
    1107           0 :         if (info.fieldType==SVG_ViewBox_datatype) {
    1108           0 :                 SVG_ViewBox *v = (SVG_ViewBox *)info.far_ptr;
    1109           0 :                 v->x = FLT2FIX(rc->x);
    1110           0 :                 v->y = FLT2FIX(rc->y);
    1111           0 :                 v->width = FLT2FIX(rc->w);
    1112           0 :                 v->height = FLT2FIX(rc->h);
    1113           0 :                 dom_node_changed(n, GF_FALSE, NULL);
    1114           0 :                 return JS_TRUE;
    1115             :         }
    1116           0 :         return JS_FALSE;
    1117             : }
    1118             : 
    1119           0 : 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           0 :         GF_Node *n = dom_get_element(c, obj);
    1126           0 :         if (!n) return JS_EXCEPTION;
    1127             : 
    1128           0 :         if (argc!=2) return JS_EXCEPTION;
    1129           0 :         if (!JS_IsString(argv[0])) return JS_EXCEPTION;
    1130           0 :         if (JS_IsNull(argv[1]) || !JS_IsObject(argv[1])) return JS_EXCEPTION;
    1131           0 :         path = JS_GetOpaque( argv[1], pathClass.class_id);
    1132           0 :         if (!path) return JS_EXCEPTION;
    1133             : 
    1134             :         szName = JS_ToCString(c, argv[0]);
    1135           0 :         e = gf_node_get_field_by_name(n, (char *) szName, &info);
    1136           0 :         JS_FreeCString(c, szName);
    1137           0 :         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           0 :         return JS_FALSE;
    1184             : }
    1185             : 
    1186           0 : 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           0 :         GF_Node *n = dom_get_element(c, obj);
    1193           0 :         if (!n) return JS_EXCEPTION;
    1194             : 
    1195           0 :         if (argc!=2) return JS_EXCEPTION;
    1196           0 :         if (!JS_IsString(argv[0])) return JS_EXCEPTION;
    1197           0 :         if (!JS_IsObject(argv[1])) return JS_EXCEPTION;
    1198           0 :         rgb = JS_GetOpaque(argv[1], rgbClass.class_id);
    1199           0 :         if (!rgb) return JS_EXCEPTION;
    1200             : 
    1201             :         szName = JS_ToCString(c, argv[0]);
    1202           0 :         e = gf_node_get_field_by_name(n, (char *) szName, &info);
    1203           0 :         JS_FreeCString(c, szName);
    1204           0 :         if (e != GF_OK) return JS_EXCEPTION;
    1205             : 
    1206           0 :         switch (info.fieldType) {
    1207           0 :         case SVG_Color_datatype:
    1208             :         {
    1209           0 :                 SVG_Color *col = (SVG_Color *)info.far_ptr;
    1210           0 :                 col->type = SVG_COLOR_RGBCOLOR;
    1211           0 :                 col->red = FLT2FIX(rgb->r / 255.0f);
    1212           0 :                 col->green = FLT2FIX(rgb->g / 255.0f);
    1213           0 :                 col->blue = FLT2FIX(rgb->b / 255.0f);
    1214           0 :                 dom_node_changed(n, GF_FALSE, &info);
    1215           0 :                 return JS_TRUE;
    1216             :         }
    1217           0 :         case SVG_Paint_datatype:
    1218             :         {
    1219           0 :                 SVG_Paint *paint = (SVG_Paint *)info.far_ptr;
    1220           0 :                 paint->type = SVG_PAINT_COLOR;
    1221           0 :                 paint->color.type = SVG_COLOR_RGBCOLOR;
    1222           0 :                 paint->color.red = FLT2FIX(rgb->r / 255.0f);
    1223           0 :                 paint->color.green = FLT2FIX(rgb->g / 255.0f);
    1224           0 :                 paint->color.blue = FLT2FIX(rgb->b / 255.0f);
    1225           0 :                 dom_node_changed(n, GF_FALSE, &info);
    1226           0 :                 return JS_TRUE;
    1227             :         }
    1228             :         }
    1229           0 :         return JS_FALSE;
    1230             : }
    1231             : 
    1232           0 : static JSValue svg_get_bbox(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool get_screen)
    1233             : {
    1234             :         GF_JSAPIParam par;
    1235           0 :         GF_Node *n = dom_get_element(c, obj);
    1236           0 :         if (!n || argc) return JS_EXCEPTION;
    1237             : 
    1238           0 :         par.bbox.is_set = GF_FALSE;
    1239           0 :         if (ScriptAction(n->sgprivate->scenegraph, get_screen ? GF_JSAPI_OP_GET_SCREEN_BBOX : GF_JSAPI_OP_GET_LOCAL_BBOX, (GF_Node *)n, &par) ) {
    1240           0 :                 if (par.bbox.is_set) {
    1241           0 :                         rectCI *rc = (rectCI *)gf_malloc(sizeof(rectCI));
    1242           0 :                         if (!rc) return JS_EXCEPTION;
    1243           0 :                         JSValue rO = JS_NewObjectClass(c, rectClass.class_id);
    1244           0 :                         rc->sg = NULL;
    1245           0 :                         rc->x = FIX2FLT(par.bbox.min_edge.x);
    1246             :                         /*BBox is in 3D coord system style*/
    1247           0 :                         rc->y = FIX2FLT(par.bbox.min_edge.y);
    1248           0 :                         rc->w = FIX2FLT(par.bbox.max_edge.x - par.bbox.min_edge.x);
    1249           0 :                         rc->h = FIX2FLT(par.bbox.max_edge.y - par.bbox.min_edge.y);
    1250           0 :                         JS_SetOpaque(rO, rc);
    1251           0 :                         return rO;
    1252             :                 } else {
    1253           0 :                         return JS_NULL;
    1254             :                 }
    1255             :                 return JS_TRUE;
    1256             :         }
    1257           0 :         return JS_FALSE;
    1258             : }
    1259             : 
    1260           0 : static JSValue svg_udom_get_local_bbox(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1261             : {
    1262           0 :         return svg_get_bbox(c, obj, argc, argv, GF_FALSE);
    1263             : }
    1264           0 : static JSValue svg_udom_get_screen_bbox(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1265             : {
    1266           0 :         return svg_get_bbox(c, obj, argc, argv, GF_TRUE);
    1267             : }
    1268             : 
    1269           0 : static JSValue svg_udom_get_screen_ctm(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1270             : {
    1271             :         GF_JSAPIParam par;
    1272           0 :         GF_Node *n = dom_get_element(c, obj);
    1273           0 :         if (!n || argc) return JS_EXCEPTION;
    1274             : 
    1275           0 :         if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_GET_TRANSFORM, (GF_Node *)n, &par)) {
    1276           0 :                 GF_Matrix2D *mx = (GF_Matrix2D *)gf_malloc(sizeof(GF_Matrix2D));
    1277           0 :                 if (!mx) return JS_EXCEPTION;
    1278           0 :                 JSValue mO = JS_NewObjectClass(c, matrixClass.class_id);
    1279           0 :                 gf_mx2d_from_mx(mx, &par.mx);
    1280           0 :                 JS_SetOpaque(mO, mx);
    1281           0 :                 return mO;
    1282             :         }
    1283           0 :         return JS_EXCEPTION;
    1284             : }
    1285             : 
    1286           0 : 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           0 :         GF_Node *n = dom_get_element(c, obj);
    1292           0 :         if (!n) return JS_EXCEPTION;
    1293           0 :         if (argc!=6) return JS_EXCEPTION;
    1294             : 
    1295           0 :         GF_SAFEALLOC(mx, GF_Matrix2D)
    1296           0 :         if (!mx) return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
    1297             : 
    1298           0 :         JS_ToFloat64(c, &v, argv[0]);
    1299           0 :         mx->m[0] = FLT2FIX(v);
    1300           0 :         JS_ToFloat64(c, &v, argv[1]);
    1301           0 :         mx->m[3] = FLT2FIX(v);
    1302           0 :         JS_ToFloat64(c, &v, argv[2]);
    1303           0 :         mx->m[1] = FLT2FIX(v);
    1304           0 :         JS_ToFloat64(c, &v, argv[3]);
    1305           0 :         mx->m[4] = FLT2FIX(v);
    1306           0 :         JS_ToFloat64(c, &v, argv[4]);
    1307           0 :         mx->m[2] = FLT2FIX(v);
    1308           0 :         JS_ToFloat64(c, &v, argv[5]);
    1309           0 :         mx->m[5] = FLT2FIX(v);
    1310           0 :         mat = JS_NewObjectClass(c, matrixClass.class_id);
    1311           0 :         JS_SetOpaque(mat, mx);
    1312           0 :         return mat;
    1313             : }
    1314             : 
    1315           0 : static JSValue svg_udom_create_rect(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1316             : {
    1317             :         rectCI *rc;
    1318             :         JSValue r;
    1319           0 :         GF_Node *n = dom_get_element(c, obj);
    1320           0 :         if (!n || argc) return JS_EXCEPTION;
    1321             : 
    1322           0 :         GF_SAFEALLOC(rc, rectCI);
    1323           0 :         if (!rc) return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
    1324           0 :         r = JS_NewObjectClass(c, rectClass.class_id);
    1325           0 :         JS_SetOpaque(r, rc);
    1326           0 :         return r;
    1327             : }
    1328             : 
    1329           0 : static JSValue svg_udom_create_point(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1330             : {
    1331             :         pointCI *pt;
    1332             :         JSValue r;
    1333           0 :         GF_Node *n = dom_get_element(c, obj);
    1334           0 :         if (!n || argc) return JS_EXCEPTION;
    1335             : 
    1336           0 :         GF_SAFEALLOC(pt, pointCI);
    1337           0 :         if (!pt) return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
    1338           0 :         r = JS_NewObjectClass(c, pointClass.class_id);
    1339           0 :         JS_SetOpaque(r, pt);
    1340           0 :         return r;
    1341             : }
    1342             : 
    1343           0 : static JSValue svg_udom_create_path(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1344             : {
    1345             :         pathCI *path;
    1346             :         JSValue p;
    1347           0 :         GF_Node *n = dom_get_element(c, obj);
    1348           0 :         if (!n || argc) return JS_EXCEPTION;
    1349             : 
    1350           0 :         GF_SAFEALLOC(path, pathCI);
    1351           0 :         if (!path) return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
    1352           0 :         p = JS_NewObjectClass(c, pathClass.class_id);
    1353           0 :         JS_SetOpaque(p, path);
    1354           0 :         return p;
    1355             : }
    1356             : 
    1357           0 : static JSValue svg_udom_create_color(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1358             : {
    1359             :         rgbCI *col;
    1360             :         JSValue p;
    1361           0 :         GF_Node *n = dom_get_element(c, obj);
    1362           0 :         if (!n|| (argc!=3)) return JS_EXCEPTION;
    1363             : 
    1364           0 :         GF_SAFEALLOC(col, rgbCI);
    1365           0 :         if (!col) return js_throw_err(c, GF_DOM_EXC_DATA_CLONE_ERR);
    1366             : 
    1367           0 :         JS_ToInt32(c, &col->r, argv[0]);
    1368           0 :         JS_ToInt32(c, &col->g, argv[1]);
    1369           0 :         JS_ToInt32(c, &col->b, argv[2]);
    1370           0 :         p = JS_NewObjectClass(c, rgbClass.class_id);
    1371           0 :         JS_SetOpaque(p, col);
    1372           0 :         return p;
    1373             : }
    1374             : 
    1375           0 : 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           0 :         GF_Node *n = (GF_Node *)dom_get_element(c, obj);
    1381           0 :         if (!n) return JS_EXCEPTION;
    1382           0 :         if (n->sgprivate->tag != TAG_SVG_path) return JS_EXCEPTION;
    1383             : 
    1384           0 :         gf_node_get_field_by_name(n, "d", &info);
    1385           0 :         if (info.fieldType == SVG_PathData_datatype) {
    1386             : #if USE_GF_PATH
    1387           0 :                 GF_Path *p = (GF_Path *)info.far_ptr;
    1388           0 :                 GF_PathIterator *path_it = gf_path_iterator_new(p);
    1389           0 :                 if (path_it) {
    1390           0 :                         Fixed len = gf_path_iterator_get_length(path_it);
    1391           0 :                         length = FIX2FLT(len);
    1392           0 :                         gf_path_iterator_del(path_it);
    1393             :                 }
    1394             : #endif
    1395             :         }
    1396             :         return JS_NewFloat64(c, length);
    1397             : }
    1398             : 
    1399           0 : static JSValue svg_udom_move_focus(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1400             : {
    1401             :         GF_JSAPIParam par;
    1402           0 :         GF_Node *n = dom_get_element(c, obj);
    1403           0 :         if (!n) return JS_EXCEPTION;
    1404           0 :         if ((argc!=1) || !JS_IsObject(argv[0])) return JS_EXCEPTION;
    1405             : 
    1406           0 :         JS_ToInt32(c, &par.opt, argv[1]);
    1407           0 :         if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_SET_FOCUS, (GF_Node *)n, &par))
    1408           0 :                 return JS_TRUE;
    1409           0 :         return JS_FALSE;
    1410             : }
    1411             : 
    1412           0 : static JSValue svg_udom_set_focus(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1413             : {
    1414             :         GF_JSAPIParam par;
    1415           0 :         GF_Node *n = dom_get_element(c, obj);
    1416           0 :         if (!n) return JS_EXCEPTION;
    1417           0 :         if ((argc!=1) || !JS_IsObject(argv[0])) return JS_EXCEPTION;
    1418             : 
    1419           0 :         par.node = dom_get_element(c, argv[0]);
    1420             :         /*NOT IN THE GRAPH*/
    1421           0 :         if (!par.node || !par.node->sgprivate->num_instances) return JS_EXCEPTION;
    1422           0 :         if (ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_SET_FOCUS, (GF_Node *)n, &par))
    1423           0 :                 return JS_TRUE;
    1424           0 :         return JS_TRUE;
    1425             : }
    1426             : 
    1427           0 : static JSValue svg_udom_get_focus(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1428             : {
    1429             :         GF_JSAPIParam par;
    1430           0 :         GF_Node *n = dom_get_element(c, obj);
    1431           0 :         if (!n || argc) return JS_EXCEPTION;
    1432             : 
    1433           0 :         if (!ScriptAction(n->sgprivate->scenegraph, GF_JSAPI_OP_GET_FOCUS, (GF_Node *)n, &par))
    1434           0 :                 return JS_EXCEPTION;
    1435             : 
    1436           0 :         if (par.node) {
    1437           0 :                 return dom_element_construct(c, par.node);
    1438             :         }
    1439           0 :         return JS_NULL;
    1440             : }
    1441             : 
    1442           0 : static JSValue svg_udom_get_time(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1443             : {
    1444           0 :         GF_Node *n = dom_get_element(c, obj);
    1445           0 :         if (!n) return JS_EXCEPTION;
    1446             : 
    1447           0 :         return JS_NewFloat64(c, gf_node_get_scene_time(n) );
    1448             : }
    1449             : 
    1450             : 
    1451           0 : static JSValue svg_connection_create(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1452             : {
    1453           0 :         return js_throw_err(c, GF_DOM_EXC_NOT_SUPPORTED_ERR);
    1454             : }
    1455             : 
    1456          14 : static void baseCI_finalize(JSRuntime *rt, JSValue obj)
    1457             : {
    1458             :         /*avoids GCC warning*/
    1459          14 :         void *data = JS_GetOpaque_Nocheck(obj);
    1460          14 :         if (data) gf_free(data);
    1461          14 : }
    1462             : 
    1463           0 : static JSValue rgb_getProperty(JSContext *c, JSValueConst obj, int magic)
    1464             : {
    1465           0 :         rgbCI *col = (rgbCI *) JS_GetOpaque(obj, rgbClass.class_id);
    1466           0 :         if (!col) return JS_EXCEPTION;
    1467           0 :         switch (magic) {
    1468           0 :         case 0: return JS_NewInt32(c, col->r);
    1469           0 :         case 1: return JS_NewInt32(c, col->g);
    1470           0 :         case 2: return JS_NewInt32(c, col->b);
    1471           0 :         default:
    1472           0 :                 return JS_EXCEPTION;
    1473             :         }
    1474             : }
    1475           0 : static JSValue rgb_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
    1476             : {
    1477           0 :         rgbCI *col = (rgbCI *) JS_GetOpaque(obj, rgbClass.class_id);
    1478           0 :         if (!col) return JS_EXCEPTION;
    1479             : 
    1480           0 :         switch (magic) {
    1481           0 :         case 0: return JS_ToInt32(c, &col->r, value) ? JS_EXCEPTION : JS_TRUE;
    1482           0 :         case 1: return JS_ToInt32(c, &col->g, value) ? JS_EXCEPTION : JS_TRUE;
    1483           0 :         case 2: return JS_ToInt32(c, &col->b, value) ? JS_EXCEPTION : JS_TRUE;
    1484           0 :         default:
    1485           0 :                 return JS_EXCEPTION;
    1486             :         }
    1487             : }
    1488             : 
    1489           4 : static JSValue rect_getProperty(JSContext *c, JSValueConst obj, int magic)
    1490             : {
    1491           4 :         rectCI *rc = (rectCI *) JS_GetOpaque(obj, rectClass.class_id);
    1492           4 :         if (!rc) return JS_EXCEPTION;
    1493           4 :         if (rc->sg) {
    1494             :                 GF_JSAPIParam par;
    1495           0 :                 if (!ScriptAction(rc->sg, GF_JSAPI_OP_GET_VIEWPORT, rc->sg->RootNode, &par)) {
    1496           0 :                         return JS_EXCEPTION;
    1497             :                 }
    1498           0 :                 rc->x = FIX2FLT(par.rc.x);
    1499           0 :                 rc->y = FIX2FLT(par.rc.y);
    1500           0 :                 rc->w = FIX2FLT(par.rc.width);
    1501           0 :                 rc->h = FIX2FLT(par.rc.height);
    1502             :         }
    1503           4 :         switch (magic) {
    1504           0 :         case 0: return JS_NewFloat64(c, rc->x);
    1505           0 :         case 1: return JS_NewFloat64(c, rc->y);
    1506           2 :         case 2: return JS_NewFloat64(c, rc->w);
    1507           2 :         case 3: return JS_NewFloat64(c, rc->h);
    1508           0 :         default:
    1509           0 :                 return JS_EXCEPTION;
    1510             :         }
    1511             : }
    1512             : 
    1513           0 : static JSValue rect_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
    1514             : {
    1515             :         Double d;
    1516           0 :         rectCI *rc = (rectCI *) JS_GetOpaque(obj, rectClass.class_id);
    1517           0 :         if (!rc) return JS_EXCEPTION;
    1518           0 :         if (JS_ToFloat64(c, &d, value)) return JS_EXCEPTION;
    1519           0 :         switch (magic) {
    1520           0 :         case 0:
    1521           0 :                 rc->x = (Float) d;
    1522           0 :                 return JS_TRUE;
    1523           0 :         case 1:
    1524           0 :                 rc->y = (Float) d;
    1525           0 :                 return JS_TRUE;
    1526           0 :         case 2:
    1527           0 :                 rc->w = (Float) d;
    1528           0 :                 return JS_TRUE;
    1529           0 :         case 3:
    1530           0 :                 rc->h = (Float) d;
    1531           0 :                 return JS_TRUE;
    1532           0 :         default:
    1533           0 :                 return JS_EXCEPTION;
    1534             :         }
    1535             : }
    1536             : 
    1537           0 : static JSValue point_getProperty(JSContext *c, JSValueConst obj, int magic)
    1538             : {
    1539           0 :         pointCI *pt = (pointCI *) JS_GetOpaque(obj, pointClass.class_id);
    1540           0 :         if (!pt) return JS_EXCEPTION;
    1541             : 
    1542           0 :         if (pt->sg) {
    1543             :                 GF_JSAPIParam par;
    1544           0 :                 if (!ScriptAction(pt->sg, GF_JSAPI_OP_GET_TRANSLATE, pt->sg->RootNode, &par)) {
    1545           0 :                         return JS_EXCEPTION;
    1546             :                 }
    1547           0 :                 pt->x = FIX2FLT(par.pt.x);
    1548           0 :                 pt->y = FIX2FLT(par.pt.y);
    1549             :         }
    1550           0 :         switch (magic) {
    1551           0 :         case 0: return JS_NewFloat64(c, pt->x);
    1552           0 :         case 1: return JS_NewFloat64(c, pt->y);
    1553           0 :         default: return JS_EXCEPTION;
    1554             :         }
    1555             : }
    1556             : 
    1557           0 : static JSValue point_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
    1558             : {
    1559           0 :         pointCI *pt = (pointCI *) JS_GetOpaque(obj, pointClass.class_id);
    1560           0 :         if (!pt) return JS_EXCEPTION;
    1561             : 
    1562             :         Double d;
    1563           0 :         if (JS_ToFloat64(c, &d, value)) return JS_EXCEPTION;
    1564           0 :         switch (magic) {
    1565           0 :         case 0:
    1566           0 :                 pt->x = (Float) d;
    1567           0 :                 break;
    1568           0 :         case 1:
    1569           0 :                 pt->y = (Float) d;
    1570           0 :                 break;
    1571           0 :         default:
    1572           0 :                 return JS_EXCEPTION;
    1573             :         }
    1574           0 :         if (pt->sg) {
    1575             :                 GF_JSAPIParam par;
    1576           0 :                 par.pt.x = FLT2FIX(pt->x);
    1577           0 :                 par.pt.y = FLT2FIX(pt->y);
    1578           0 :                 ScriptAction(pt->sg, GF_JSAPI_OP_SET_TRANSLATE, pt->sg->RootNode, &par);
    1579             :         }
    1580           0 :         return JS_UNDEFINED;
    1581             : }
    1582             : 
    1583             : static JSValue svg_new_path_object(JSContext *c, SVG_PathData *d)
    1584             : {
    1585             : #if USE_GF_PATH
    1586           0 :         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             : 
    1611           3 : static void pathCI_finalize(JSRuntime *rt, JSValue obj)
    1612             : {
    1613           3 :         pathCI *p = (pathCI *) JS_GetOpaque(obj, pathClass.class_id);
    1614           3 :         if (p) {
    1615           0 :                 if (p->pts) gf_free(p->pts);
    1616           0 :                 if (p->tags) gf_free(p->tags);
    1617           0 :                 gf_free(p);
    1618             :         }
    1619           3 : }
    1620             : 
    1621           0 : static JSValue path_getProperty(JSContext *c, JSValueConst obj, int magic)
    1622             : {
    1623           0 :         pathCI *p = (pathCI *) JS_GetOpaque(obj, pathClass.class_id);
    1624           0 :         if (!p) return JS_EXCEPTION;
    1625           0 :         switch (magic) {
    1626           0 :         case 0: return JS_NewInt32(c, p->nb_coms);
    1627           0 :         default:
    1628           0 :                 return JS_EXCEPTION;
    1629             :         }
    1630             : }
    1631             : 
    1632           0 : static JSValue svg_path_get_segment(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1633             : {
    1634             :         u32 idx;
    1635           0 :         pathCI *p = (pathCI *) JS_GetOpaque(obj, pathClass.class_id);
    1636           0 :         if (!p) return JS_EXCEPTION;
    1637           0 :         if ((argc!=1) || JS_ToInt32(c, &idx, argv[0])) return JS_EXCEPTION;
    1638           0 :         if (idx>=p->nb_coms) return JS_TRUE;
    1639           0 :         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           0 :         return JS_EXCEPTION;
    1652             : }
    1653             : 
    1654           0 : 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           0 :         pathCI *p = (pathCI *) JS_GetOpaque(obj, pathClass.class_id);
    1659           0 :         if (!p) return JS_EXCEPTION;
    1660             : 
    1661           0 :         if ((argc!=2) || !JS_IsInteger(argv[0]) || !JS_IsInteger(argv[1])) return JS_EXCEPTION;
    1662           0 :         if (JS_ToInt32(c, &idx, argv[0])) return JS_EXCEPTION;
    1663           0 :         if (JS_ToInt32(c, &param_idx, argv[1])) return JS_EXCEPTION;
    1664           0 :         if (idx>=p->nb_coms) return JS_TRUE;
    1665             :         pt_idx = 0;
    1666           0 :         for (i=0; i<idx; i++) {
    1667           0 :                 switch (p->tags[i]) {
    1668           0 :                 case 0:
    1669           0 :                         pt_idx++;
    1670           0 :                         break;
    1671           0 :                 case 1:
    1672           0 :                         pt_idx++;
    1673           0 :                         break;
    1674           0 :                 case 2:
    1675           0 :                         pt_idx+=3;
    1676           0 :                         break;
    1677           0 :                 case 3:
    1678           0 :                         pt_idx+=2;
    1679           0 :                         break;
    1680           0 :                 case 4:
    1681           0 :                         pt_idx+=2;
    1682           0 :                         break;
    1683           0 :                 case 5:
    1684           0 :                         pt_idx+=1;
    1685           0 :                         break;
    1686             :                 }
    1687             :         }
    1688           0 :         switch (p->tags[idx]) {
    1689           0 :         case 0:
    1690             :         case 1:
    1691           0 :                 if (param_idx>1) return JS_TRUE;
    1692           0 :                 pt = &p->pts[pt_idx];
    1693           0 :                 return JS_NewFloat64(c, param_idx ? pt->y : pt->x);
    1694           0 :         case 2:/* Curve To */
    1695           0 :                 if (param_idx>5) return JS_TRUE;
    1696           0 :                 pt = &p->pts[pt_idx + (param_idx/2) ];
    1697           0 :                 return JS_NewFloat64(c, (param_idx%2) ? pt->y : pt->x);
    1698           0 :         case 3:/* Next Curve To */
    1699           0 :                 if (param_idx>5) return JS_TRUE;
    1700           0 :                 if (param_idx<2) {
    1701           0 :                         pt = &p->pts[pt_idx - 1];
    1702           0 :                         return JS_NewFloat64(c, param_idx ? pt->y : pt->x);
    1703             :                 }
    1704           0 :                 param_idx-=2;
    1705           0 :                 pt = &p->pts[pt_idx + (param_idx/2)];
    1706           0 :                 return JS_NewFloat64(c, (param_idx%2) ? pt->y : pt->x);
    1707             : 
    1708           0 :         case 4:/* Quad To */
    1709           0 :                 if (param_idx>3) return JS_TRUE;
    1710           0 :                 pt = &p->pts[pt_idx + (param_idx/2) ];
    1711           0 :                 return JS_NewFloat64(c, (param_idx%2) ? pt->y : pt->x);
    1712             : 
    1713           0 :         case 5:/* Next Quad To */
    1714           0 :                 if (param_idx>3) return JS_TRUE;
    1715           0 :                 if (param_idx<2) {
    1716           0 :                         pt = &p->pts[pt_idx - 1];
    1717           0 :                         return JS_NewFloat64(c, param_idx ? pt->y : pt->x);
    1718             :                 } else {
    1719           0 :                         param_idx-=2;
    1720           0 :                         pt = &p->pts[pt_idx];
    1721           0 :                         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           0 :         return JS_EXCEPTION;
    1729             : }
    1730             : 
    1731           0 : static u32 svg_path_realloc_pts(pathCI *p, u32 nb_pts)
    1732             : {
    1733             :         u32 i, orig_pts;
    1734             :         orig_pts = 0;
    1735           0 :         for (i=0; i<p->nb_coms; i++) {
    1736           0 :                 switch (p->tags[i]) {
    1737           0 :                 case 0:
    1738           0 :                         orig_pts++;
    1739           0 :                         break;
    1740           0 :                 case 1:
    1741           0 :                         orig_pts++;
    1742           0 :                         break;
    1743           0 :                 case 2:
    1744           0 :                         orig_pts+=3;
    1745           0 :                         break;
    1746           0 :                 case 3:
    1747           0 :                         orig_pts+=2;
    1748           0 :                         break;
    1749           0 :                 case 4:
    1750           0 :                         orig_pts+=2;
    1751           0 :                         break;
    1752           0 :                 case 5:
    1753           0 :                         orig_pts+=1;
    1754           0 :                         break;
    1755             :                 }
    1756             :         }
    1757           0 :         p->pts = (ptCI *)gf_realloc(p->pts, sizeof(ptCI)*(nb_pts+orig_pts));
    1758           0 :         return orig_pts;
    1759             : }
    1760             : 
    1761           0 : 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           0 :         p = (pathCI *) JS_GetOpaque(obj, pathClass.class_id);
    1768           0 :         if (!p || (argc!=2)) return JS_EXCEPTION;
    1769             : 
    1770           0 :         if (JS_ToFloat64(c, &x, argv[0])) return JS_EXCEPTION;
    1771           0 :         if (JS_ToFloat64(c, &y, argv[1])) return JS_EXCEPTION;
    1772           0 :         nb_pts = svg_path_realloc_pts(p, 1);
    1773           0 :         p->pts[nb_pts].x = (Float) x;
    1774           0 :         p->pts[nb_pts].y = (Float) y;
    1775           0 :         p->tags = (u8 *)gf_realloc(p->tags, sizeof(u8)*(p->nb_coms+1) );
    1776           0 :         p->tags[p->nb_coms] = 0;
    1777           0 :         p->nb_coms++;
    1778           0 :         return JS_TRUE;
    1779             : }
    1780             : 
    1781           0 : 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           0 :         p = (pathCI *) JS_GetOpaque(obj, pathClass.class_id);
    1787           0 :         if (!p || (argc!=2)) return JS_EXCEPTION;
    1788             : 
    1789           0 :         if (JS_ToFloat64(c, &x, argv[0])) return JS_EXCEPTION;
    1790           0 :         if (JS_ToFloat64(c, &y, argv[1])) return JS_EXCEPTION;
    1791             : 
    1792           0 :         nb_pts = svg_path_realloc_pts(p, 1);
    1793           0 :         p->pts[nb_pts].x = (Float) x;
    1794           0 :         p->pts[nb_pts].y = (Float) y;
    1795           0 :         p->tags = (u8 *)gf_realloc(p->tags, sizeof(u8)*(p->nb_coms+1) );
    1796           0 :         p->tags[p->nb_coms] = 1;
    1797           0 :         p->nb_coms++;
    1798           0 :         return JS_TRUE;
    1799             : }
    1800             : 
    1801           0 : 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           0 :         p = (pathCI *) JS_GetOpaque(obj, pathClass.class_id);
    1808           0 :         if (!p || (argc!=4)) return JS_EXCEPTION;
    1809             : 
    1810           0 :         if (JS_ToFloat64(c, &x1, argv[0])) return JS_EXCEPTION;
    1811           0 :         if (JS_ToFloat64(c, &y1, argv[1])) return JS_EXCEPTION;
    1812           0 :         if (JS_ToFloat64(c, &x2, argv[2])) return JS_EXCEPTION;
    1813           0 :         if (JS_ToFloat64(c, &y2, argv[3])) return JS_EXCEPTION;
    1814           0 :         nb_pts = svg_path_realloc_pts(p, 2);
    1815           0 :         p->pts[nb_pts].x = (Float) x1;
    1816           0 :         p->pts[nb_pts].y = (Float) y1;
    1817           0 :         p->pts[nb_pts+1].x = (Float) x2;
    1818           0 :         p->pts[nb_pts+1].y = (Float) y2;
    1819           0 :         p->tags = (u8 *)gf_realloc(p->tags, sizeof(u8)*(p->nb_coms+1) );
    1820           0 :         p->tags[p->nb_coms] = 4;
    1821           0 :         p->nb_coms++;
    1822           0 :         return JS_TRUE;
    1823             : }
    1824             : 
    1825           0 : 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           0 :         p = (pathCI *) JS_GetOpaque(obj, pathClass.class_id);
    1832           0 :         if (!p || (argc!=6)) return JS_EXCEPTION;
    1833             : 
    1834           0 :         if (JS_ToFloat64(c, &x1, argv[0])) return JS_EXCEPTION;
    1835           0 :         if (JS_ToFloat64(c, &y1, argv[1])) return JS_EXCEPTION;
    1836           0 :         if (JS_ToFloat64(c, &x2, argv[2])) return JS_EXCEPTION;
    1837           0 :         if (JS_ToFloat64(c, &y2, argv[3])) return JS_EXCEPTION;
    1838           0 :         if (JS_ToFloat64(c, &x, argv[4])) return JS_EXCEPTION;
    1839           0 :         if (JS_ToFloat64(c, &y, argv[5])) return JS_EXCEPTION;
    1840           0 :         nb_pts = svg_path_realloc_pts(p, 3);
    1841           0 :         p->pts[nb_pts].x = (Float) x1;
    1842           0 :         p->pts[nb_pts].y = (Float) y1;
    1843           0 :         p->pts[nb_pts+1].x = (Float) x2;
    1844           0 :         p->pts[nb_pts+1].y = (Float) y2;
    1845           0 :         p->pts[nb_pts+2].x = (Float) x;
    1846           0 :         p->pts[nb_pts+2].y = (Float) y;
    1847           0 :         p->tags = (u8 *)gf_realloc(p->tags, sizeof(u8)*(p->nb_coms+1) );
    1848           0 :         p->tags[p->nb_coms] = 2;
    1849           0 :         p->nb_coms++;
    1850           0 :         return JS_TRUE;
    1851             : }
    1852             : 
    1853           0 : static JSValue svg_path_close(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1854             : {
    1855           0 :         pathCI *p = (pathCI *) JS_GetOpaque(obj, pathClass.class_id);
    1856           0 :         if (!p) return JS_EXCEPTION;
    1857             : 
    1858           0 :         p->tags = (u8 *)gf_realloc(p->tags, sizeof(u8)*(p->nb_coms+1) );
    1859           0 :         p->tags[p->nb_coms] = 6;
    1860           0 :         p->nb_coms++;
    1861           0 :         return JS_TRUE;
    1862             : }
    1863             : 
    1864             : 
    1865           0 : static JSValue matrix_getProperty(JSContext *c, JSValueConst obj, int magic)
    1866             : {
    1867           0 :         GF_Matrix2D *mx = (GF_Matrix2D *) JS_GetOpaque(obj, matrixClass.class_id);
    1868           0 :         if (!mx) return JS_EXCEPTION;
    1869             : 
    1870           0 :         switch (magic) {
    1871           0 :         case 0: return JS_NewFloat64(c, FIX2FLT(mx->m[0]));
    1872           0 :         case 1: return JS_NewFloat64(c, FIX2FLT(mx->m[3]));
    1873           0 :         case 2: return JS_NewFloat64(c, FIX2FLT(mx->m[1]));
    1874           0 :         case 3: return JS_NewFloat64(c, FIX2FLT(mx->m[4]));
    1875           0 :         case 4: return JS_NewFloat64(c, FIX2FLT(mx->m[2]));
    1876           0 :         case 5: return JS_NewFloat64(c, FIX2FLT(mx->m[5]));
    1877           0 :         default:
    1878           0 :                 return JS_EXCEPTION;
    1879             :         }
    1880             : }
    1881             : 
    1882           0 : static JSValue matrix_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
    1883             : {
    1884             :         Double d;
    1885           0 :         GF_Matrix2D *mx = (GF_Matrix2D *) JS_GetOpaque(obj, matrixClass.class_id);
    1886           0 :         if (!mx) return JS_EXCEPTION;
    1887           0 :         if (JS_ToFloat64(c, &d, value)) return JS_EXCEPTION;
    1888             : 
    1889           0 :         switch (magic) {
    1890           0 :         case 0:
    1891           0 :                 mx->m[0] = FLT2FIX(d);
    1892           0 :                 break;
    1893           0 :         case 1:
    1894           0 :                 mx->m[3] = FLT2FIX(d);
    1895           0 :                 break;
    1896           0 :         case 2:
    1897           0 :                 mx->m[1] = FLT2FIX(d);
    1898           0 :                 break;
    1899           0 :         case 3:
    1900           0 :                 mx->m[4] = FLT2FIX(d);
    1901           0 :                 break;
    1902           0 :         case 4:
    1903           0 :                 mx->m[2] = FLT2FIX(d);
    1904           0 :                 break;
    1905           0 :         case 5:
    1906           0 :                 mx->m[5] = FLT2FIX(d);
    1907           0 :                 break;
    1908             :         default:
    1909             :                 break;
    1910             :         }
    1911           0 :         return JS_EXCEPTION;
    1912             : }
    1913             : 
    1914           0 : static JSValue svg_mx2d_get_component(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1915             : {
    1916             :         u32 comp;
    1917           0 :         GF_Matrix2D *mx = (GF_Matrix2D *) JS_GetOpaque(obj, matrixClass.class_id);
    1918           0 :         if (!mx || (argc!=1)) return JS_EXCEPTION;
    1919           0 :         if (JS_ToInt32(c, &comp, argv[0])) return JS_EXCEPTION;
    1920             : 
    1921           0 :         switch (comp) {
    1922           0 :         case 0: return JS_NewFloat64(c, FIX2FLT(mx->m[0]));
    1923           0 :         case 1: return JS_NewFloat64(c, FIX2FLT(mx->m[3]));
    1924           0 :         case 2: return JS_NewFloat64(c, FIX2FLT(mx->m[1]));
    1925           0 :         case 3: return JS_NewFloat64(c, FIX2FLT(mx->m[4]));
    1926           0 :         case 4: return JS_NewFloat64(c, FIX2FLT(mx->m[2]));
    1927           0 :         case 5: return JS_NewFloat64(c, FIX2FLT(mx->m[5]));
    1928             :         }
    1929           0 :         return JS_EXCEPTION;
    1930             : }
    1931             : 
    1932           0 : static JSValue svg_mx2d_multiply(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1933             : {
    1934             :         GF_Matrix2D *mx1, *mx2;
    1935           0 :         mx1 = (GF_Matrix2D *) JS_GetOpaque(obj, matrixClass.class_id);
    1936           0 :         if (!mx1 || (argc!=1)) return JS_EXCEPTION;
    1937           0 :         mx2 = (GF_Matrix2D *) JS_GetOpaque(argv[0], matrixClass.class_id);
    1938           0 :         if (!mx2) return JS_EXCEPTION;
    1939             : 
    1940           0 :         gf_mx2d_add_matrix(mx1, mx2);
    1941             :         return JS_DupValue(c, obj);
    1942             : }
    1943             : 
    1944           0 : static JSValue svg_mx2d_inverse(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1945             : {
    1946           0 :         GF_Matrix2D *mx = (GF_Matrix2D *) JS_GetOpaque(obj, matrixClass.class_id);
    1947           0 :         if (!mx) return JS_EXCEPTION;
    1948           0 :         gf_mx2d_inverse(mx);
    1949             :         return JS_DupValue(c, obj);
    1950             : }
    1951             : 
    1952           0 : static JSValue svg_mx2d_translate(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1953             : {
    1954             :         Double x, y;
    1955             :         GF_Matrix2D *mx1, mx2;
    1956           0 :         mx1 = (GF_Matrix2D *) JS_GetOpaque(obj, matrixClass.class_id);
    1957           0 :         if (!mx1 || (argc!=2)) return JS_EXCEPTION;
    1958             : 
    1959           0 :         if (JS_ToFloat64(c, &x, argv[0]) || JS_ToFloat64(c, &y, argv[1])) return JS_EXCEPTION;
    1960             : 
    1961           0 :         gf_mx2d_init(mx2);
    1962           0 :         mx2.m[2] = FLT2FIX(x);
    1963           0 :         mx2.m[5] = FLT2FIX(y);
    1964           0 :         gf_mx2d_pre_multiply(mx1, &mx2);
    1965             :         return JS_DupValue(c, obj);
    1966             : }
    1967             : 
    1968           0 : static JSValue svg_mx2d_scale(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1969             : {
    1970             :         Double scale;
    1971             :         GF_Matrix2D *mx1, mx2;
    1972           0 :         mx1 = (GF_Matrix2D *) JS_GetOpaque(obj, matrixClass.class_id);
    1973           0 :         if (!mx1 || (argc!=2)) return JS_EXCEPTION;
    1974           0 :         if (JS_ToFloat64(c, &scale, argv[0])) return JS_EXCEPTION;
    1975             : 
    1976             :         gf_mx2d_init(mx2);
    1977           0 :         mx2.m[0] = mx2.m[4] = FLT2FIX(scale);
    1978           0 :         gf_mx2d_pre_multiply(mx1, &mx2);
    1979             :         return JS_DupValue(c, obj);
    1980             : }
    1981             : 
    1982           0 : static JSValue svg_mx2d_rotate(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
    1983             : {
    1984             :         Double angle;
    1985             :         GF_Matrix2D *mx1, mx2;
    1986             : 
    1987           0 :         mx1 = (GF_Matrix2D *) JS_GetOpaque(obj, matrixClass.class_id);
    1988           0 :         if (!mx1 || (argc!=2)) return JS_EXCEPTION;
    1989           0 :         if (JS_ToFloat64(c, &angle, argv[0])) return JS_EXCEPTION;
    1990             : 
    1991           0 :         gf_mx2d_init(mx2);
    1992           0 :         gf_mx2d_add_rotation(&mx2, 0, 0, gf_mulfix(FLT2FIX(angle/180), GF_PI));
    1993           0 :         gf_mx2d_pre_multiply(mx1, &mx2);
    1994             :         return JS_DupValue(c, obj);
    1995             : }
    1996             : 
    1997           0 : JSValue svg_udom_new_rect(JSContext *c, Fixed x, Fixed y, Fixed width, Fixed height)
    1998             : {
    1999           0 :         rectCI *rc = (rectCI *)gf_malloc(sizeof(rectCI));
    2000           0 :         if (!rc) return JS_EXCEPTION;
    2001           0 :         JSValue r = JS_NewObjectClass(c, rectClass.class_id);
    2002           0 :         rc->x = FIX2FLT(x);
    2003           0 :         rc->y = FIX2FLT(y);
    2004           0 :         rc->w = FIX2FLT(width);
    2005           0 :         rc->h = FIX2FLT(height);
    2006           0 :         rc->sg = NULL;
    2007           0 :         JS_SetOpaque(r, rc);
    2008           0 :         return r;
    2009             : }
    2010             : 
    2011           0 : JSValue svg_udom_new_point(JSContext *c, Fixed x, Fixed y)
    2012             : {
    2013           0 :         pointCI *pt = (pointCI *)gf_malloc(sizeof(pointCI));
    2014           0 :         if (!pt) return JS_EXCEPTION;
    2015           0 :         JSValue p = JS_NewObjectClass(c, pointClass.class_id);
    2016           0 :         pt->x = FIX2FLT(x);
    2017           0 :         pt->y = FIX2FLT(y);
    2018           0 :         pt->sg = NULL;
    2019           0 :         JS_SetOpaque(p, pt);
    2020           0 :         return p;
    2021             : }
    2022             : 
    2023             : #ifdef GPAC_ENABLE_HTML5_MEDIA
    2024             : void *html_get_element_class(GF_Node *n);
    2025             : #endif
    2026             : 
    2027          90 : JSClassID svg_get_element_class(GF_Node *n)
    2028             : {
    2029          90 :         if (!n) return 0;
    2030          90 :         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          90 :                 return svgElement.class_id;
    2038             :         }
    2039             :         return 0;
    2040             : }
    2041           3 : JSClassID svg_get_document_class(GF_SceneGraph *sg)
    2042             : {
    2043           3 :         GF_Node *n = sg->RootNode;
    2044           3 :         if (!n) return 0;
    2045           3 :         if ((n->sgprivate->tag>=GF_NODE_RANGE_FIRST_SVG) && (n->sgprivate->tag<=GF_NODE_RANGE_LAST_SVG))
    2046           3 :                 return svgDocument.class_id;
    2047             :         return 0;
    2048             : }
    2049             : 
    2050          37 : Bool is_svg_document_class(JSContext *c, JSValue obj)
    2051             : {
    2052          37 :         void *ptr = JS_GetOpaque(obj, svgDocument.class_id);
    2053          37 :         if (ptr) return GF_TRUE;
    2054          37 :         return GF_FALSE;
    2055             : }
    2056             : 
    2057          37 : Bool is_svg_element_class(JSContext *c, JSValue obj)
    2058             : {
    2059          37 :         void *ptr = JS_GetOpaque(obj, svgElement.class_id);
    2060          37 :         if (ptr) return GF_TRUE;
    2061          37 :         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             : 
    2229           3 : static void svg_init_js_api(GF_SceneGraph *scene)
    2230             : {
    2231           3 :         JSContext *c = scene->svg_js->js_ctx;
    2232           3 :         JSRuntime *jsrt = JS_GetRuntime(c);
    2233           3 :         JSValue global = JS_GetGlobalObject(scene->svg_js->js_ctx);
    2234             : 
    2235           3 :         SETUP_JSCLASS(svg_globalClass, "Window", globalFuncs, NULL, NULL, 0);
    2236           3 :         scene->svg_js->global = JS_NewObjectClass(c, svg_globalClass.class_id);
    2237           3 :         JS_SetOpaque(scene->svg_js->global, scene);
    2238           3 :         JS_SetPropertyStr(c, global, "Window", scene->svg_js->global);
    2239             : 
    2240           3 :         JS_SetPropertyStr(c, global, "alert", JS_NewCFunction(c, js_print, "alert", 1));
    2241             :         
    2242             :         /*initialize DOM core */
    2243           3 :         dom_js_load(scene, scene->svg_js->js_ctx);
    2244             : 
    2245           3 :         qjs_module_init_xhr_global(c, global);
    2246             : 
    2247           3 :         svg_define_udom_exception(scene->svg_js->js_ctx, scene->svg_js->global);
    2248           3 :         JSValue console = JS_NewObject(c);
    2249           3 :         JS_SetPropertyStr(c, console, "log", JS_NewCFunction(c, js_print, "print", 1));
    2250           3 :         JS_SetPropertyStr(c, global, "console", console);
    2251             : 
    2252           3 :         svgDocument.class.gc_mark = domDocument_gc_mark;
    2253           3 :         SETUP_JSCLASS(svgDocument, "SVGDocument", documentFuncs, NULL, dom_document_finalize, dom_js_get_document_proto(c));
    2254           3 :         svgElement.class.gc_mark = domElement_gc_mark;
    2255           3 :         SETUP_JSCLASS(svgElement, "SVGElement", svg_elementFuncs, NULL, dom_element_finalize, dom_js_get_element_proto(c));
    2256             : 
    2257           3 :         SETUP_JSCLASS(rgbClass, "SVGRGBColor", rgb_Funcs, NULL, baseCI_finalize, 0);
    2258           3 :         SETUP_JSCLASS(rectClass, "SVGRect", rect_Funcs, NULL, baseCI_finalize, 0);
    2259           3 :         SETUP_JSCLASS(pointClass, "SVGPoint", point_Funcs, NULL, baseCI_finalize, 0);
    2260           3 :         SETUP_JSCLASS(matrixClass, "SVGMatrix", matrix_Funcs, NULL, baseCI_finalize, 0);
    2261             : 
    2262           3 :         SETUP_JSCLASS(pathClass, "SVGPath", path_Funcs, NULL, pathCI_finalize, 0);
    2263             : 
    2264             : 
    2265           3 :         JS_SetPropertyStr(c, scene->svg_js->pathClass.proto, "MOVE_TO", JS_NewInt32(c, 77));
    2266           3 :         JS_SetPropertyStr(c, scene->svg_js->pathClass.proto, "LINE_TO", JS_NewInt32(c, 76));
    2267           3 :         JS_SetPropertyStr(c, scene->svg_js->pathClass.proto, "CURVE_TO", JS_NewInt32(c, 67));
    2268           3 :         JS_SetPropertyStr(c, scene->svg_js->pathClass.proto, "QUAD_TO", JS_NewInt32(c, 81));
    2269           3 :         JS_SetPropertyStr(c, scene->svg_js->pathClass.proto, "CLOSE", JS_NewInt32(c, 90));
    2270             : 
    2271             :         /*we have our own constructors*/
    2272           3 :         scene->get_element_class = svg_get_element_class;
    2273           3 :         scene->get_document_class = svg_get_document_class;
    2274             : 
    2275             :         /*create document object*/
    2276           3 :         dom_js_define_document(scene->svg_js->js_ctx, global, scene);
    2277             :         /*create event object, and remember it*/
    2278           3 :         scene->svg_js->event = dom_js_define_event(scene->svg_js->js_ctx);
    2279             : 
    2280             :         JS_FreeValue(c, global);
    2281           3 : }
    2282             : 
    2283             : GF_DOM_Event *dom_get_evt_private(JSValue v);
    2284             : 
    2285         331 : JSContext *svg_script_get_context(GF_SceneGraph *sg)
    2286             : {
    2287         331 :         return sg->svg_js ? sg->svg_js->js_ctx : NULL;
    2288             : }
    2289             : 
    2290           0 : 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           0 :         char *sep = strchr(utf8_script, '(');
    2297             : 
    2298           0 :         if (!sep) {
    2299             :                 strcpy(szFuncName, utf8_script);
    2300             :                 strcat(szFuncName, "(evt)");
    2301             :                 utf8_script = szFuncName;
    2302             :         }
    2303             : 
    2304           0 :         gf_js_lock(sg->svg_js->js_ctx, GF_TRUE);
    2305             : 
    2306           0 :         prev_event = dom_get_evt_private(sg->svg_js->event);
    2307           0 :         JS_SetOpaque(sg->svg_js->event, event);
    2308           0 :         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           0 :         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           0 :         if (JS_IsException(ret)) {
    2324           0 :                 js_dump_error(sg->svg_js->js_ctx);
    2325             :                 ok=GF_FALSE;
    2326             :         }
    2327           0 :         JS_FreeValue(sg->svg_js->js_ctx, ret);
    2328             : 
    2329           0 :         if (sg->svg_js->force_gc) {
    2330           0 :                 gf_js_call_gc(sg->svg_js->js_ctx);
    2331           0 :                 sg->svg_js->force_gc = GF_FALSE;
    2332             :         }
    2333           0 :         js_do_loop(sg->svg_js->js_ctx);
    2334           0 :         gf_js_lock(sg->svg_js->js_ctx, GF_FALSE);
    2335             : 
    2336           0 :         return ok;
    2337             : }
    2338             : 
    2339             : #ifdef GPAC_ENABLE_HTML5_MEDIA
    2340             : void html_media_js_api_del();
    2341             : #endif
    2342             : 
    2343           3 : void gf_svg_script_context_del(GF_SVGJS *svg_js, GF_SceneGraph *scenegraph)
    2344             : {
    2345           3 :         gf_sg_js_dom_pre_destroy(JS_GetRuntime(svg_js->js_ctx), scenegraph, NULL);
    2346           3 :         gf_js_delete_context(svg_js->js_ctx);
    2347           3 :         dom_js_unload();
    2348             : #ifdef GPAC_ENABLE_HTML5_MEDIA
    2349             :         /* HTML */
    2350             :         html_media_js_api_del();
    2351             : #endif
    2352             : 
    2353           3 :         gf_free(svg_js);
    2354           3 :         scenegraph->svg_js = NULL;
    2355             : 
    2356           3 : }
    2357             : 
    2358         199 : static void svg_script_predestroy(GF_Node *n, void *eff, Bool is_destroy)
    2359             : {
    2360         199 :         if (is_destroy) {
    2361           3 :                 GF_SVGJS *svg_js = n->sgprivate->scenegraph->svg_js;
    2362             :                 /*unregister script from parent scene (cf base_scenegraph::sg_reset) */
    2363           3 :                 gf_list_del_item(n->sgprivate->scenegraph->scripts, n);
    2364             : 
    2365           3 :                 if (svg_js->nb_scripts) {
    2366           3 :                         svg_js->nb_scripts--;
    2367             : 
    2368             :                         /*detach this script from our object cache*/
    2369           3 :                         gf_sg_js_dom_pre_destroy(JS_GetRuntime(svg_js->js_ctx), n->sgprivate->scenegraph, n);
    2370             : 
    2371           3 :                         if (!svg_js->nb_scripts) {
    2372           3 :                                 gf_svg_script_context_del(svg_js, n->sgprivate->scenegraph);
    2373             :                         }
    2374             :                 }
    2375             :         }
    2376         199 : }
    2377             : 
    2378           3 : GF_Err JSScript_CreateSVGContext(GF_SceneGraph *sg)
    2379             : {
    2380             :         GF_SVGJS *svg_js;
    2381             : 
    2382           3 :         if (sg->svg_js) {
    2383             :                 /* the JS/SVG context is already created, no need to do anything  */
    2384             :                 return GF_OK;
    2385             :         }
    2386             : 
    2387           3 :         GF_SAFEALLOC(svg_js, GF_SVGJS);
    2388           3 :         if (!svg_js) {
    2389             :                 return GF_OUT_OF_MEM;
    2390             :         }
    2391             :         /*create new ecmascript context*/
    2392           3 :         svg_js->js_ctx = gf_js_create_context();
    2393           3 :         if (!svg_js->js_ctx) {
    2394           0 :                 gf_free(svg_js);
    2395           0 :                 return GF_SCRIPT_ERROR;
    2396             :         }
    2397             : 
    2398           3 :         gf_js_lock(svg_js->js_ctx, GF_TRUE);
    2399             : 
    2400           3 :         sg->svg_js = svg_js;
    2401             :         /*load SVG & DOM APIs*/
    2402           3 :         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           3 :         svg_js->script_execute = svg_script_execute;
    2411           3 :         svg_js->handler_execute = svg_script_execute_handler;
    2412             : 
    2413           3 :         gf_js_lock(svg_js->js_ctx, GF_FALSE);
    2414             : 
    2415           3 :         return GF_OK;
    2416             : }
    2417             : 
    2418           0 : GF_DOMText *svg_get_text_child(GF_Node *node)
    2419             : {
    2420             :         GF_ChildNodeItem *child;
    2421             :         GF_DOMText *txt;
    2422             :         txt = NULL;
    2423           1 :         child = ((SVG_Element*)node)->children;
    2424           1 :         if (! child) return NULL;
    2425           0 :         while (child) {
    2426           0 :                 txt = (GF_DOMText*)child->node;
    2427           0 :                 if ((txt->sgprivate->tag==TAG_DOMText) && txt->textContent) return txt;
    2428             :                 txt = NULL;
    2429           0 :                 child = child->next;
    2430             :         }
    2431             :         return NULL;
    2432             : }
    2433             : 
    2434           2 : 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           2 :         svg_js = script->sgprivate->scenegraph->svg_js;
    2446           2 :         if (!strnicmp(file, "file://", 7)) file += 7;
    2447             : 
    2448           2 :         if (!gf_file_exists(file)) {
    2449             :                 GF_JSAPIParam par;
    2450           0 :                 GF_SceneGraph *scene = script->sgprivate->scenegraph;
    2451           0 :                 par.uri.url = file;
    2452           0 :                 if (scene->script_action && scene->script_action(scene->script_action_cbck, GF_JSAPI_OP_RESOLVE_XLINK, script, &par))
    2453           0 :                         abs_url = (char *) par.uri.url;
    2454             : 
    2455           0 :                 if (abs_url || !gf_file_exists(abs_url)) {
    2456           0 :                         if (abs_url) gf_free(abs_url);
    2457           0 :                         return GF_FALSE;
    2458             :                 }
    2459             :         }
    2460             : 
    2461           0 :         e = gf_file_load_data(abs_url ? abs_url : file, &jsscript, &fsize);
    2462           2 :         if (abs_url) gf_free(abs_url);
    2463             : 
    2464           2 :         if (e!=GF_OK) return GF_FALSE;
    2465             : 
    2466             :         /*for handler, only load code*/
    2467           2 :         if (script->sgprivate->tag==TAG_SVG_handler) {
    2468           0 :                 GF_DOMText *txt = gf_dom_add_text_node(script, jsscript);
    2469           0 :                 txt->type = GF_DOM_TEXT_INSERTED;
    2470           0 :                 return GF_TRUE;
    2471             :         }
    2472             : 
    2473           2 :         gf_js_lock(svg_js->js_ctx, GF_TRUE);
    2474             : 
    2475           2 :         if (!gf_opts_get_bool("core", "no-js-mods") && JS_DetectModule((const char *) jsscript, fsize )) {
    2476             :                 flags = JS_EVAL_TYPE_MODULE;
    2477           0 :                 svg_js->use_strict = GF_TRUE;
    2478             :         }
    2479             : 
    2480           2 :         ret = JS_Eval(svg_js->js_ctx, jsscript, sizeof(char)*fsize, file, flags);
    2481           2 :         if (JS_IsException(ret)) {
    2482           0 :                 js_dump_error(svg_js->js_ctx);
    2483             :                 success=GF_FALSE;
    2484             :         }
    2485           2 :         JS_FreeValue(svg_js->js_ctx, ret);
    2486           2 :         if (svg_js->force_gc) {
    2487           0 :                 gf_js_call_gc(svg_js->js_ctx);
    2488           0 :                 svg_js->force_gc = GF_FALSE;
    2489             :         }
    2490           2 :         gf_js_lock(svg_js->js_ctx, GF_FALSE);
    2491             : 
    2492           2 :         gf_dom_listener_process_add(script->sgprivate->scenegraph);
    2493             : 
    2494           2 :         gf_free(jsscript);
    2495           2 :         return success;
    2496             : }
    2497             : 
    2498             : #include <gpac/download.h>
    2499             : #include <gpac/network.h>
    2500             : 
    2501             : 
    2502           3 : void JSScript_LoadSVG(GF_Node *node)
    2503             : {
    2504             :         GF_DOMText *txt;
    2505             :         GF_SVGJS *svg_js;
    2506             :         GF_FieldInfo href_info;
    2507             : 
    2508           3 :         if (!node->sgprivate->scenegraph->svg_js) {
    2509           4 :                 if (JSScript_CreateSVGContext(node->sgprivate->scenegraph) != GF_OK) return;
    2510             :         }
    2511             : 
    2512             :         /*register script with parent scene (cf base_scenegraph::sg_reset) */
    2513           3 :         gf_list_add(node->sgprivate->scenegraph->scripts, node);
    2514             : 
    2515           3 :         svg_js = node->sgprivate->scenegraph->svg_js;
    2516           3 :         if (!node->sgprivate->UserCallback) {
    2517           3 :                 svg_js->nb_scripts++;
    2518           3 :                 node->sgprivate->UserCallback = svg_script_predestroy;
    2519             :         }
    2520             :         /*if href download the script file*/
    2521           3 :         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           2 :                 XMLRI *xmlri = (XMLRI *)href_info.far_ptr;
    2527             : 
    2528             :                 /* getting a download manager */
    2529           2 :                 par.dnld_man = NULL;
    2530           2 :                 ScriptAction(node->sgprivate->scenegraph, GF_JSAPI_OP_GET_DOWNLOAD_MANAGER, NULL, &par);
    2531           2 :                 dnld_man = par.dnld_man;
    2532             : 
    2533             : 
    2534             :                 /* resolve the uri of the script*/
    2535           2 :                 par.uri.nb_params = 0;
    2536           2 :                 par.uri.url = xmlri->string;
    2537           2 :                 ScriptAction(node->sgprivate->scenegraph, GF_JSAPI_OP_RESOLVE_URI, node, &par);
    2538           2 :                 url = (char *)par.uri.url;
    2539             : 
    2540             :                 /* if the file is local, we don't need to download it */
    2541           2 :                 if (!strstr(url, "://") || !strnicmp(url, "file://", 7)) {
    2542           2 :                         svg_js_load_script(node, url);
    2543           0 :                 } else if (dnld_man) {
    2544             :                         /*fetch the remote script synchronously and load it - cf section on script processing in SVG specs*/
    2545           0 :                         GF_DownloadSession *sess = gf_dm_sess_new(dnld_man, url, GF_NETIO_SESSION_NOT_THREADED, NULL, NULL, &e);
    2546           0 :                         if (sess) {
    2547           0 :                                 e = gf_dm_sess_process(sess);
    2548           0 :                                 if (e==GF_OK) {
    2549           0 :                                         const char *szCache = gf_dm_sess_get_cache_name(sess);
    2550           0 :                                         if (!svg_js_load_script(node, (char *) szCache))
    2551           0 :                                                 e = GF_SCRIPT_ERROR;
    2552             :                                 }
    2553           0 :                                 gf_dm_sess_del(sess);
    2554             :                         }
    2555           0 :                         if (e) {
    2556           0 :                                 par.info.e = e;
    2557           0 :                                 par.info.msg = "Cannot fetch script";
    2558           0 :                                 ScriptAction(node->sgprivate->scenegraph, GF_JSAPI_OP_MESSAGE, NULL, &par);
    2559             :                         }
    2560             :                 }
    2561           2 :                 gf_free(url);
    2562             :         }
    2563             :         /*for scripts only, execute*/
    2564           1 :         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           1 :                 if (!txt) return;
    2571           0 :                 txtlen = (u32) strlen(txt->textContent);
    2572             : 
    2573           0 :                 if (!gf_opts_get_bool("core", "no-js-mods") && JS_DetectModule((const char *) txt, txtlen )) {
    2574             :                         flags = JS_EVAL_TYPE_MODULE;
    2575           0 :                         svg_js->use_strict = GF_TRUE;
    2576             :                 }
    2577             : 
    2578           0 :                 ret = JS_Eval(svg_js->js_ctx, txt->textContent, (u32) strlen(txt->textContent), "inline_script", flags);
    2579           0 :                 if (JS_IsException(ret)) {
    2580           0 :                         js_dump_error(svg_js->js_ctx);
    2581             :                 }
    2582           0 :                 JS_FreeValue(svg_js->js_ctx, ret);
    2583           0 :                 gf_dom_listener_process_add(node->sgprivate->scenegraph);
    2584           0 :                 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
    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             : */
    2609           0 : 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           0 :         if (utf8_script) {
    2622           0 :                 if (!node) return GF_FALSE;
    2623             :                 hdl = NULL;
    2624             :         } else {
    2625           0 :                 if (JS_IsUndefined(hdl->js_data->fun_val) && JS_IsUndefined(hdl->js_data->evt_listen_obj)) {
    2626             :                         txt = svg_get_text_child(node);
    2627           0 :                         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           0 :         svg_js = node->sgprivate->scenegraph->svg_js;
    2634             : 
    2635             : #ifndef GPAC_DISABLE_LOG
    2636           0 :         if (gf_log_tool_level_on(GF_LOG_SCRIPT, GF_LOG_DEBUG)) {
    2637             :                 char *content, *_content = NULL;
    2638           0 :                 if (utf8_script) {
    2639             :                         content = utf8_script;
    2640           0 :                 } else if (!JS_IsUndefined(hdl->js_data->fun_val)) {
    2641           0 :                         content = _content = (char *) JS_ToCString(svg_js->js_ctx, hdl->js_data->fun_val);
    2642           0 :                 } else if (txt) {
    2643           0 :                         content = txt->textContent;
    2644             :                 } else {
    2645             :                         content = "unknown";
    2646             :                 }
    2647           0 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_SCRIPT, ("[DOM Events    ] Executing script code from handler: %s\n", content) );
    2648           0 :                 JS_FreeCString(svg_js->js_ctx, _content);
    2649             :         }
    2650             : #endif
    2651             : 
    2652           0 :         gf_js_lock(svg_js->js_ctx, GF_TRUE);
    2653           0 :         prev_event = dom_get_evt_private(svg_js->event);
    2654             :         /*break loops*/
    2655           0 :         if (prev_event && (prev_event->type==event->type) && (prev_event->target==event->target)) {
    2656           0 :                 gf_js_lock(svg_js->js_ctx, GF_FALSE);
    2657           0 :                 return GF_FALSE;
    2658             :         }
    2659           0 :         JS_SetOpaque(svg_js->event, event);
    2660             : 
    2661           0 :         svg_js->in_script = GF_TRUE;
    2662           0 :         if (svg_js->use_strict)
    2663             :                 flags = JS_EVAL_TYPE_MODULE;
    2664             : 
    2665             :         /*if an observer is being specified, use it*/
    2666           0 :         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           0 :         else __this = observer ? dom_element_construct(svg_js->js_ctx, observer) : svg_js->global;
    2669             : 
    2670           0 :         if (txt && hdl && hdl->js_data && !JS_IsUndefined(hdl->js_data->fun_val)) {
    2671           0 :                 hdl->js_data->fun_val = JS_EvalThis(svg_js->js_ctx, __this, txt->textContent, strlen(txt->textContent), "handler", flags|JS_EVAL_FLAG_COMPILE_ONLY);
    2672             :         }
    2673             : 
    2674           0 :         if (utf8_script) {
    2675           0 :                 ret = JS_EvalThis(svg_js->js_ctx, __this, utf8_script, (u32) strlen(utf8_script), "inline script", flags);
    2676             :         }
    2677           0 :         else if (hdl && hdl->js_data
    2678           0 :                 && (!JS_IsUndefined(hdl->js_data->fun_val) || !JS_IsUndefined(hdl->js_data->evt_listen_obj) )
    2679           0 :         ) {
    2680             :                 JSValue evt;
    2681             :                 JSValue argv[1];
    2682           0 :                 evt = gf_dom_new_event(svg_js->js_ctx);
    2683           0 :                 JS_SetOpaque(evt, event);
    2684           0 :                 argv[0] = evt;
    2685             : 
    2686           0 :                 if (!JS_IsUndefined(hdl->js_data->fun_val) ) {
    2687           0 :                         ret = JS_Call(svg_js->js_ctx, hdl->js_data->fun_val, __this, 1, argv);
    2688             :                 } else {
    2689           0 :                         JSValue fun = JS_GetPropertyStr(svg_js->js_ctx, hdl->js_data->evt_listen_obj, "hanldeEvent");
    2690           0 :                         ret = JS_Call(svg_js->js_ctx, fun, hdl->js_data->evt_listen_obj, 1, argv);
    2691           0 :                         JS_FreeValue(svg_js->js_ctx, fun);
    2692             :                 }
    2693           0 :         } else if (txt) {
    2694           0 :                 JSValue fun = JS_GetPropertyStr(svg_js->js_ctx, svg_js->global, txt->textContent);
    2695           0 :                 if (!JS_IsUndefined(fun)) {
    2696           0 :                         ret = JS_NULL;
    2697           0 :                         if (svg_script_execute(node->sgprivate->scenegraph, txt->textContent, event)) {
    2698             :                                 success = GF_FALSE;
    2699             :                         }
    2700             :                 }
    2701             :                 else {
    2702           0 :                         ret = JS_EvalThis(svg_js->js_ctx, __this, txt->textContent, (u32) strlen(txt->textContent), "internal", flags);
    2703             :                 }
    2704           0 :                 JS_FreeValue(svg_js->js_ctx, fun);
    2705             :         } else {
    2706           0 :                 ret = JS_NULL;
    2707             :         }
    2708           0 :         if (JS_IsException(ret)) {
    2709           0 :                 js_dump_error(svg_js->js_ctx);
    2710             :                 success = GF_FALSE;
    2711             :         }
    2712           0 :         JS_FreeValue(svg_js->js_ctx, ret);
    2713             : 
    2714           0 :         JS_SetOpaque(svg_js->event, prev_event);
    2715           0 :         if (txt && hdl && hdl->js_data) hdl->js_data->fun_val = JS_UNDEFINED;
    2716             : 
    2717           0 :         while (svg_js->force_gc) {
    2718           0 :                 svg_js->force_gc = GF_FALSE;
    2719           0 :                 gf_js_call_gc(svg_js->js_ctx);
    2720             :         }
    2721           0 :         svg_js->in_script = GF_FALSE;
    2722             : 
    2723             :         /*check any pending exception if outer-most event*/
    2724           0 :         if (!prev_event) {
    2725           0 :                 js_do_loop(svg_js->js_ctx);
    2726             :         }
    2727             : 
    2728           0 :         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           0 :         if (!success) {
    2746           0 :                 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

Generated by: LCOV version 1.13