msctf: Implement ITfClientId.
[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)  (&(x)->lpIActiveScriptSiteInterruptPollVtbl)
67 #define ACTSCPWIN(x)   (&(x)->lpIActiveScriptSiteWindowVtbl)
68 #define ACTSCPDBG32(x) (&(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 = IActiveScriptParse64_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             IUnknown_Release(This->parse_proc);
179             This->parse_proc = NULL;
180         }
181
182         if(This->parse) {
183             IUnknown_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 if(IsEqualGUID(&IID_ICanHandleException, riid)) {
227         TRACE("(%p)->(IID_ICanHandleException not supported %p)\n", This, ppv);
228         return E_NOINTERFACE;
229     }else {
230         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
231         return E_NOINTERFACE;
232     }
233
234     IUnknown_AddRef((IUnknown*)*ppv);
235     return S_OK;
236 }
237
238 static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface)
239 {
240     ScriptHost *This = ACTSCPSITE_THIS(iface);
241     LONG ref = InterlockedIncrement(&This->ref);
242
243     TRACE("(%p) ref=%d\n", This, ref);
244
245     return ref;
246 }
247
248 static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface)
249 {
250     ScriptHost *This = ACTSCPSITE_THIS(iface);
251     LONG ref = InterlockedDecrement(&This->ref);
252
253     TRACE("(%p) ref=%d\n", This, ref);
254
255     if(!ref) {
256         release_script_engine(This);
257         if(This->doc)
258             list_remove(&This->entry);
259         heap_free(This);
260     }
261
262     return ref;
263 }
264
265 static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid)
266 {
267     ScriptHost *This = ACTSCPSITE_THIS(iface);
268
269     TRACE("(%p)->(%p)\n", This, plcid);
270
271     *plcid = GetUserDefaultLCID();
272     return S_OK;
273 }
274
275 static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName,
276         DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti)
277 {
278     ScriptHost *This = ACTSCPSITE_THIS(iface);
279
280     TRACE("(%p)->(%s %x %p %p)\n", This, debugstr_w(pstrName), dwReturnMask, ppiunkItem, ppti);
281
282     if(dwReturnMask != SCRIPTINFO_IUNKNOWN) {
283         FIXME("Unsupported mask %x\n", dwReturnMask);
284         return E_NOTIMPL;
285     }
286
287     *ppiunkItem = NULL;
288
289     if(strcmpW(pstrName, windowW))
290         return DISP_E_MEMBERNOTFOUND;
291
292     if(!This->doc)
293         return E_FAIL;
294
295     /* FIXME: Return proxy object */
296     *ppiunkItem = (IUnknown*)HTMLWINDOW2(This->doc->window);
297     IUnknown_AddRef(*ppiunkItem);
298
299     return S_OK;
300 }
301
302 static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *pbstrVersion)
303 {
304     ScriptHost *This = ACTSCPSITE_THIS(iface);
305     FIXME("(%p)->(%p)\n", This, pbstrVersion);
306     return E_NOTIMPL;
307 }
308
309 static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface,
310         const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo)
311 {
312     ScriptHost *This = ACTSCPSITE_THIS(iface);
313     FIXME("(%p)->(%p %p)\n", This, pvarResult, pexcepinfo);
314     return E_NOTIMPL;
315 }
316
317 static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE ssScriptState)
318 {
319     ScriptHost *This = ACTSCPSITE_THIS(iface);
320
321     TRACE("(%p)->(%x)\n", This, ssScriptState);
322
323     This->script_state = ssScriptState;
324     return S_OK;
325 }
326
327 static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror)
328 {
329     ScriptHost *This = ACTSCPSITE_THIS(iface);
330     FIXME("(%p)->(%p)\n", This, pscripterror);
331     return E_NOTIMPL;
332 }
333
334 static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
335 {
336     ScriptHost *This = ACTSCPSITE_THIS(iface);
337
338     TRACE("(%p)->()\n", This);
339
340     return S_OK;
341 }
342
343 static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface)
344 {
345     ScriptHost *This = ACTSCPSITE_THIS(iface);
346
347     TRACE("(%p)->()\n", This);
348
349     return S_OK;
350 }
351
352 #undef ACTSCPSITE_THIS
353
354 static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = {
355     ActiveScriptSite_QueryInterface,
356     ActiveScriptSite_AddRef,
357     ActiveScriptSite_Release,
358     ActiveScriptSite_GetLCID,
359     ActiveScriptSite_GetItemInfo,
360     ActiveScriptSite_GetDocVersionString,
361     ActiveScriptSite_OnScriptTerminate,
362     ActiveScriptSite_OnStateChange,
363     ActiveScriptSite_OnScriptError,
364     ActiveScriptSite_OnEnterScript,
365     ActiveScriptSite_OnLeaveScript
366 };
367
368 #define ACTSCPPOLL_THIS(iface) DEFINE_THIS(ScriptHost, IActiveScriptSiteInterruptPoll, iface)
369
370 static HRESULT WINAPI ActiveScriptSiteInterruptPoll_QueryInterface(IActiveScriptSiteInterruptPoll *iface,
371         REFIID riid, void **ppv)
372 {
373     ScriptHost *This = ACTSCPPOLL_THIS(iface);
374     return IActiveScriptSite_QueryInterface(ACTSCPSITE(This), riid, ppv);
375 }
376
377 static ULONG WINAPI ActiveScriptSiteInterruptPoll_AddRef(IActiveScriptSiteInterruptPoll *iface)
378 {
379     ScriptHost *This = ACTSCPPOLL_THIS(iface);
380     return IActiveScriptSite_AddRef(ACTSCPSITE(This));
381 }
382
383 static ULONG WINAPI ActiveScriptSiteInterruptPoll_Release(IActiveScriptSiteInterruptPoll *iface)
384 {
385     ScriptHost *This = ACTSCPPOLL_THIS(iface);
386     return IActiveScriptSite_Release(ACTSCPSITE(This));
387 }
388
389 static HRESULT WINAPI ActiveScriptSiteInterruptPoll_QueryContinue(IActiveScriptSiteInterruptPoll *iface)
390 {
391     ScriptHost *This = ACTSCPPOLL_THIS(iface);
392
393     TRACE("(%p)\n", This);
394
395     return S_OK;
396 }
397
398 #undef ACTSCPPOLL_THIS
399
400 static const IActiveScriptSiteInterruptPollVtbl ActiveScriptSiteInterruptPollVtbl = {
401     ActiveScriptSiteInterruptPoll_QueryInterface,
402     ActiveScriptSiteInterruptPoll_AddRef,
403     ActiveScriptSiteInterruptPoll_Release,
404     ActiveScriptSiteInterruptPoll_QueryContinue
405 };
406
407 #define ACTSCPWIN_THIS(iface) DEFINE_THIS(ScriptHost, IActiveScriptSiteWindow, iface)
408
409 static HRESULT WINAPI ActiveScriptSiteWindow_QueryInterface(IActiveScriptSiteWindow *iface,
410         REFIID riid, void **ppv)
411 {
412     ScriptHost *This = ACTSCPWIN_THIS(iface);
413     return IActiveScriptSite_QueryInterface(ACTSCPSITE(This), riid, ppv);
414 }
415
416 static ULONG WINAPI ActiveScriptSiteWindow_AddRef(IActiveScriptSiteWindow *iface)
417 {
418     ScriptHost *This = ACTSCPWIN_THIS(iface);
419     return IActiveScriptSite_AddRef(ACTSCPSITE(This));
420 }
421
422 static ULONG WINAPI ActiveScriptSiteWindow_Release(IActiveScriptSiteWindow *iface)
423 {
424     ScriptHost *This = ACTSCPWIN_THIS(iface);
425     return IActiveScriptSite_Release(ACTSCPSITE(This));
426 }
427
428 static HRESULT WINAPI ActiveScriptSiteWindow_GetWindow(IActiveScriptSiteWindow *iface, HWND *phwnd)
429 {
430     ScriptHost *This = ACTSCPWIN_THIS(iface);
431     FIXME("(%p)->(%p)\n", This, phwnd);
432     return E_NOTIMPL;
433 }
434
435 static HRESULT WINAPI ActiveScriptSiteWindow_EnableModeless(IActiveScriptSiteWindow *iface, BOOL fEnable)
436 {
437     ScriptHost *This = ACTSCPWIN_THIS(iface);
438     FIXME("(%p)->(%x)\n", This, fEnable);
439     return E_NOTIMPL;
440 }
441
442 #undef ACTSCPWIN_THIS
443
444 static const IActiveScriptSiteWindowVtbl ActiveScriptSiteWindowVtbl = {
445     ActiveScriptSiteWindow_QueryInterface,
446     ActiveScriptSiteWindow_AddRef,
447     ActiveScriptSiteWindow_Release,
448     ActiveScriptSiteWindow_GetWindow,
449     ActiveScriptSiteWindow_EnableModeless
450 };
451
452 #define ACTSCPDBG32_THIS(iface) DEFINE_THIS(ScriptHost, IActiveScriptSiteDebug32, iface)
453
454 static HRESULT WINAPI ActiveScriptSiteDebug32_QueryInterface(IActiveScriptSiteDebug32 *iface,
455         REFIID riid, void **ppv)
456 {
457     ScriptHost *This = ACTSCPDBG32_THIS(iface);
458     return IActiveScriptSite_QueryInterface(ACTSCPSITE(This), riid, ppv);
459 }
460
461 static ULONG WINAPI ActiveScriptSiteDebug32_AddRef(IActiveScriptSiteDebug32 *iface)
462 {
463     ScriptHost *This = ACTSCPDBG32_THIS(iface);
464     return IActiveScriptSite_AddRef(ACTSCPSITE(This));
465 }
466
467 static ULONG WINAPI ActiveScriptSiteDebug32_Release(IActiveScriptSiteDebug32 *iface)
468 {
469     ScriptHost *This = ACTSCPDBG32_THIS(iface);
470     return IActiveScriptSite_Release(ACTSCPSITE(This));
471 }
472
473 static HRESULT WINAPI ActiveScriptSiteDebug32_GetDocumentContextFromPosition(IActiveScriptSiteDebug32 *iface,
474             DWORD dwSourceContext, ULONG uCharacterOffset, ULONG uNumChars, IDebugDocumentContext **ppsc)
475 {
476     ScriptHost *This = ACTSCPDBG32_THIS(iface);
477     FIXME("(%p)->(%x %u %u %p)\n", This, dwSourceContext, uCharacterOffset, uNumChars, ppsc);
478     return E_NOTIMPL;
479 }
480
481 static HRESULT WINAPI ActiveScriptSiteDebug32_GetApplication(IActiveScriptSiteDebug32 *iface, IDebugApplication32 **ppda)
482 {
483     ScriptHost *This = ACTSCPDBG32_THIS(iface);
484     FIXME("(%p)->(%p)\n", This, ppda);
485     return E_NOTIMPL;
486 }
487
488 static HRESULT WINAPI ActiveScriptSiteDebug32_GetRootApplicationNode(IActiveScriptSiteDebug32 *iface,
489             IDebugApplicationNode **ppdanRoot)
490 {
491     ScriptHost *This = ACTSCPDBG32_THIS(iface);
492     FIXME("(%p)->(%p)\n", This, ppdanRoot);
493     return E_NOTIMPL;
494 }
495
496 static HRESULT WINAPI ActiveScriptSiteDebug32_OnScriptErrorDebug(IActiveScriptSiteDebug32 *iface,
497             IActiveScriptErrorDebug *pErrorDebug, BOOL *pfEnterDebugger, BOOL *pfCallOnScriptErrorWhenContinuing)
498 {
499     ScriptHost *This = ACTSCPDBG32_THIS(iface);
500     FIXME("(%p)->(%p %p %p)\n", This, pErrorDebug, pfEnterDebugger, pfCallOnScriptErrorWhenContinuing);
501     return E_NOTIMPL;
502 }
503
504 #undef ACTSCPDBG32_THIS
505
506 static const IActiveScriptSiteDebug32Vtbl ActiveScriptSiteDebug32Vtbl = {
507     ActiveScriptSiteDebug32_QueryInterface,
508     ActiveScriptSiteDebug32_AddRef,
509     ActiveScriptSiteDebug32_Release,
510     ActiveScriptSiteDebug32_GetDocumentContextFromPosition,
511     ActiveScriptSiteDebug32_GetApplication,
512     ActiveScriptSiteDebug32_GetRootApplicationNode,
513     ActiveScriptSiteDebug32_OnScriptErrorDebug
514 };
515
516 static ScriptHost *create_script_host(HTMLDocument *doc, const GUID *guid)
517 {
518     ScriptHost *ret;
519     HRESULT hres;
520
521     ret = heap_alloc_zero(sizeof(*ret));
522     ret->lpIActiveScriptSiteVtbl               = &ActiveScriptSiteVtbl;
523     ret->lpIActiveScriptSiteInterruptPollVtbl  = &ActiveScriptSiteInterruptPollVtbl;
524     ret->lpIActiveScriptSiteWindowVtbl         = &ActiveScriptSiteWindowVtbl;
525     ret->lpIActiveScriptSiteDebug32Vtbl        = &ActiveScriptSiteDebug32Vtbl;
526     ret->ref = 1;
527     ret->doc = doc;
528     ret->script_state = SCRIPTSTATE_UNINITIALIZED;
529
530     ret->guid = *guid;
531     list_add_tail(&doc->script_hosts, &ret->entry);
532
533     hres = CoCreateInstance(&ret->guid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
534             &IID_IActiveScript, (void**)&ret->script);
535     if(FAILED(hres))
536         WARN("Could not load script engine: %08x\n", hres);
537     else if(!init_script_engine(ret))
538         release_script_engine(ret);
539
540     return ret;
541 }
542
543 static void parse_text(ScriptHost *script_host, LPCWSTR text)
544 {
545     EXCEPINFO excepinfo;
546     VARIANT var;
547     HRESULT hres;
548
549     static const WCHAR script_endW[] = {'<','/','S','C','R','I','P','T','>',0};
550
551     TRACE("%s\n", debugstr_w(text));
552
553     VariantInit(&var);
554     memset(&excepinfo, 0, sizeof(excepinfo));
555     hres = IActiveScriptParse64_ParseScriptText(script_host->parse, text, windowW, NULL, script_endW,
556                                               0, 0, SCRIPTTEXT_ISVISIBLE|SCRIPTTEXT_HOSTMANAGESSOURCE,
557                                               &var, &excepinfo);
558     if(FAILED(hres))
559         WARN("ParseScriptText failed: %08x\n", hres);
560
561 }
562
563 static void parse_extern_script(ScriptHost *script_host, LPCWSTR src)
564 {
565     IMoniker *mon;
566     char *buf;
567     WCHAR *text;
568     DWORD len, size=0;
569     HRESULT hres;
570
571     static const WCHAR wine_schemaW[] = {'w','i','n','e',':'};
572
573     if(strlenW(src) > sizeof(wine_schemaW)/sizeof(WCHAR) && !memcmp(src, wine_schemaW, sizeof(wine_schemaW)))
574         src += sizeof(wine_schemaW)/sizeof(WCHAR);
575
576     hres = CreateURLMoniker(NULL, src, &mon);
577     if(FAILED(hres))
578         return;
579
580     hres = bind_mon_to_buffer(script_host->doc, mon, (void**)&buf, &size);
581     IMoniker_Release(mon);
582     if(FAILED(hres))
583         return;
584
585     len = MultiByteToWideChar(CP_ACP, 0, buf, size, NULL, 0);
586     text = heap_alloc((len+1)*sizeof(WCHAR));
587     MultiByteToWideChar(CP_ACP, 0, buf, size, text, len);
588     heap_free(buf);
589     text[len] = 0;
590
591     parse_text(script_host, text);
592
593     heap_free(text);
594 }
595
596 static void parse_inline_script(ScriptHost *script_host, nsIDOMHTMLScriptElement *nsscript)
597 {
598     const PRUnichar *text;
599     nsAString text_str;
600     nsresult nsres;
601
602     nsAString_Init(&text_str, NULL);
603
604     nsres = nsIDOMHTMLScriptElement_GetText(nsscript, &text_str);
605
606     if(NS_SUCCEEDED(nsres)) {
607         nsAString_GetData(&text_str, &text);
608         parse_text(script_host, text);
609     }else {
610         ERR("GetText failed: %08x\n", nsres);
611     }
612
613     nsAString_Finish(&text_str);
614 }
615
616 static void parse_script_elem(ScriptHost *script_host, nsIDOMHTMLScriptElement *nsscript)
617 {
618     const PRUnichar *src;
619     nsAString src_str;
620     nsresult nsres;
621
622     nsAString_Init(&src_str, NULL);
623
624     nsres = nsIDOMHTMLScriptElement_GetSrc(nsscript, &src_str);
625     nsAString_GetData(&src_str, &src);
626
627     if(NS_FAILED(nsres))
628         ERR("GetSrc failed: %08x\n", nsres);
629     else if(*src)
630         parse_extern_script(script_host, src);
631     else
632         parse_inline_script(script_host, nsscript);
633
634     nsAString_Finish(&src_str);
635 }
636
637 static BOOL get_guid_from_type(LPCWSTR type, GUID *guid)
638 {
639     const WCHAR text_javascriptW[] =
640         {'t','e','x','t','/','j','a','v','a','s','c','r','i','p','t',0};
641
642     /* FIXME: Handle more types */
643     if(!strcmpiW(type, text_javascriptW)) {
644         *guid = CLSID_JScript;
645     }else {
646         FIXME("Unknown type %s\n", debugstr_w(type));
647         return FALSE;
648     }
649
650     return TRUE;
651 }
652
653 static BOOL get_guid_from_language(LPCWSTR type, GUID *guid)
654 {
655     HRESULT hres;
656
657     hres = CLSIDFromProgID(type, guid);
658     if(FAILED(hres))
659         return FALSE;
660
661     /* FIXME: Check CATID_ActiveScriptParse */
662
663     return TRUE;
664 }
665
666 static BOOL get_script_guid(nsIDOMHTMLScriptElement *nsscript, GUID *guid)
667 {
668     nsAString attr_str, val_str;
669     BOOL ret = FALSE;
670     nsresult nsres;
671
672     static const PRUnichar languageW[] = {'l','a','n','g','u','a','g','e',0};
673
674     nsAString_Init(&val_str, NULL);
675
676     nsres = nsIDOMHTMLScriptElement_GetType(nsscript, &val_str);
677     if(NS_SUCCEEDED(nsres)) {
678         const PRUnichar *type;
679
680         nsAString_GetData(&val_str, &type);
681         if(*type) {
682             ret = get_guid_from_type(type, guid);
683             nsAString_Finish(&val_str);
684             return ret;
685         }
686     }else {
687         ERR("GetType failed: %08x\n", nsres);
688     }
689
690     nsAString_Init(&attr_str, languageW);
691
692     nsres = nsIDOMHTMLScriptElement_GetAttribute(nsscript, &attr_str, &val_str);
693     if(NS_SUCCEEDED(nsres)) {
694         const PRUnichar *language;
695
696         nsAString_GetData(&val_str, &language);
697
698         if(*language) {
699             ret = get_guid_from_language(language, guid);
700         }else {
701             *guid = CLSID_JScript;
702             ret = TRUE;
703         }
704     }else {
705         ERR("GetAttribute(language) failed: %08x\n", nsres);
706     }
707
708     nsAString_Finish(&attr_str);
709     nsAString_Finish(&val_str);
710
711     return ret;
712 }
713
714 static ScriptHost *get_script_host(HTMLDocument *doc, const GUID *guid)
715 {
716     ScriptHost *iter;
717
718     if(IsEqualGUID(&CLSID_JScript, guid) && doc->scriptmode != SCRIPTMODE_ACTIVESCRIPT) {
719         TRACE("Ignoring JScript\n");
720         return NULL;
721     }
722
723     LIST_FOR_EACH_ENTRY(iter, &doc->script_hosts, ScriptHost, entry) {
724         if(IsEqualGUID(guid, &iter->guid))
725             return iter;
726     }
727
728     return create_script_host(doc, guid);
729 }
730
731 void doc_insert_script(HTMLDocument *doc, nsIDOMHTMLScriptElement *nsscript)
732 {
733     ScriptHost *script_host;
734     GUID guid;
735
736     if(!get_script_guid(nsscript, &guid)) {
737         WARN("Could not find script GUID\n");
738         return;
739     }
740
741     script_host = get_script_host(doc, &guid);
742     if(!script_host)
743         return;
744
745     if(script_host->parse)
746         parse_script_elem(script_host, nsscript);
747 }
748
749 IDispatch *script_parse_event(HTMLDocument *doc, LPCWSTR text)
750 {
751     ScriptHost *script_host;
752     GUID guid = CLSID_JScript;
753     const WCHAR *ptr;
754     IDispatch *disp;
755     HRESULT hres;
756
757     static const WCHAR delimiterW[] = {'\"',0};
758
759     for(ptr = text; isalnumW(*ptr); ptr++);
760     if(*ptr == ':') {
761         LPWSTR language;
762         BOOL b;
763
764         language = heap_alloc((ptr-text+1)*sizeof(WCHAR));
765         memcpy(language, text, (ptr-text)*sizeof(WCHAR));
766         language[ptr-text] = 0;
767
768         b = get_guid_from_language(language, &guid);
769
770         heap_free(language);
771
772         if(!b) {
773             WARN("Could not find language\n");
774             return NULL;
775         }
776
777         ptr++;
778     }else {
779         ptr = text;
780     }
781
782     script_host = get_script_host(doc, &guid);
783     if(!script_host || !script_host->parse_proc)
784         return NULL;
785
786     hres = IActiveScriptParseProcedure64_ParseProcedureText(script_host->parse_proc, ptr, NULL, emptyW,
787             NULL, NULL, delimiterW, 0 /* FIXME */, 0,
788             SCRIPTPROC_HOSTMANAGESSOURCE|SCRIPTPROC_IMPLICIT_THIS|SCRIPTPROC_IMPLICIT_PARENTS, &disp);
789     if(FAILED(hres)) {
790         WARN("ParseProcedureText failed: %08x\n", hres);
791         return NULL;
792     }
793
794     TRACE("ret %p\n", disp);
795     return disp;
796 }
797
798 static BOOL is_jscript_available(void)
799 {
800     static BOOL available, checked;
801
802     if(!checked) {
803         IUnknown *unk;
804         HRESULT hres = CoGetClassObject(&CLSID_JScript, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk);
805
806         if(SUCCEEDED(hres)) {
807             available = TRUE;
808             IUnknown_Release(unk);
809         }else {
810             available = FALSE;
811         }
812         checked = TRUE;
813     }
814
815     return available;
816 }
817
818 void set_script_mode(HTMLDocument *doc, SCRIPTMODE mode)
819 {
820     nsIWebBrowserSetup *setup;
821     nsresult nsres;
822
823     if(mode == SCRIPTMODE_ACTIVESCRIPT && !is_jscript_available()) {
824         TRACE("jscript.dll not available\n");
825         doc->scriptmode = SCRIPTMODE_GECKO;
826         return;
827     }
828
829     doc->scriptmode = mode;
830
831     if(!doc->nscontainer || !doc->nscontainer->webbrowser)
832         return;
833
834     nsres = nsIWebBrowser_QueryInterface(doc->nscontainer->webbrowser,
835             &IID_nsIWebBrowserSetup, (void**)&setup);
836     if(NS_SUCCEEDED(nsres)) {
837         nsres = nsIWebBrowserSetup_SetProperty(setup, SETUP_ALLOW_JAVASCRIPT,
838                 doc->scriptmode == SCRIPTMODE_GECKO);
839         nsIWebBrowserSetup_Release(setup);
840     }
841
842     if(NS_FAILED(nsres))
843         ERR("JavaScript setup failed: %08x\n", nsres);
844 }
845
846 void release_script_hosts(HTMLDocument *doc)
847 {
848     ScriptHost *iter;
849
850     while(!list_empty(&doc->script_hosts)) {
851         iter = LIST_ENTRY(list_head(&doc->script_hosts), ScriptHost, entry);
852
853         release_script_engine(iter);
854         list_remove(&iter->entry);
855         iter->doc = NULL;
856         IActiveScript_Release(ACTSCPSITE(iter));
857     }
858 }