1 //This software module was originally developed by TelecomParisTech in the
2 //course of the development of MPEG-U Widgets (ISO/IEC 23007-1) standard.
3 //
4 //This software module is an implementation of a part of one or
5 //more MPEG-U Widgets (ISO/IEC 23007-1) tools as specified by the MPEG-U Widgets
6 //(ISO/IEC 23007-1) standard. ISO/IEC gives users of the MPEG-U Widgets
7 //(ISO/IEC 23007-1) free license to this software module or modifications
8 //thereof for use in hardware or software products claiming conformance to
9 //the MPEG-U Widgets (ISO/IEC 23007-1). Those intending to use this software
10 //module in hardware or software products are advised that its use may
11 //infringe existing patents.
12 //The original developer of this software module and his/her company, the
13 //subsequent editors and their companies, and ISO/IEC have no liability
14 //for use of this software module or modifications thereof in an implementation.
15 //Copyright is not released for non MPEG-U Widgets (ISO/IEC 23007-1) conforming
16 //products.
17 //Telecom ParisTech retains full right to use the code for his/her own purpose,
18 //assign or donate the code to a third party and to inhibit third parties from
19 //using the code for non MPEG-U Widgets (ISO/IEC 23007-1) conforming products.
20 //
21 //This copyright notice must be included in all copies or derivative works.
22 //
23 //Copyright (c) 2009 Telecom ParisTech.
24 //
25 // Alternatively, this software module may be redistributed and/or modified
26 //  it under the terms of the GNU Lesser General Public License as published by
27 //  the Free Software Foundation; either version 2, or (at your option)
28 //  any later version.
29 //
30 /////////////////////////////////////////////////////////////////////////////////
31 
32 /////////////////////////////////////////////////////////////////////////////////
33 //
34 //	Authors:
35 //					Cyril Concolato, Telecom ParisTech
36 //					Jean Le Feuvre, Telecom ParisTech
37 //
38 /////////////////////////////////////////////////////////////////////////////////
39 
40 
41 #include <gpac/internal/terminal_dev.h>
42 #include <gpac/internal/scenegraph_dev.h>
43 #include <gpac/nodes_svg.h>
44 #include <gpac/constants.h>
45 
46 #if defined(GPAC_HAS_SPIDERMONKEY) && !defined(GPAC_DISABLE_SVG)
47 
48 typedef struct
49 {
50 	GF_Scene *scene;
51 	u8 oti;
52 	char *file_name;
53 	u32 file_size;
54 	Bool loaded;
55 } WgtLoad;
56 
WGT_ProcessData(GF_SceneDecoder * plug,const char * inBuffer,u32 inBufferLength,u16 ES_ID,u32 stream_time,u32 mmlevel)57 static GF_Err WGT_ProcessData(GF_SceneDecoder *plug, const char *inBuffer, u32 inBufferLength,
58                               u16 ES_ID, u32 stream_time, u32 mmlevel)
59 {
60 	GF_Err e = GF_OK;
61 	WgtLoad *wgtload = (WgtLoad *)plug->privateStack;
62 
63 	if (stream_time==(u32)-1) {
64 		gf_sg_reset(wgtload->scene->graph);
65 		return GF_OK;
66 	}
67 
68 	switch (wgtload->oti) {
69 	case GPAC_OTI_PRIVATE_SCENE_WGT:
70 		if (wgtload->file_name && !wgtload->loaded) {
71 			const char *path, *wmpath;
72 			char *tmp;
73 			GF_Node *n, *root;
74 			GF_FieldInfo info;
75 			FILE *jsfile;
76 			GF_ChildNodeItem *last;
77 
78 			wgtload->loaded = GF_TRUE;
79 
80 			gf_sg_add_namespace(wgtload->scene->graph, "http://www.w3.org/2000/svg", NULL);
81 			gf_sg_add_namespace(wgtload->scene->graph, "http://www.w3.org/1999/xlink", "xlink");
82 			gf_sg_add_namespace(wgtload->scene->graph, "http://www.w3.org/2001/xml-events", "ev");
83 			gf_sg_set_scene_size_info(wgtload->scene->graph, 800, 600, GF_TRUE);
84 
85 			/* modify the scene with an Inline/Animation pointing to the widget start file URL */
86 			n = root = gf_node_new(wgtload->scene->graph, TAG_SVG_svg);
87 			gf_node_register(root, NULL);
88 			gf_sg_set_root_node(wgtload->scene->graph, root);
89 			gf_node_get_attribute_by_tag(n, TAG_SVG_ATT_viewBox, GF_TRUE, GF_FALSE, &info);
90 			gf_svg_parse_attribute(n, &info, "0 0 320 240", 0);
91 			gf_node_get_attribute_by_name(n, "xmlns", 0, GF_TRUE, GF_FALSE, &info);
92 			gf_svg_parse_attribute(n, &info, "http://www.w3.org/2000/svg", 0);
93 			/*
94 						gf_sg_set_scene_size_info(wgtload->scene->graph, 800, 600, 1);
95 						gf_node_get_attribute_by_tag(n, TAG_SVG_ATT_width, 1, 0, &info);
96 						gf_svg_parse_attribute(n, &info, "800", 0);
97 						gf_node_get_attribute_by_tag(n, TAG_SVG_ATT_height, 1, 0, &info);
98 						gf_svg_parse_attribute(n, &info, "600", 0);
99 			*/
100 			gf_node_init(n);
101 
102 			n = gf_node_new(wgtload->scene->graph, TAG_SVG_animation);
103 			gf_node_set_id(n, 1, "w_anim");
104 			gf_node_register(n, root);
105 			gf_node_list_add_child_last(&((GF_ParentNode *)root)->children, n, &last);
106 			gf_node_get_attribute_by_tag(n, TAG_SVG_ATT_width, GF_TRUE, GF_FALSE, &info);
107 			gf_svg_parse_attribute(n, &info, "320", 0);
108 			gf_node_get_attribute_by_tag(n, TAG_SVG_ATT_height, GF_TRUE, GF_FALSE, &info);
109 			gf_svg_parse_attribute(n, &info, "240", 0);
110 			gf_node_init(n);
111 
112 			tmp = wgtload->file_name;
113 			while ((tmp = strchr(tmp, '\\'))) {
114 				tmp[0] = '/';
115 				tmp++;
116 			}
117 
118 			n = gf_node_new(wgtload->scene->graph, TAG_SVG_script);
119 			gf_node_register(n, root);
120 			gf_node_list_add_child_last(&((GF_ParentNode *)root)->children, n, &last);
121 			path = gf_opts_get_key("Widgets", "WidgetLoadScript");
122 			jsfile = path ? gf_fopen(path, "rt") : NULL;
123 			if (jsfile) {
124 				gf_fclose(jsfile);
125 				gf_node_get_attribute_by_tag(n, TAG_XLINK_ATT_href, GF_TRUE, GF_FALSE, &info);
126 				gf_svg_parse_attribute(n, &info, (char *) path, 0);
127 			} else {
128 				const char *load_fun = "function load_widget(wid_url) {\n"
129 				                       "	var wid = WidgetManager.load(wid_url);\n"
130 				                       "	var anim = document.getElementById('w_anim');\n"
131 				                       "	if (wid != null) {\n"
132 				                       "		wid.activate(anim);"
133 				                       "		anim.setAttributeNS('http://www.w3.org/1999/xlink', 'href', wid.main);\n"
134 				                       "	} else {\n"
135 				                       "		alert('Widget ' + wid_url + ' is not valid');\n"
136 				                       "	}\n"
137 				                       "}\n";
138 
139 				gf_dom_add_text_node(n, gf_strdup(load_fun) );
140 			}
141 			gf_node_init(n);
142 
143 
144 			wmpath = gf_opts_get_key("Widgets", "WidgetManagerScript");
145 			jsfile = wmpath ? gf_fopen(wmpath, "rt") : NULL;
146 			if (jsfile) {
147 				gf_fclose(jsfile);
148 				n = gf_node_new(wgtload->scene->graph, TAG_SVG_script);
149 				gf_node_register(n, root);
150 				gf_node_list_add_child_last(&((GF_ParentNode *)root)->children, n, &last);
151 				gf_node_get_attribute_by_tag(n, TAG_XLINK_ATT_href, GF_TRUE, GF_FALSE, &info);
152 				gf_svg_parse_attribute(n, &info, (char *) wmpath, 0);
153 				gf_node_init(n);
154 
155 				n = gf_node_new(wgtload->scene->graph, TAG_SVG_script);
156 				gf_node_register(n, root);
157 				gf_node_list_add_child_last(&((GF_ParentNode *)root)->children, n, &last);
158 				gf_dom_add_text_node(n, gf_strdup("widget_manager_init();") );
159 				gf_node_init(n);
160 			}
161 
162 			tmp = (char*)gf_malloc(sizeof(char) * (strlen(wgtload->file_name)+50) );
163 			sprintf(tmp, "load_widget(\"%s\");\n", wgtload->file_name);
164 
165 			n = gf_node_new(wgtload->scene->graph, TAG_SVG_script);
166 			gf_node_register(n, root);
167 			gf_node_list_add_child_last(&((GF_ParentNode *)root)->children, n, &last);
168 			gf_dom_add_text_node(n, gf_strdup(tmp) );
169 			gf_free(tmp);
170 
171 			gf_node_init(n);
172 
173 			if ((wgtload->scene->graph_attached!=1) && (gf_sg_get_root_node(wgtload->scene->graph)!=NULL) ) {
174 				gf_scene_attach_to_compositor(wgtload->scene);
175 				e = GF_EOS;
176 			}
177 		}
178 		break;
179 
180 	default:
181 		return GF_BAD_PARAM;
182 	}
183 	return e;
184 }
185 
WGT_AttachScene(GF_SceneDecoder * plug,GF_Scene * scene,Bool is_scene_decoder)186 static GF_Err WGT_AttachScene(GF_SceneDecoder *plug, GF_Scene *scene, Bool is_scene_decoder)
187 {
188 	WgtLoad *wgtload = (WgtLoad *)plug->privateStack;
189 	wgtload->scene = scene;
190 	return GF_OK;
191 }
192 
WGT_ReleaseScene(GF_SceneDecoder * plug)193 static GF_Err WGT_ReleaseScene(GF_SceneDecoder *plug)
194 {
195 	WgtLoad *wgtload = (WgtLoad *)plug->privateStack;
196 	wgtload->scene = NULL;
197 	return GF_OK;
198 }
199 
WGT_AttachStream(GF_BaseDecoder * plug,GF_ESD * esd)200 static GF_Err WGT_AttachStream(GF_BaseDecoder *plug, GF_ESD *esd)
201 {
202 	GF_BitStream *bs;
203 	WgtLoad *wgtload = (WgtLoad *)plug->privateStack;
204 	if (esd->decoderConfig->upstream) return GF_NOT_SUPPORTED;
205 
206 	/* decSpecInfo is not null only when reading from an WGT file (local or distant, cached or not) */
207 	switch (esd->decoderConfig->objectTypeIndication) {
208 	case GPAC_OTI_PRIVATE_SCENE_WGT:
209 	default:
210 		if (!esd->decoderConfig->decoderSpecificInfo) return GF_NON_COMPLIANT_BITSTREAM;
211 		bs = gf_bs_new(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, GF_BITSTREAM_READ);
212 		wgtload->file_size = gf_bs_read_u32(bs);
213 		gf_bs_del(bs);
214 		wgtload->file_name =  (char *) gf_malloc(sizeof(char)*(1 + esd->decoderConfig->decoderSpecificInfo->dataLength - sizeof(u32)) );
215 		memcpy(wgtload->file_name, esd->decoderConfig->decoderSpecificInfo->data + sizeof(u32), esd->decoderConfig->decoderSpecificInfo->dataLength - sizeof(u32) );
216 		wgtload->file_name[esd->decoderConfig->decoderSpecificInfo->dataLength - sizeof(u32) ] = 0;
217 		break;
218 	}
219 	wgtload->oti = esd->decoderConfig->objectTypeIndication;
220 	return GF_OK;
221 }
222 
WGT_DetachStream(GF_BaseDecoder * plug,u16 ES_ID)223 static GF_Err WGT_DetachStream(GF_BaseDecoder *plug, u16 ES_ID)
224 {
225 	WgtLoad *wgtload = (WgtLoad *)plug->privateStack;
226 	if (wgtload->file_name) gf_free(wgtload->file_name);
227 	wgtload->file_name = NULL;
228 	return GF_OK;
229 }
230 
WGT_GetName(struct _basedecoder * plug)231 const char *WGT_GetName(struct _basedecoder *plug)
232 {
233 	return "GPAC W3C Widget Loader";
234 }
235 
WGT_CanHandleStream(GF_BaseDecoder * ifce,u32 StreamType,GF_ESD * esd,u8 PL)236 static u32 WGT_CanHandleStream(GF_BaseDecoder *ifce, u32 StreamType, GF_ESD *esd, u8 PL)
237 {
238 	/*don't reply to media type query*/
239 	if (!esd) return GF_CODEC_NOT_SUPPORTED;
240 
241 	if (StreamType==GF_STREAM_PRIVATE_SCENE) {
242 		if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_PRIVATE_SCENE_WGT) return GF_CODEC_SUPPORTED;
243 		return GF_CODEC_NOT_SUPPORTED;
244 	}
245 	return GF_CODEC_NOT_SUPPORTED;
246 }
247 
WGT_GetCapabilities(GF_BaseDecoder * plug,GF_CodecCapability * cap)248 static GF_Err WGT_GetCapabilities(GF_BaseDecoder *plug, GF_CodecCapability *cap)
249 {
250 	cap->cap.valueInt = 0;
251 	if (cap->CapCode==GF_CODEC_PADDING_BYTES) {
252 		/* Adding one byte of padding for \r\n problems*/
253 		cap->cap.valueInt = 1;
254 		return GF_OK;
255 	}
256 	return GF_NOT_SUPPORTED;
257 }
258 
WGT_SetCapabilities(GF_BaseDecoder * plug,const GF_CodecCapability capability)259 static GF_Err WGT_SetCapabilities(GF_BaseDecoder *plug, const GF_CodecCapability capability)
260 {
261 	return GF_OK;
262 }
263 
264 /*interface create*/
LoadWidgetReader()265 GF_BaseInterface *LoadWidgetReader()
266 {
267 	WgtLoad *wgtload;
268 	GF_SceneDecoder *sdec;
269 
270 	GF_SAFEALLOC(sdec, GF_SceneDecoder)
271 	if (!sdec) return NULL;
272 	GF_REGISTER_MODULE_INTERFACE(sdec, GF_SCENE_DECODER_INTERFACE, "GPAC W3C Widget Loader", "gpac distribution");
273 
274 	GF_SAFEALLOC(wgtload, WgtLoad);
275 	if (!wgtload) {
276 		gf_free(sdec);
277 		return NULL;
278 	}
279 
280 	sdec->privateStack = wgtload;
281 	sdec->AttachStream = WGT_AttachStream;
282 	sdec->CanHandleStream = WGT_CanHandleStream;
283 	sdec->DetachStream = WGT_DetachStream;
284 	sdec->AttachScene = WGT_AttachScene;
285 	sdec->ReleaseScene = WGT_ReleaseScene;
286 	sdec->ProcessData = WGT_ProcessData;
287 	sdec->GetName = WGT_GetName;
288 	sdec->SetCapabilities = WGT_SetCapabilities;
289 	sdec->GetCapabilities = WGT_GetCapabilities;
290 	return (GF_BaseInterface *)sdec;
291 }
292 
293 
294 /*interface destroy*/
ShutdownWidgetReader(GF_BaseInterface * ifce)295 void ShutdownWidgetReader(GF_BaseInterface *ifce)
296 {
297 	GF_SceneDecoder *sdec = (GF_SceneDecoder *)ifce;
298 	WgtLoad *wgtload;
299 	if (!ifce)
300 		return;
301 	wgtload = (WgtLoad *) sdec->privateStack;
302 	if (wgtload)
303 		gf_free(wgtload);
304 	sdec->privateStack = NULL;
305 	gf_free(sdec);
306 }
307 
308 #endif	/* defined(GPAC_HAS_SPIDERMONKEY) && !defined(GPAC_DISABLE_SVG) */
309