📄 dom_smjs.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Authors: Jean le Feuvre * Copyright (c) 2007-200X ENST * All rights reserved * * This file is part of GPAC / Scene Graph sub-project * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <gpac/internal/scenegraph_dev.h>/*base SVG type*/#include <gpac/nodes_svg_da.h>/*dom events*/#include <gpac/events.h>#include <gpac/download.h>#include <gpac/network.h>#include <gpac/xml.h>#ifdef GPAC_HAS_SPIDERMONKEY#define DOM_CORE_SETUP_CLASS(the_class, cname, flag, getp, setp, fin) \ memset(&the_class, 0, sizeof(the_class)); \ the_class.name = cname; \ the_class.flags = flag; \ the_class.addProperty = JS_PropertyStub; \ the_class.delProperty = JS_PropertyStub; \ the_class.getProperty = getp; \ the_class.setProperty = setp; \ the_class.enumerate = JS_EnumerateStub; \ the_class.resolve = JS_ResolveStub; \ the_class.convert = JS_ConvertStub; \ the_class.finalize = fin;static GFINLINE Bool ScriptAction(GF_SceneGraph *scene, u32 type, GF_Node *node, GF_JSAPIParam *param){ if (scene->script_action) return scene->script_action(scene->script_action_cbck, type, node, param); return 0;}static GFINLINE GF_SceneGraph *xml_get_scenegraph(JSContext *c){ GF_SceneGraph *scene; JSObject *global = JS_GetGlobalObject(c); assert(global); scene = JS_GetPrivate(c, global); assert(scene); return scene;}/************************************************************ * * DOM3 core implementation * * This is NOT a full dom implementation :) * *************************************************************/typedef struct{ u32 nb_inst; JSClass domDocumentClass; JSClass domNodeClass; JSClass domElementClass; JSClass domTextClass; JSClass domNodeListClass; JSClass domEventClass; JSClass xmlHTTPRequestClass;} GF_DOMRuntime;static GF_DOMRuntime *dom_rt = NULL;/*SVG uDOM declarations*/JSBool svg_udom_set_property(JSContext *c, GF_Node *n, u32 svg_prop_id, jsval *vp);JSBool svg_udom_get_property(JSContext *c, GF_Node *_n, u32 svg_prop_id, jsval *vp);JSBool svg_udom_smil_begin(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_smil_end(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_smil_pause(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_smil_resume(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_get_trait(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_get_float_trait(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_get_matrix_trait(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_get_rect_trait(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_get_path_trait(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_get_rgb_color_trait(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_set_trait(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_set_float_trait(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_set_matrix_trait(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_set_rect_trait(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_set_path_trait(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_set_rgb_color_trait(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_get_local_bbox(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_get_screen_bbox(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_get_screen_ctm(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_create_matrix_components(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_create_rect(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_create_path(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_create_color(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_move_focus(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_set_focus(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);JSBool svg_udom_get_focus(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval);jsval svg_udom_new_rect(JSContext *c, Fixed x, Fixed y, Fixed width, Fixed h);jsval svg_udom_new_point(JSContext *c, Fixed x, Fixed y);static JSBool xml_dom3_not_implemented(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ return JS_FALSE;}/*DOM Node functions*/#define JS_DOM3_NODE_FUNCS \ {"insertBefore", xml_node_insert_before, 2}, \ {"replaceChild", xml_node_replace_child, 2}, \ {"removeChild", xml_node_remove_child, 1}, \ {"appendChild", xml_node_append_child, 1}, \ {"hasChildNodes", xml_node_has_children, 0}, \ {"cloneNode", xml_dom3_not_implemented, 1}, \ {"normalize", xml_dom3_not_implemented, 0}, \ {"isSupported", xml_dom3_not_implemented, 2}, \ {"hasAttributes", xml_node_has_attributes, 0}, \ {"compareDocumentPosition", xml_dom3_not_implemented, 1}, \ {"isSameNode", xml_node_is_same_node, 1}, \ {"lookupPrefix", xml_dom3_not_implemented, 1}, \ {"isDefaultNamespace", xml_dom3_not_implemented, 1}, \ {"lookupNamespaceURI", xml_dom3_not_implemented, 1}, \ /*we don't support full node compare*/ \ {"isEqualNode", xml_node_is_same_node, 1}, \ {"getFeature", xml_dom3_not_implemented, 2}, \ {"setUserData", xml_dom3_not_implemented, 3}, \ {"getUserData", xml_dom3_not_implemented, 1},/*DOM Node properties*/#define JS_DOM3_NODE_PROPS \ {"nodeName", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY}, \ {"nodeValue", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT}, \ {"nodeType", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY}, \ {"parentNode", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY}, \ {"childNodes", 4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY}, \ {"firstChild", 5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY}, \ {"lastChild", 6, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY}, \ {"previousSibling", 7, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY}, \ {"nextSibling", 8, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY}, \ {"attributes", 9, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY}, \ {"ownerDocument", 10, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY}, \ {"namespaceURI", 11, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY}, \ {"prefix", 12, JSPROP_ENUMERATE | JSPROP_PERMANENT}, \ {"localName", 13, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY}, \ {"baseURI", 14, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY}, \ {"textContent", 15, JSPROP_ENUMERATE | JSPROP_PERMANENT}, #define JS_DOM3_NODE_LAST_PROP 15#define JS_DOM3_uDOM_FIRST_PROP 18static void dom_node_changed(GF_Node *n, Bool child_modif, GF_FieldInfo *info){ if (!info) { gf_node_changed(n, NULL); } else if (child_modif) { gf_node_dirty_set(n, GF_SG_CHILD_DIRTY, 0); } else { u32 flag = gf_svg_get_rendering_flag_if_modified((SVG_Element *)n, info); gf_node_dirty_set(n, flag, 0); } /*trigger rendering*/ if (n->sgprivate->scenegraph->NodeCallback) n->sgprivate->scenegraph->NodeCallback(n->sgprivate->scenegraph->userpriv, GF_SG_CALLBACK_MODIFIED, n, info);}GF_Node *dom_get_node(JSContext *c, JSObject *obj, Bool *is_doc){ if (is_doc) *is_doc = 0; if (JS_InstanceOf(c, obj, &dom_rt->domDocumentClass, NULL)) { GF_SceneGraph *sg = (GF_SceneGraph *)JS_GetPrivate(c, obj); if (is_doc) *is_doc = 1; return sg->RootNode; } if (JS_InstanceOf(c, obj, &dom_rt->domElementClass, NULL) || JS_InstanceOf(c, obj, &dom_rt->domTextClass, NULL) || JS_InstanceOf(c, obj, &dom_rt->domNodeClass, NULL) ) return (GF_Node *) JS_GetPrivate(c, obj); return NULL;}static jsval dom_document_construct(JSContext *c, GF_SceneGraph *sg){ JSObject *new_obj; if (sg->document) return OBJECT_TO_JSVAL(sg->document); if (sg->reference_count) sg->reference_count++; gf_node_register(sg->RootNode, NULL); new_obj = JS_NewObject(c, &dom_rt->domDocumentClass, 0, 0); JS_SetPrivate(c, new_obj, sg); sg->document = new_obj; return OBJECT_TO_JSVAL(new_obj);}static jsval dom_base_node_construct(JSContext *c, JSClass *_class, GF_Node *n){ GF_SceneGraph *sg; u32 i, count; JSObject *new_obj; if (!n || !n->sgprivate->scenegraph) return JSVAL_VOID; if (n->sgprivate->tag<TAG_DOMText) return JSVAL_VOID; sg = n->sgprivate->scenegraph; count = gf_list_count(sg->objects); for (i=0; i<count; i++) { JSObject *obj = gf_list_get(sg->objects, i); GF_Node *a_node = JS_GetPrivate(c, obj); if (n==a_node) return OBJECT_TO_JSVAL(obj); } if (n->sgprivate->scenegraph->reference_count) n->sgprivate->scenegraph->reference_count ++; gf_node_register(n, NULL); new_obj = JS_NewObject(c, _class, 0, 0); JS_SetPrivate(c, new_obj, n); gf_list_add(sg->objects, new_obj); return OBJECT_TO_JSVAL(new_obj);}static jsval dom_node_construct(JSContext *c, GF_Node *n){ /*in our implementation ONLY ELEMENTS are created, never attributes. We therefore always create Elements when asked to create a node !!*/ return dom_base_node_construct(c, &dom_rt->domElementClass, n);}jsval dom_element_construct(JSContext *c, GF_Node *n){ /*in our implementation ONLY ELEMENTS are created, never attributes. We therefore always create Elements when asked to create a node !!*/ return dom_base_node_construct(c, &dom_rt->domElementClass, n);}static jsval dom_text_construct(JSContext *c, GF_Node *n){ return dom_base_node_construct(c, &dom_rt->domTextClass, n);}Bool dom_is_element(JSContext *c, JSObject *obj){ if (JS_InstanceOf(c, obj, &dom_rt->domElementClass, NULL)) return 1; return 0;}static void dom_unregister_node(GF_Node *n){ GF_SceneGraph *sg = n->sgprivate->scenegraph; if (!sg) return; /*!! node is being deleted !! */ if (!n->sgprivate->num_instances) return; gf_node_unregister(n, NULL); if (sg->reference_count) { sg->reference_count--; if (!sg->reference_count) gf_sg_del(sg); }}static jsval dom_node_get_sibling(JSContext *c, GF_Node *n, Bool is_prev){ s32 idx; GF_ParentNode *par; if (!n) return JSVAL_VOID; par = (GF_ParentNode *)gf_node_get_parent(n, 0); if (!par) return JSVAL_VOID; idx = gf_node_list_find_child(par->children, n); if (idx<0) return JSVAL_VOID; if (is_prev) { idx--; if (idx<0) return JSVAL_VOID; } else idx++; return dom_node_construct(c, gf_node_list_get_child(par->children, idx) );}static char *dom_flatten_text(GF_Node *n){ u32 len = 0; char *res = NULL; GF_ChildNodeItem *list; if (n->sgprivate->tag==TAG_DOMText) return strdup(((GF_DOMText*)n)->textContent); list = ((GF_ParentNode *)n)->children; while (list) { char *t = dom_flatten_text(list->node); if (t) { u32 sub_len = strlen(t); res = realloc(res, sizeof(char)*(len+sub_len+1)); if (!len) res[0] = 0; strcat(res, t); free(t); } list = list->next; } return res;}/*dom3 NodeList/NamedNodeMap*/typedef struct{ /*set if the object is a childList from an existing node*/ GF_ParentNode *owner; /*child list*/ GF_ChildNodeItem *child;} DOMNodeList;static jsval dom_nodelist_construct(JSContext *c, GF_ParentNode *n){ DOMNodeList *nl; JSObject *new_obj; if (!n) return JSVAL_VOID; GF_SAFEALLOC(nl, DOMNodeList); nl->owner = n; if (n->sgprivate->scenegraph->reference_count) n->sgprivate->scenegraph->reference_count++; gf_node_register((GF_Node*)n, NULL); new_obj = JS_NewObject(c, &dom_rt->domNodeListClass, 0, 0); JS_SetPrivate(c, new_obj, nl); return OBJECT_TO_JSVAL(new_obj);}static void dom_nodelist_finalize(JSContext *c, JSObject *obj){ DOMNodeList *nl; if (!JS_InstanceOf(c, obj, &dom_rt->domNodeListClass, NULL) ) return; nl = (DOMNodeList *) JS_GetPrivate(c, obj); if (!nl) return; if (nl->owner) { dom_unregister_node((GF_Node*)nl->owner); } else { /*unregister all nodes for created lists*/ while (nl->child) { GF_ChildNodeItem *child = nl->child; nl->child = child->next; dom_unregister_node(child->node); free(child); } } free(nl);}static JSBool dom_nodelist_item(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ GF_Node *n; u32 idx, count; DOMNodeList *nl; if (!JS_InstanceOf(c, obj, &dom_rt->domNodeListClass, NULL) ) return JS_FALSE; if ((argc!=1) || !JSVAL_IS_INT(argv[0])) return JS_FALSE; nl = (DOMNodeList *)JS_GetPrivate(c, obj); count = gf_node_list_get_count(nl->owner ? nl->owner->children : nl->child); idx = JSVAL_TO_INT(argv[0]); if ((idx<0) || (idx>=count)) { *rval = JSVAL_VOID; return JS_TRUE; } n = gf_node_list_get_child(nl->owner ? nl->owner->children : nl->child, idx); *rval = dom_node_construct(c, n); return JS_TRUE;}static JSBool dom_nodelist_getProperty(JSContext *c, JSObject *obj, jsval id, jsval *vp){ DOMNodeList *nl; if (!JS_InstanceOf(c, obj, &dom_rt->domNodeListClass, NULL) ) return JS_FALSE; if (!JSVAL_IS_INT(id)) return JS_TRUE; switch (JSVAL_TO_INT(id)) { case 0: nl = (DOMNodeList *) JS_GetPrivate(c, obj); *vp = INT_TO_JSVAL( gf_node_list_get_count(nl->owner ? nl->owner->children : nl->child) ); return JS_TRUE; } return JS_FALSE;}static JSBool dom_nodelist_setProperty(JSContext *c, JSObject *obj, jsval id, jsval *vp){ if (!JSVAL_IS_INT(id)) return JS_TRUE; /*no write prop*/ return JS_FALSE;}/*dom event listener*/#define JS_DOM3_EVEN_TARGET_FUNC \ {"addEventListenerNS", dom_event_add_listener, 4}, \ {"removeEventListenerNS", dom_event_remove_listener, 4}, \ {"addEventListener", dom_event_add_listener, 3}, \ {"removeEventListener", dom_event_remove_listener, 3}, \ {"dispatchEvent", xml_dom3_not_implemented, 1},/*eventListeners routines used by document, element and connection interfaces*/JSBool dom_event_add_listener(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ GF_FieldInfo info; GF_Node *listener; SVG_handlerElement *handler; char *type, *callback; u32 of = 0; u32 evtType; char *inNS = NULL; GF_Node *node = NULL; if (JS_InstanceOf(c, obj, &dom_rt->domDocumentClass, NULL) ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -