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