riched20: Remove unused variables.
[wine] / dlls / mshtml / script.c
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "ole2.h"
29 #include "activscp.h"
30 #include "activdbg.h"
31 #include "objsafe.h"
32
33 #include "wine/debug.h"
34
35 #include "mshtml_private.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
38
39 static const WCHAR windowW[] = {'w','i','n','d','o','w',0};
40 static const WCHAR emptyW[] = {0};
41
42 static const CLSID CLSID_JScript =
43     {0xf414c260,0x6ac0,0x11cf,{0xb6,0xd1,0x00,0xaa,0x00,0xbb,0xbb,0x58}};
44
45 typedef struct {
46     const IActiveScriptSiteVtbl               *lpIActiveScriptSiteVtbl;
47     const IActiveScriptSiteInterruptPollVtbl  *lpIActiveScriptSiteInterruptPollVtbl;
48     const IActiveScriptSiteWindowVtbl         *lpIActiveScriptSiteWindowVtbl;
49     const IActiveScriptSiteDebug32Vtbl        *lpIActiveScriptSiteDebug32Vtbl;
50
51     LONG ref;
52
53     IActiveScript *script;
54     IActiveScriptParse *parse;
55     IActiveScriptParseProcedure *parse_proc;
56
57     SCRIPTSTATE script_state;
58
59     HTMLDocument *doc;
60
61     GUID guid;
62     struct list entry;
63 } ScriptHost;
64
65 #define ACTSCPSITE(x)  ((IActiveScriptSite*)               &(x)->lpIActiveScriptSiteVtbl)
66 #define ACTSCPPOLL(x)  ((IActiveScriptSiteInterruptPoll*)  &(x)->lpIActiveScriptSiteInterruptPollVtbl)
67 #define ACTSCPWIN(x)   ((IActiveScriptSiteWindow*)         &(x)->lpIActiveScriptSiteWindowVtbl)
68 #define ACTSCPDBG32(x) ((IActiveScriptSiteDebug32*)        &(x)->lpIActiveScriptSiteDebug32Vtbl)
69
70 static BOOL init_script_engine(ScriptHost *script_host)
71 {
72     IActiveScriptProperty *property;
73     IObjectSafety *safety;
74     SCRIPTSTATE state;
75     DWORD supported_opts=0, enabled_opts=0;
76     HRESULT hres;
77
78     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptParse, (void**)&script_host->parse);
79     if(FAILED(hres)) {
80         WARN("Could not get IActiveScriptHost: %08x\n", hres);
81         return FALSE;
82     }
83
84     hres = IActiveScript_QueryInterface(script_host->script, &IID_IObjectSafety, (void**)&safety);
85     if(FAILED(hres)) {
86         FIXME("Could not get IObjectSafety: %08x\n", hres);
87         return FALSE;
88     }
89
90     hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, &supported_opts, &enabled_opts);
91     if(FAILED(hres)) {
92         FIXME("GetInterfaceSafetyOptions failed: %08x\n", hres);
93     }else if(!(supported_opts & INTERFACE_USES_DISPEX)) {
94         FIXME("INTERFACE_USES_DISPEX is not supported\n");
95     }else {
96         hres = IObjectSafety_SetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse,
97                 INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER,
98                 INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER);
99         if(FAILED(hres))
100             FIXME("SetInterfaceSafetyOptions failed: %08x\n", hres);
101     }
102
103     IObjectSafety_Release(safety);
104     if(FAILED(hres))
105         return FALSE;
106
107     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptProperty, (void**)&property);
108     if(SUCCEEDED(hres)) {
109         VARIANT var;
110
111         V_VT(&var) = VT_BOOL;
112         V_BOOL(&var) = VARIANT_TRUE;
113         hres = IActiveScriptProperty_SetProperty(property, SCRIPTPROP_HACK_TRIDENTEVENTSINK, NULL, &var);
114         if(FAILED(hres))
115             WARN("SetProperty failed: %08x\n", hres);
116
117         IActiveScriptProperty_Release(property);
118     }else {
119         WARN("Could not get IActiveScriptProperty: %08x\n", hres);
120     }
121
122     hres = IActiveScriptParse_InitNew(script_host->parse);
123     if(FAILED(hres)) {
124         WARN("InitNew failed: %08x\n", hres);
125         return FALSE;
126     }
127
128     hres = IActiveScript_SetScriptSite(script_host->script, ACTSCPSITE(script_host));
129     if(FAILED(hres)) {
130         WARN("SetScriptSite failed: %08x\n", hres);
131         IActiveScript_Close(script_host->script);
132         return FALSE;
133     }
134
135     hres = IActiveScript_GetScriptState(script_host->script, &state);
136     if(FAILED(hres))
137         WARN("GetScriptState failed: %08x\n", hres);
138     else if(state != SCRIPTSTATE_INITIALIZED)
139         FIXME("state = %x\n", state);
140
141     hres = IActiveScript_SetScriptState(script_host->script, SCRIPTSTATE_STARTED);
142     if(FAILED(hres)) {
143         WARN("Starting script failed: %08x\n", hres);
144         return FALSE;
145     }
146
147     hres = IActiveScript_AddNamedItem(script_host->script, windowW,
148             SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS);
149     if(FAILED(hres))
150        WARN("AddNamedItem failed: %08x\n", hres);
151
152     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptParseProcedure2,
153                                         (void**)&script_host->parse_proc);
154     if(FAILED(hres)) {
155         /* FIXME: QI for IActiveScriptParseProcedure */
156         WARN("Could not get IActiveScriptParseProcedure iface: %08x\n", hres);
157     }
158
159     return TRUE;
160 }
161
162 static void release_script_engine(ScriptHost *This)
163 {
164     if(!This->script)
165         return;
166
167     switch(This->script_state) {
168     case SCRIPTSTATE_CONNECTED:
169         IActiveScript_SetScriptState(This->script, SCRIPTSTATE_DISCONNECTED);
170
171     case SCRIPTSTATE_STARTED:
172     case SCRIPTSTATE_DISCONNECTED:
173     case SCRIPTSTATE_INITIALIZED:
174         IActiveScript_Close(This->script);
175
176     default:
177         if(This->parse_proc) {
178             IActiveScriptParseProcedure_Release(This->parse_proc);
179             This->parse_proc = NULL;
180         }
181
182         if(This->parse) {
183             IActiveScriptParse_Release(This->parse);
184             This->parse = NULL;
185         }
186     }
187
188     IActiveScript_Release(This->script);
189     This->script = NULL;
190     This->script_state = SCRIPTSTATE_UNINITIALIZED;
191 }
192
193 void connect_scripts(HTMLDocument *doc)
194 {
195     ScriptHost *iter;
196
197     LIST_FOR_EACH_ENTRY(iter, &doc->script_hosts, ScriptHost, entry) {
198         if(iter->script_state == SCRIPTSTATE_STARTED)
199             IActiveScript_SetScriptState(iter->script, SCRIPTSTATE_CONNECTED);
200     }
201 }
202
203 #define ACTSCPSITE_THIS(iface) DEFINE_THIS(ScriptHost, IActiveScriptSite, iface)
204
205 static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv)
206 {
207     ScriptHost *This = ACTSCPSITE_THIS(iface);
208
209     *ppv = NULL;
210
211     if(IsEqualGUID(&IID_IUnknown, riid)) {
212         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
213         *ppv = ACTSCPSITE(This);
214     }else if(IsEqualGUID(&IID_IActiveScriptSite, riid)) {
215         TRACE("(%p)->(IID_IActiveScriptSite %p)\n", This, ppv);
216         *ppv = ACTSCPSITE(This);
217     }else if(IsEqualGUID(&IID_IActiveScriptSiteInterruptPoll, riid)) {
218         TRACE("(%p)->(IID_IActiveScriptSiteInterruprtPoll %p)\n", This, ppv);
219         *ppv = ACTSCPPOLL(This);
220     }else if(IsEqualGUID(&IID_IActiveScriptSiteWindow, riid)) {
221         TRACE("(%p)->(IID_IActiveScriptSiteWindow %p)\n", This, ppv);
222         *ppv = ACTSCPWIN(This);
223     }else if(IsEqualGUID(&IID_IActiveScriptSiteDebug32, riid)) {
224         TRACE("(%p)->(IID_IActiveScriptSiteDebug32 %p)\n", This, ppv);
225         *ppv = ACTSCPDBG32(This);
226     }else {
227         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
228         return E_NOINTERFACE;
229     }
230
231     IUnknown_AddRef((IUnknown*)*ppv);
232     return S_OK;
233 }
234
235 static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface)
236 {
237     ScriptHost *This = ACTSCPSITE_THIS(iface);
238     LONG ref = InterlockedIncrement(&This->ref);
239
240     TRACE("(%p) ref=%d\n", This, ref);
241
242     return ref;
243 }
244
245 static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface)
246 {
247     ScriptHost *This = ACTSCPSITE_THIS(iface);
248     LONG ref = InterlockedDecrement(&This->ref);
249
250     TRACE("(%p) ref=%d\n", This, ref);
251
252     if(!ref) {
253         release_script_engine(This);
254         if(This->doc)
255             list_remove(&This->entry);
256         heap_free(This);
257     }
258
259     return ref;
260 }
261
262 static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid)
263 {
264     ScriptHost *This = ACTSCPSITE_THIS(iface);
265
266     TRACE("(%p)->(%p)\n", This, plcid);
267
268     *plcid = GetUserDefaultLCID();
269     return S_OK;
270 }
271
272 static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName,
273         DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti)
274 {
275     ScriptHost *This = ACTSCPSITE_THIS(iface);
276
277     TRACE("(%p)->(%s %x %p %p)\n", This, debugstr_w(pstrName), dwReturnMask, ppiunkItem, ppti);
278
279     if(dwReturnMask != SCRIPTINFO_IUNKNOWN) {
280         FIXME("Unsupported mask %x\n", dwReturnMask);
281         return E_NOTIMPL;
282     }
283
284     *ppiunkItem = NULL;
285
286     if(strcmpW(pstrName, windowW))
287         return DISP_E_MEMBERNOTFOUND;
288
289     if(!This->doc)
290         return E_FAIL;
291
292     /* FIXME: Return proxy object */
293     *ppiunkItem = (IUnknown*)HTMLWINDOW2(This->doc->window);
294     IUnknown_AddRef(*ppiunkItem);
295
296     return S_OK;
297 }
298
299 static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *pbstrVersion)
300 {
301     ScriptHost *This = ACTSCPSITE_THIS(iface);
302     FIXME("(%p)->(%p)\n", This, pbstrVersion);
303     return E_NOTIMPL;
304 }
305
306 static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface,
307         const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo)
308 {
309     ScriptHost *This = ACTSCPSITE_THIS(iface);
310     FIXME("(%p)->(%p %p)\n", This, pvarResult, pexcepinfo);
311     return E_NOTIMPL;
312 }
313
314 static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE ssScriptState)
315 {
316     ScriptHost *This = ACTSCPSITE_THIS(iface);
317
318     TRACE("(%p)->(%x)\n", This, ssScriptState);
319
320     This->script_state = ssScriptState;
321     return S_OK;
322 }
323
324 static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror)
325 {
326     ScriptHost *This = ACTSCPSITE_THIS(iface);
327     FIXME("(%p)->(%p)\n", This, pscripterror);
328     return E_NOTIMPL;
329 }
330
331 static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
332 {
333     ScriptHost *This = ACTSCPSITE_THIS(iface);
334
335     TRACE("(%p)->()\n", This);
336
337     return S_OK;
338 }
339
340 static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface)
341 {
342     ScriptHost *This = ACTSCPSITE_THIS(iface);
343
344     TRACE("(%p)->()\n", This);
345
346     return S_OK;
347 }
348
349 #undef ACTSCPSITE_THIS
350
351 static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = {
352     ActiveScriptSite_QueryInterface,
353     ActiveScriptSite_AddRef,
354     ActiveScriptSite_Release,
355     ActiveScriptSite_GetLCID,
356     ActiveScriptSite_GetItemInfo,
357     ActiveScriptSite_GetDocVersionString,
358     ActiveScriptSite_OnScriptTerminate,
359     ActiveScriptSite_OnStateChange,
360     ActiveScriptSite_OnScriptError,
361     ActiveScriptSite_OnEnterScript,
362     ActiveScriptSite_OnLeaveScript
363 };
364
365 #define ACTSCPPOLL_THIS(iface) DEFINE_THIS(ScriptHost, IActiveScriptSiteInterruptPoll, iface)
366
367 static HRESULT WINAPI ActiveScriptSiteInterruptPoll_QueryInterface(IActiveScriptSiteInterruptPoll *iface,
368         REFIID riid, void **ppv)
369 {
370     ScriptHost *This = ACTSCPPOLL_THIS(iface);
371     return IActiveScriptSite_QueryInterface(ACTSCPSITE(This), riid, ppv);
372 }
373
374 static ULONG WINAPI ActiveScriptSiteInterruptPoll_AddRef(IActiveScriptSiteInterruptPoll *iface)
375 {
376     ScriptHost *This = ACTSCPPOLL_THIS(iface);
377     return IActiveScriptSite_AddRef(ACTSCPSITE(This));
378 }
379
380 static ULONG WINAPI ActiveScriptSiteInterruptPoll_Release(IActiveScriptSiteInterruptPoll *iface)
381 {
382     ScriptHost *This = ACTSCPPOLL_THIS(iface);
383     return IActiveScriptSite_Release(ACTSCPSITE(This));
384 }
385
386 static HRESULT WINAPI ActiveScriptSiteInterruptPoll_QueryContinue(IActiveScriptSiteInterruptPoll *iface)
387 {
388     ScriptHost *This = ACTSCPPOLL_THIS(iface);
389     FIXME("(%p)\n", This);
390     return E_NOTIMPL;
391 }
392
393 #undef ACTSCPPOLL_THIS
394
395 static const IActiveScriptSiteInterruptPollVtbl ActiveScriptSiteInterruptPollVtbl = {
396     ActiveScriptSiteInterruptPoll_QueryInterface,
397     ActiveScriptSiteInterruptPoll_AddRef,
398     ActiveScriptSiteInterruptPoll_Release,
399     ActiveScriptSiteInterruptPoll_QueryContinue
400 };
401
402 #define ACTSCPWIN_THIS(iface) DEFINE_THIS(ScriptHost, IActiveScriptSiteWindow, iface)
403
404 static HRESULT WINAPI ActiveScriptSiteWindow_QueryInterface(IActiveScriptSiteWindow *iface,
405         REFIID riid, void **ppv)
406 {
407     ScriptHost *This = ACTSCPWIN_THIS(iface);
408     return IActiveScriptSite_QueryInterface(ACTSCPSITE(This), riid, ppv);
409 }
410
411 static ULONG WINAPI ActiveScriptSiteWindow_AddRef(IActiveScriptSiteWindow *iface)
412 {
413     ScriptHost *This = ACTSCPWIN_THIS(iface);
414     return IActiveScriptSite_AddRef(ACTSCPSITE(This));
415 }
416
417 static ULONG WINAPI ActiveScriptSiteWindow_Release(IActiveScriptSiteWindow *iface)
418 {
419     ScriptHost *This = ACTSCPWIN_THIS(iface);
420     return IActiveScriptSite_Release(ACTSCPSITE(This));
421 }
422
423 static HRESULT WINAPI ActiveScriptSiteWindow_GetWindow(IActiveScriptSiteWindow *iface, HWND *phwnd)
424 {
425     ScriptHost *This = ACTSCPWIN_THIS(iface);
426     FIXME("(%p)->(%p)\n", This, phwnd);
427     return E_NOTIMPL;
428 }
429
430 static HRESULT WINAPI ActiveScriptSiteWindow_EnableModeless(IActiveScriptSiteWindow *iface, BOOL fEnable)
431 {
432     ScriptHost *This = ACTSCPWIN_THIS(iface);
433     FIXME("(%p)->(%x)\n", This, fEnable);
434     return E_NOTIMPL;
435 }
436
437 #undef ACTSCPWIN_THIS
438
439 static const IActiveScriptSiteWindowVtbl ActiveScriptSiteWindowVtbl = {
440     ActiveScriptSiteWindow_QueryInterface,
441     ActiveScriptSiteWindow_AddRef,
442     ActiveScriptSiteWindow_Release,
443     ActiveScriptSiteWindow_GetWindow,
444     ActiveScriptSiteWindow_EnableModeless
445 };
446
447 #define ACTSCPDBG32_THIS(iface) DEFINE_THIS(ScriptHost, IActiveScriptSiteDebug32, iface)
448
449 static HRESULT WINAPI ActiveScriptSiteDebug32_QueryInterface(IActiveScriptSiteDebug32 *iface,
450         REFIID riid, void **ppv)
451 {
452     ScriptHost *This = ACTSCPDBG32_THIS(iface);
453     return IActiveScriptSite_QueryInterface(ACTSCPSITE(This), riid, ppv);
454 }
455
456 static ULONG WINAPI ActiveScriptSiteDebug32_AddRef(IActiveScriptSiteDebug32 *iface)
457 {
458     ScriptHost *This = ACTSCPDBG32_THIS(iface);
459     return IActiveScriptSite_AddRef(ACTSCPSITE(This));
460 }
461
462 static ULONG WINAPI ActiveScriptSiteDebug32_Release(IActiveScriptSiteDebug32 *iface)
463 {
464     ScriptHost *This = ACTSCPDBG32_THIS(iface);
465     return IActiveScriptSite_Release(ACTSCPSITE(This));
466 }
467
468 static HRESULT WINAPI ActiveScriptSiteDebug32_GetDocumentContextFromPosition(IActiveScriptSiteDebug32 *iface,
469             DWORD dwSourceContext, ULONG uCharacterOffset, ULONG uNumChars, IDebugDocumentContext **ppsc)
470 {
471     ScriptHost *This = ACTSCPDBG32_THIS(iface);
472     FIXME("(%p)->(%x %u %u %p)\n", This, dwSourceContext, uCharacterOffset, uNumChars, ppsc);
473     return E_NOTIMPL;
474 }
475
476 static HRESULT WINAPI ActiveScriptSiteDebug32_GetApplication(IActiveScriptSiteDebug32 *iface, IDebugApplication32 **ppda)
477 {
478     ScriptHost *This = ACTSCPDBG32_THIS(iface);
479     FIXME("(%p)->(%p)\n", This, ppda);
480     return E_NOTIMPL;
481 }
482
483 static HRESULT WINAPI ActiveScriptSiteDebug32_GetRootApplicationNode(IActiveScriptSiteDebug32 *iface,
484             IDebugApplicationNode **ppdanRoot)
485 {
486     ScriptHost *This = ACTSCPDBG32_THIS(iface);
487     FIXME("(%p)->(%p)\n", This, ppdanRoot);
488     return E_NOTIMPL;
489 }
490
491 static HRESULT WINAPI ActiveScriptSiteDebug32_OnScriptErrorDebug(IActiveScriptSiteDebug32 *iface,
492             IActiveScriptErrorDebug *pErrorDebug, BOOL *pfEnterDebugger, BOOL *pfCallOnScriptErrorWhenContinuing)
493 {
494     ScriptHost *This = ACTSCPDBG32_THIS(iface);
495     FIXME("(%p)->(%p %p %p)\n", This, pErrorDebug, pfEnterDebugger, pfCallOnScriptErrorWhenContinuing);
496     return E_NOTIMPL;
497 }
498
499 #undef ACTSCPDBG32_THIS
500
501 static const IActiveScriptSiteDebug32Vtbl ActiveScriptSiteDebug32Vtbl = {
502     ActiveScriptSiteDebug32_QueryInterface,
503     ActiveScriptSiteDebug32_AddRef,
504     ActiveScriptSiteDebug32_Release,
505     ActiveScriptSiteDebug32_GetDocumentContextFromPosition,
506     ActiveScriptSiteDebug32_GetApplication,
507     ActiveScriptSiteDebug32_GetRootApplicationNode,
508     ActiveScriptSiteDebug32_OnScriptErrorDebug
509 };
510
511 static ScriptHost *create_script_host(HTMLDocument *doc, const GUID *guid)
512 {
513     ScriptHost *ret;
514     HRESULT hres;
515
516     ret = heap_alloc_zero(sizeof(*ret));
517     ret->lpIActiveScriptSiteVtbl               = &ActiveScriptSiteVtbl;
518     ret->lpIActiveScriptSiteInterruptPollVtbl  = &ActiveScriptSiteInterruptPollVtbl;
519     ret->lpIActiveScriptSiteWindowVtbl         = &ActiveScriptSiteWindowVtbl;
520     ret->lpIActiveScriptSiteDebug32Vtbl        = &ActiveScriptSiteDebug32Vtbl;
521     ret->ref = 1;
522     ret->doc = doc;
523     ret->script_state = SCRIPTSTATE_UNINITIALIZED;
524
525     ret->guid = *guid;
526     list_add_tail(&doc->script_hosts, &ret->entry);
527
528     hres = CoCreateInstance(&ret->guid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
529             &IID_IActiveScript, (void**)&ret->script);
530     if(FAILED(hres))
531         WARN("Could not load script engine: %08x\n", hres);
532     else if(!init_script_engine(ret))
533         release_script_engine(ret);
534
535     return ret;
536 }
537
538 static void parse_text(ScriptHost *script_host, LPCWSTR text)
539 {
540     EXCEPINFO excepinfo;
541     VARIANT var;
542     HRESULT hres;
543
544     static const WCHAR script_endW[] = {'<','/','S','C','R','I','P','T','>',0};
545
546     TRACE("%s\n", debugstr_w(text));
547
548     VariantInit(&var);
549     memset(&excepinfo, 0, sizeof(excepinfo));
550     hres = IActiveScriptParse_ParseScriptText(script_host->parse, text, windowW, NULL, script_endW,
551                                               0, 0, SCRIPTTEXT_ISVISIBLE|SCRIPTTEXT_HOSTMANAGESSOURCE,
552                                               &var, &excepinfo);
553     if(FAILED(hres))
554         WARN("ParseScriptText failed: %08x\n", hres);
555
556 }
557
558 static void parse_extern_script(ScriptHost *script_host, LPCWSTR src)
559 {
560     IMoniker *mon;
561     char *buf;
562     WCHAR *text;
563     DWORD len, size=0;
564     HRESULT hres;
565
566     static const WCHAR wine_schemaW[] = {'w','i','n','e',':'};
567
568     if(strlenW(src) > sizeof(wine_schemaW)/sizeof(WCHAR) && !memcmp(src, wine_schemaW, sizeof(wine_schemaW)))
569         src += sizeof(wine_schemaW)/sizeof(WCHAR);
570
571     hres = CreateURLMoniker(NULL, src, &mon);
572     if(FAILED(hres))
573         return;
574
575     hres = bind_mon_to_buffer(script_host->doc, mon, (void**)&buf, &size);
576     IMoniker_Release(mon);
577     if(FAILED(hres))
578         return;
579
580     len = MultiByteToWideChar(CP_ACP, 0, buf, size, NULL, 0);
581     text = heap_alloc((len+1)*sizeof(WCHAR));
582     MultiByteToWideChar(CP_ACP, 0, buf, size, text, len);
583     heap_free(buf);
584     text[len] = 0;
585
586     parse_text(script_host, text);
587
588     heap_free(text);
589 }
590
591 static void parse_inline_script(ScriptHost *script_host, nsIDOMHTMLScriptElement *nsscript)
592 {
593     const PRUnichar *text;
594     nsAString text_str;
595     nsresult nsres;
596
597     nsAString_Init(&text_str, NULL);
598
599     nsres = nsIDOMHTMLScriptElement_GetText(nsscript, &text_str);
600
601     if(NS_SUCCEEDED(nsres)) {
602         nsAString_GetData(&text_str, &text);
603         parse_text(script_host, text);
604     }else {
605         ERR("GetText failed: %08x\n", nsres);
606     }
607
608     nsAString_Finish(&text_str);
609 }
610
611 static void parse_script_elem(ScriptHost *script_host, nsIDOMHTMLScriptElement *nsscript)
612 {
613     const PRUnichar *src;
614     nsAString src_str;
615     nsresult nsres;
616
617     nsAString_Init(&src_str, NULL);
618
619     nsres = nsIDOMHTMLScriptElement_GetSrc(nsscript, &src_str);
620     nsAString_GetData(&src_str, &src);
621
622     if(NS_FAILED(nsres))
623         ERR("GetSrc failed: %08x\n", nsres);
624     else if(*src)
625         parse_extern_script(script_host, src);
626     else
627         parse_inline_script(script_host, nsscript);
628
629     nsAString_Finish(&src_str);
630 }
631
632 static BOOL get_guid_from_type(LPCWSTR type, GUID *guid)
633 {
634     const WCHAR text_javascriptW[] =
635         {'t','e','x','t','/','j','a','v','a','s','c','r','i','p','t',0};
636
637     /* FIXME: Handle more types */
638     if(!strcmpW(type, text_javascriptW)) {
639         *guid = CLSID_JScript;
640     }else {
641         FIXME("Unknown type %s\n", debugstr_w(type));
642         return FALSE;
643     }
644
645     return TRUE;
646 }
647
648 static BOOL get_guid_from_language(LPCWSTR type, GUID *guid)
649 {
650     HRESULT hres;
651
652     hres = CLSIDFromProgID(type, guid);
653     if(FAILED(hres))
654         return FALSE;
655
656     /* FIXME: Check CATID_ActiveScriptParse */
657
658     return TRUE;
659 }
660
661 static BOOL get_script_guid(nsIDOMHTMLScriptElement *nsscript, GUID *guid)
662 {
663     nsAString attr_str, val_str;
664     BOOL ret = FALSE;
665     nsresult nsres;
666
667     static const PRUnichar languageW[] = {'l','a','n','g','u','a','g','e',0};
668
669     nsAString_Init(&val_str, NULL);
670
671     nsres = nsIDOMHTMLScriptElement_GetType(nsscript, &val_str);
672     if(NS_SUCCEEDED(nsres)) {
673         const PRUnichar *type;
674
675         nsAString_GetData(&val_str, &type);
676         if(*type) {
677             ret = get_guid_from_type(type, guid);
678             nsAString_Finish(&val_str);
679             return ret;
680         }
681     }else {
682         ERR("GetType failed: %08x\n", nsres);
683     }
684
685     nsAString_Init(&attr_str, languageW);
686
687     nsres = nsIDOMHTMLScriptElement_GetAttribute(nsscript, &attr_str, &val_str);
688     if(NS_SUCCEEDED(nsres)) {
689         const PRUnichar *language;
690
691         nsAString_GetData(&val_str, &language);
692
693         if(*language) {
694             ret = get_guid_from_language(language, guid);
695         }else {
696             *guid = CLSID_JScript;
697             ret = TRUE;
698         }
699     }else {
700         ERR("GetAttribute(language) failed: %08x\n", nsres);
701     }
702
703     nsAString_Finish(&attr_str);
704     nsAString_Finish(&val_str);
705
706     return ret;
707 }
708
709 static ScriptHost *get_script_host(HTMLDocument *doc, const GUID *guid)
710 {
711     ScriptHost *iter;
712
713     if(IsEqualGUID(&CLSID_JScript, &guid)) {
714         FIXME("Ignoring JScript\n");
715         return NULL;
716     }
717
718     LIST_FOR_EACH_ENTRY(iter, &doc->script_hosts, ScriptHost, entry) {
719         if(IsEqualGUID(guid, &iter->guid))
720             return iter;
721     }
722
723     return create_script_host(doc, guid);
724 }
725
726 void doc_insert_script(HTMLDocument *doc, nsIDOMHTMLScriptElement *nsscript)
727 {
728     ScriptHost *script_host;
729     GUID guid;
730
731     if(!get_script_guid(nsscript, &guid)) {
732         WARN("Could not find script GUID\n");
733         return;
734     }
735
736     script_host = get_script_host(doc, &guid);
737     if(!script_host)
738         return;
739
740     if(script_host->parse)
741         parse_script_elem(script_host, nsscript);
742 }
743
744 IDispatch *script_parse_event(HTMLDocument *doc, LPCWSTR text)
745 {
746     ScriptHost *script_host;
747     GUID guid = CLSID_JScript;
748     const WCHAR *ptr;
749     IDispatch *disp;
750     HRESULT hres;
751
752     static const WCHAR delimiterW[] = {'\"',0};
753
754     for(ptr = text; isalnumW(*ptr); ptr++);
755     if(*ptr == ':') {
756         LPWSTR language;
757         BOOL b;
758
759         language = heap_alloc((ptr-text+1)*sizeof(WCHAR));
760         memcpy(language, text, (ptr-text)*sizeof(WCHAR));
761         language[ptr-text] = 0;
762
763         b = get_guid_from_language(language, &guid);
764
765         heap_free(language);
766
767         if(!b) {
768             WARN("Could not find language\n");
769             return NULL;
770         }
771
772         ptr++;
773     }else {
774         ptr = text;
775     }
776
777     script_host = get_script_host(doc, &guid);
778     if(!script_host || !script_host->parse_proc)
779         return NULL;
780
781     hres = IActiveScriptParseProcedure_ParseProcedureText(script_host->parse_proc, ptr, NULL, emptyW,
782             NULL, NULL, delimiterW, 0 /* FIXME */, 0,
783             SCRIPTPROC_HOSTMANAGESSOURCE|SCRIPTPROC_IMPLICIT_THIS|SCRIPTPROC_IMPLICIT_PARENTS, &disp);
784     if(FAILED(hres)) {
785         WARN("ParseProcedureText failed: %08x\n", hres);
786         return NULL;
787     }
788
789     TRACE("ret %p\n", disp);
790     return disp;
791 }
792
793 void release_script_hosts(HTMLDocument *doc)
794 {
795     ScriptHost *iter;
796
797     while(!list_empty(&doc->script_hosts)) {
798         iter = LIST_ENTRY(list_head(&doc->script_hosts), ScriptHost, entry);
799
800         release_script_engine(iter);
801         list_remove(&iter->entry);
802         iter->doc = NULL;
803         IActiveScript_Release(ACTSCPSITE(iter));
804     }
805 }