windowscodecs: Add stub TGA decoder.
[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 #ifdef _WIN64
40 #define CTXARG_T DWORDLONG
41 #define IActiveScriptSiteDebugVtbl IActiveScriptSiteDebug64Vtbl
42 #else
43 #define CTXARG_T DWORD
44 #define IActiveScriptSiteDebugVtbl IActiveScriptSiteDebug32Vtbl
45 #endif
46
47 static const WCHAR windowW[] = {'w','i','n','d','o','w',0};
48 static const WCHAR emptyW[] = {0};
49
50 static const CLSID CLSID_JScript =
51     {0xf414c260,0x6ac0,0x11cf,{0xb6,0xd1,0x00,0xaa,0x00,0xbb,0xbb,0x58}};
52
53 struct ScriptHost {
54     const IActiveScriptSiteVtbl               *lpIActiveScriptSiteVtbl;
55     const IActiveScriptSiteInterruptPollVtbl  *lpIActiveScriptSiteInterruptPollVtbl;
56     const IActiveScriptSiteWindowVtbl         *lpIActiveScriptSiteWindowVtbl;
57     const IActiveScriptSiteDebugVtbl          *lpIActiveScriptSiteDebugVtbl;
58     const IServiceProviderVtbl                *lpServiceProviderVtbl;
59
60     LONG ref;
61
62     IActiveScript *script;
63     IActiveScriptParse *parse;
64     IActiveScriptParseProcedure *parse_proc;
65
66     SCRIPTSTATE script_state;
67
68     HTMLWindow *window;
69
70     GUID guid;
71     struct list entry;
72 };
73
74 #define ACTSCPSITE(x)  ((IActiveScriptSite*)               &(x)->lpIActiveScriptSiteVtbl)
75 #define ACTSCPPOLL(x)  (&(x)->lpIActiveScriptSiteInterruptPollVtbl)
76 #define ACTSCPWIN(x)   (&(x)->lpIActiveScriptSiteWindowVtbl)
77 #define ACTSCPDBG(x)   (&(x)->lpIActiveScriptSiteDebugVtbl)
78
79 static void set_script_prop(ScriptHost *script_host, DWORD property, VARIANT *val)
80 {
81     IActiveScriptProperty *script_prop;
82     HRESULT hres;
83
84     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptProperty,
85             (void**)&script_prop);
86     if(FAILED(hres)) {
87         WARN("Could not get IActiveScriptProperty iface: %08x\n", hres);
88         return;
89     }
90
91     hres = IActiveScriptProperty_SetProperty(script_prop, property, NULL, val);
92     IActiveScriptProperty_Release(script_prop);
93     if(FAILED(hres))
94         WARN("SetProperty(%x) failed: %08x\n", property, hres);
95 }
96
97 static BOOL init_script_engine(ScriptHost *script_host)
98 {
99     IObjectSafety *safety;
100     SCRIPTSTATE state;
101     DWORD supported_opts=0, enabled_opts=0;
102     VARIANT var;
103     HRESULT hres;
104
105     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptParse, (void**)&script_host->parse);
106     if(FAILED(hres)) {
107         WARN("Could not get IActiveScriptHost: %08x\n", hres);
108         return FALSE;
109     }
110
111     hres = IActiveScript_QueryInterface(script_host->script, &IID_IObjectSafety, (void**)&safety);
112     if(FAILED(hres)) {
113         FIXME("Could not get IObjectSafety: %08x\n", hres);
114         return FALSE;
115     }
116
117     hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, &supported_opts, &enabled_opts);
118     if(FAILED(hres)) {
119         FIXME("GetInterfaceSafetyOptions failed: %08x\n", hres);
120     }else if(!(supported_opts & INTERFACE_USES_DISPEX)) {
121         FIXME("INTERFACE_USES_DISPEX is not supported\n");
122     }else {
123         hres = IObjectSafety_SetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse,
124                 INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER,
125                 INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER);
126         if(FAILED(hres))
127             FIXME("SetInterfaceSafetyOptions failed: %08x\n", hres);
128     }
129
130     IObjectSafety_Release(safety);
131     if(FAILED(hres))
132         return FALSE;
133
134     V_VT(&var) = VT_I4;
135     V_I4(&var) = 1;
136     set_script_prop(script_host, SCRIPTPROP_INVOKEVERSIONING, &var);
137
138     V_VT(&var) = VT_BOOL;
139     V_BOOL(&var) = VARIANT_TRUE;
140     set_script_prop(script_host, SCRIPTPROP_HACK_TRIDENTEVENTSINK, &var);
141
142     hres = IActiveScriptParse64_InitNew(script_host->parse);
143     if(FAILED(hres)) {
144         WARN("InitNew failed: %08x\n", hres);
145         return FALSE;
146     }
147
148     hres = IActiveScript_SetScriptSite(script_host->script, ACTSCPSITE(script_host));
149     if(FAILED(hres)) {
150         WARN("SetScriptSite failed: %08x\n", hres);
151         IActiveScript_Close(script_host->script);
152         return FALSE;
153     }
154
155     hres = IActiveScript_GetScriptState(script_host->script, &state);
156     if(FAILED(hres))
157         WARN("GetScriptState failed: %08x\n", hres);
158     else if(state != SCRIPTSTATE_INITIALIZED)
159         FIXME("state = %x\n", state);
160
161     hres = IActiveScript_SetScriptState(script_host->script, SCRIPTSTATE_STARTED);
162     if(FAILED(hres)) {
163         WARN("Starting script failed: %08x\n", hres);
164         return FALSE;
165     }
166
167     hres = IActiveScript_AddNamedItem(script_host->script, windowW,
168             SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS);
169     if(SUCCEEDED(hres)) {
170         V_VT(&var) = VT_BOOL;
171         V_BOOL(&var) = VARIANT_TRUE;
172         set_script_prop(script_host, SCRIPTPROP_ABBREVIATE_GLOBALNAME_RESOLUTION, &var);
173     }else {
174        WARN("AddNamedItem failed: %08x\n", hres);
175     }
176
177     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptParseProcedure2,
178                                         (void**)&script_host->parse_proc);
179     if(FAILED(hres)) {
180         /* FIXME: QI for IActiveScriptParseProcedure */
181         WARN("Could not get IActiveScriptParseProcedure iface: %08x\n", hres);
182     }
183
184     return TRUE;
185 }
186
187 static void release_script_engine(ScriptHost *This)
188 {
189     if(!This->script)
190         return;
191
192     switch(This->script_state) {
193     case SCRIPTSTATE_CONNECTED:
194         IActiveScript_SetScriptState(This->script, SCRIPTSTATE_DISCONNECTED);
195
196     case SCRIPTSTATE_STARTED:
197     case SCRIPTSTATE_DISCONNECTED:
198     case SCRIPTSTATE_INITIALIZED:
199         IActiveScript_Close(This->script);
200
201     default:
202         if(This->parse_proc) {
203             IUnknown_Release(This->parse_proc);
204             This->parse_proc = NULL;
205         }
206
207         if(This->parse) {
208             IUnknown_Release(This->parse);
209             This->parse = NULL;
210         }
211     }
212
213     IActiveScript_Release(This->script);
214     This->script = NULL;
215     This->script_state = SCRIPTSTATE_UNINITIALIZED;
216 }
217
218 void connect_scripts(HTMLWindow *window)
219 {
220     ScriptHost *iter;
221
222     LIST_FOR_EACH_ENTRY(iter, &window->script_hosts, ScriptHost, entry) {
223         if(iter->script_state == SCRIPTSTATE_STARTED)
224             IActiveScript_SetScriptState(iter->script, SCRIPTSTATE_CONNECTED);
225     }
226 }
227
228 #define ACTSCPSITE_THIS(iface) DEFINE_THIS(ScriptHost, IActiveScriptSite, iface)
229
230 static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv)
231 {
232     ScriptHost *This = ACTSCPSITE_THIS(iface);
233
234     *ppv = NULL;
235
236     if(IsEqualGUID(&IID_IUnknown, riid)) {
237         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
238         *ppv = ACTSCPSITE(This);
239     }else if(IsEqualGUID(&IID_IActiveScriptSite, riid)) {
240         TRACE("(%p)->(IID_IActiveScriptSite %p)\n", This, ppv);
241         *ppv = ACTSCPSITE(This);
242     }else if(IsEqualGUID(&IID_IActiveScriptSiteInterruptPoll, riid)) {
243         TRACE("(%p)->(IID_IActiveScriptSiteInterruprtPoll %p)\n", This, ppv);
244         *ppv = ACTSCPPOLL(This);
245     }else if(IsEqualGUID(&IID_IActiveScriptSiteWindow, riid)) {
246         TRACE("(%p)->(IID_IActiveScriptSiteWindow %p)\n", This, ppv);
247         *ppv = ACTSCPWIN(This);
248     }else if(IsEqualGUID(&IID_IActiveScriptSiteDebug, riid)) {
249         TRACE("(%p)->(IID_IActiveScriptSiteDebug %p)\n", This, ppv);
250         *ppv = ACTSCPDBG(This);
251     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
252         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
253         *ppv = SERVPROV(This);
254     }else if(IsEqualGUID(&IID_ICanHandleException, riid)) {
255         TRACE("(%p)->(IID_ICanHandleException not supported %p)\n", This, ppv);
256         return E_NOINTERFACE;
257     }else {
258         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
259         return E_NOINTERFACE;
260     }
261
262     IUnknown_AddRef((IUnknown*)*ppv);
263     return S_OK;
264 }
265
266 static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface)
267 {
268     ScriptHost *This = ACTSCPSITE_THIS(iface);
269     LONG ref = InterlockedIncrement(&This->ref);
270
271     TRACE("(%p) ref=%d\n", This, ref);
272
273     return ref;
274 }
275
276 static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface)
277 {
278     ScriptHost *This = ACTSCPSITE_THIS(iface);
279     LONG ref = InterlockedDecrement(&This->ref);
280
281     TRACE("(%p) ref=%d\n", This, ref);
282
283     if(!ref) {
284         release_script_engine(This);
285         if(This->window)
286             list_remove(&This->entry);
287         heap_free(This);
288     }
289
290     return ref;
291 }
292
293 static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid)
294 {
295     ScriptHost *This = ACTSCPSITE_THIS(iface);
296
297     TRACE("(%p)->(%p)\n", This, plcid);
298
299     *plcid = GetUserDefaultLCID();
300     return S_OK;
301 }
302
303 static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName,
304         DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti)
305 {
306     ScriptHost *This = ACTSCPSITE_THIS(iface);
307
308     TRACE("(%p)->(%s %x %p %p)\n", This, debugstr_w(pstrName), dwReturnMask, ppiunkItem, ppti);
309
310     if(dwReturnMask != SCRIPTINFO_IUNKNOWN) {
311         FIXME("Unsupported mask %x\n", dwReturnMask);
312         return E_NOTIMPL;
313     }
314
315     *ppiunkItem = NULL;
316
317     if(strcmpW(pstrName, windowW))
318         return DISP_E_MEMBERNOTFOUND;
319
320     if(!This->window)
321         return E_FAIL;
322
323     /* FIXME: Return proxy object */
324     *ppiunkItem = (IUnknown*)HTMLWINDOW2(This->window);
325     IUnknown_AddRef(*ppiunkItem);
326
327     return S_OK;
328 }
329
330 static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *pbstrVersion)
331 {
332     ScriptHost *This = ACTSCPSITE_THIS(iface);
333     FIXME("(%p)->(%p)\n", This, pbstrVersion);
334     return E_NOTIMPL;
335 }
336
337 static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface,
338         const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo)
339 {
340     ScriptHost *This = ACTSCPSITE_THIS(iface);
341     FIXME("(%p)->(%p %p)\n", This, pvarResult, pexcepinfo);
342     return E_NOTIMPL;
343 }
344
345 static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE ssScriptState)
346 {
347     ScriptHost *This = ACTSCPSITE_THIS(iface);
348
349     TRACE("(%p)->(%x)\n", This, ssScriptState);
350
351     This->script_state = ssScriptState;
352     return S_OK;
353 }
354
355 static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror)
356 {
357     ScriptHost *This = ACTSCPSITE_THIS(iface);
358     FIXME("(%p)->(%p)\n", This, pscripterror);
359     return E_NOTIMPL;
360 }
361
362 static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
363 {
364     ScriptHost *This = ACTSCPSITE_THIS(iface);
365
366     TRACE("(%p)->()\n", This);
367
368     return S_OK;
369 }
370
371 static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface)
372 {
373     ScriptHost *This = ACTSCPSITE_THIS(iface);
374
375     TRACE("(%p)->()\n", This);
376
377     return S_OK;
378 }
379
380 #undef ACTSCPSITE_THIS
381
382 static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = {
383     ActiveScriptSite_QueryInterface,
384     ActiveScriptSite_AddRef,
385     ActiveScriptSite_Release,
386     ActiveScriptSite_GetLCID,
387     ActiveScriptSite_GetItemInfo,
388     ActiveScriptSite_GetDocVersionString,
389     ActiveScriptSite_OnScriptTerminate,
390     ActiveScriptSite_OnStateChange,
391     ActiveScriptSite_OnScriptError,
392     ActiveScriptSite_OnEnterScript,
393     ActiveScriptSite_OnLeaveScript
394 };
395
396 #define ACTSCPPOLL_THIS(iface) DEFINE_THIS(ScriptHost, IActiveScriptSiteInterruptPoll, iface)
397
398 static HRESULT WINAPI ActiveScriptSiteInterruptPoll_QueryInterface(IActiveScriptSiteInterruptPoll *iface,
399         REFIID riid, void **ppv)
400 {
401     ScriptHost *This = ACTSCPPOLL_THIS(iface);
402     return IActiveScriptSite_QueryInterface(ACTSCPSITE(This), riid, ppv);
403 }
404
405 static ULONG WINAPI ActiveScriptSiteInterruptPoll_AddRef(IActiveScriptSiteInterruptPoll *iface)
406 {
407     ScriptHost *This = ACTSCPPOLL_THIS(iface);
408     return IActiveScriptSite_AddRef(ACTSCPSITE(This));
409 }
410
411 static ULONG WINAPI ActiveScriptSiteInterruptPoll_Release(IActiveScriptSiteInterruptPoll *iface)
412 {
413     ScriptHost *This = ACTSCPPOLL_THIS(iface);
414     return IActiveScriptSite_Release(ACTSCPSITE(This));
415 }
416
417 static HRESULT WINAPI ActiveScriptSiteInterruptPoll_QueryContinue(IActiveScriptSiteInterruptPoll *iface)
418 {
419     ScriptHost *This = ACTSCPPOLL_THIS(iface);
420
421     TRACE("(%p)\n", This);
422
423     return S_OK;
424 }
425
426 #undef ACTSCPPOLL_THIS
427
428 static const IActiveScriptSiteInterruptPollVtbl ActiveScriptSiteInterruptPollVtbl = {
429     ActiveScriptSiteInterruptPoll_QueryInterface,
430     ActiveScriptSiteInterruptPoll_AddRef,
431     ActiveScriptSiteInterruptPoll_Release,
432     ActiveScriptSiteInterruptPoll_QueryContinue
433 };
434
435 #define ACTSCPWIN_THIS(iface) DEFINE_THIS(ScriptHost, IActiveScriptSiteWindow, iface)
436
437 static HRESULT WINAPI ActiveScriptSiteWindow_QueryInterface(IActiveScriptSiteWindow *iface,
438         REFIID riid, void **ppv)
439 {
440     ScriptHost *This = ACTSCPWIN_THIS(iface);
441     return IActiveScriptSite_QueryInterface(ACTSCPSITE(This), riid, ppv);
442 }
443
444 static ULONG WINAPI ActiveScriptSiteWindow_AddRef(IActiveScriptSiteWindow *iface)
445 {
446     ScriptHost *This = ACTSCPWIN_THIS(iface);
447     return IActiveScriptSite_AddRef(ACTSCPSITE(This));
448 }
449
450 static ULONG WINAPI ActiveScriptSiteWindow_Release(IActiveScriptSiteWindow *iface)
451 {
452     ScriptHost *This = ACTSCPWIN_THIS(iface);
453     return IActiveScriptSite_Release(ACTSCPSITE(This));
454 }
455
456 static HRESULT WINAPI ActiveScriptSiteWindow_GetWindow(IActiveScriptSiteWindow *iface, HWND *phwnd)
457 {
458     ScriptHost *This = ACTSCPWIN_THIS(iface);
459     FIXME("(%p)->(%p)\n", This, phwnd);
460     return E_NOTIMPL;
461 }
462
463 static HRESULT WINAPI ActiveScriptSiteWindow_EnableModeless(IActiveScriptSiteWindow *iface, BOOL fEnable)
464 {
465     ScriptHost *This = ACTSCPWIN_THIS(iface);
466     FIXME("(%p)->(%x)\n", This, fEnable);
467     return E_NOTIMPL;
468 }
469
470 #undef ACTSCPWIN_THIS
471
472 static const IActiveScriptSiteWindowVtbl ActiveScriptSiteWindowVtbl = {
473     ActiveScriptSiteWindow_QueryInterface,
474     ActiveScriptSiteWindow_AddRef,
475     ActiveScriptSiteWindow_Release,
476     ActiveScriptSiteWindow_GetWindow,
477     ActiveScriptSiteWindow_EnableModeless
478 };
479
480 #define ACTSCPDBG_THIS(iface) DEFINE_THIS(ScriptHost, IActiveScriptSiteDebug, iface)
481
482 static HRESULT WINAPI ActiveScriptSiteDebug_QueryInterface(IActiveScriptSiteDebug *iface,
483         REFIID riid, void **ppv)
484 {
485     ScriptHost *This = ACTSCPDBG_THIS(iface);
486     return IActiveScriptSite_QueryInterface(ACTSCPSITE(This), riid, ppv);
487 }
488
489 static ULONG WINAPI ActiveScriptSiteDebug_AddRef(IActiveScriptSiteDebug *iface)
490 {
491     ScriptHost *This = ACTSCPDBG_THIS(iface);
492     return IActiveScriptSite_AddRef(ACTSCPSITE(This));
493 }
494
495 static ULONG WINAPI ActiveScriptSiteDebug_Release(IActiveScriptSiteDebug *iface)
496 {
497     ScriptHost *This = ACTSCPDBG_THIS(iface);
498     return IActiveScriptSite_Release(ACTSCPSITE(This));
499 }
500
501 static HRESULT WINAPI ActiveScriptSiteDebug_GetDocumentContextFromPosition(IActiveScriptSiteDebug *iface,
502             CTXARG_T dwSourceContext, ULONG uCharacterOffset, ULONG uNumChars, IDebugDocumentContext **ppsc)
503 {
504     ScriptHost *This = ACTSCPDBG_THIS(iface);
505     FIXME("(%p)->(%s %u %u %p)\n", This, wine_dbgstr_longlong(dwSourceContext), uCharacterOffset,
506           uNumChars, ppsc);
507     return E_NOTIMPL;
508 }
509
510 static HRESULT WINAPI ActiveScriptSiteDebug_GetApplication(IActiveScriptSiteDebug *iface, IDebugApplication **ppda)
511 {
512     ScriptHost *This = ACTSCPDBG_THIS(iface);
513     FIXME("(%p)->(%p)\n", This, ppda);
514     return E_NOTIMPL;
515 }
516
517 static HRESULT WINAPI ActiveScriptSiteDebug_GetRootApplicationNode(IActiveScriptSiteDebug *iface,
518             IDebugApplicationNode **ppdanRoot)
519 {
520     ScriptHost *This = ACTSCPDBG_THIS(iface);
521     FIXME("(%p)->(%p)\n", This, ppdanRoot);
522     return E_NOTIMPL;
523 }
524
525 static HRESULT WINAPI ActiveScriptSiteDebug_OnScriptErrorDebug(IActiveScriptSiteDebug *iface,
526             IActiveScriptErrorDebug *pErrorDebug, BOOL *pfEnterDebugger, BOOL *pfCallOnScriptErrorWhenContinuing)
527 {
528     ScriptHost *This = ACTSCPDBG_THIS(iface);
529     FIXME("(%p)->(%p %p %p)\n", This, pErrorDebug, pfEnterDebugger, pfCallOnScriptErrorWhenContinuing);
530     return E_NOTIMPL;
531 }
532
533 #undef ACTSCPDBG_THIS
534
535 static const IActiveScriptSiteDebugVtbl ActiveScriptSiteDebugVtbl = {
536     ActiveScriptSiteDebug_QueryInterface,
537     ActiveScriptSiteDebug_AddRef,
538     ActiveScriptSiteDebug_Release,
539     ActiveScriptSiteDebug_GetDocumentContextFromPosition,
540     ActiveScriptSiteDebug_GetApplication,
541     ActiveScriptSiteDebug_GetRootApplicationNode,
542     ActiveScriptSiteDebug_OnScriptErrorDebug
543 };
544
545 #define SERVPROV_THIS(iface) DEFINE_THIS(ScriptHost, ServiceProvider, iface)
546
547 static HRESULT WINAPI ASServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
548 {
549     ScriptHost *This = SERVPROV_THIS(iface);
550     return IActiveScriptSite_QueryInterface(ACTSCPSITE(This), riid, ppv);
551 }
552
553 static ULONG WINAPI ASServiceProvider_AddRef(IServiceProvider *iface)
554 {
555     ScriptHost *This = SERVPROV_THIS(iface);
556     return IActiveScriptSite_AddRef(ACTSCPSITE(This));
557 }
558
559 static ULONG WINAPI ASServiceProvider_Release(IServiceProvider *iface)
560 {
561     ScriptHost *This = SERVPROV_THIS(iface);
562     return IActiveScriptSite_Release(ACTSCPSITE(This));
563 }
564
565 static HRESULT WINAPI ASServiceProvider_QueryService(IServiceProvider *iface, REFGUID guidService,
566         REFIID riid, void **ppv)
567 {
568     ScriptHost *This = SERVPROV_THIS(iface);
569
570     if(IsEqualGUID(&SID_SInternetHostSecurityManager, guidService)) {
571         TRACE("(%p)->(SID_SInternetHostSecurityManager)\n", This);
572
573         if(!This->window || !This->window->doc)
574             return E_NOINTERFACE;
575
576         return IInternetHostSecurityManager_QueryInterface(HOSTSECMGR(This->window->doc), riid, ppv);
577     }
578
579     FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
580     return E_NOINTERFACE;
581 }
582
583 #undef SERVPROV_THIS
584
585 static const IServiceProviderVtbl ASServiceProviderVtbl = {
586     ASServiceProvider_QueryInterface,
587     ASServiceProvider_AddRef,
588     ASServiceProvider_Release,
589     ASServiceProvider_QueryService
590 };
591
592 static ScriptHost *create_script_host(HTMLWindow *window, const GUID *guid)
593 {
594     ScriptHost *ret;
595     HRESULT hres;
596
597     ret = heap_alloc_zero(sizeof(*ret));
598     ret->lpIActiveScriptSiteVtbl               = &ActiveScriptSiteVtbl;
599     ret->lpIActiveScriptSiteInterruptPollVtbl  = &ActiveScriptSiteInterruptPollVtbl;
600     ret->lpIActiveScriptSiteWindowVtbl         = &ActiveScriptSiteWindowVtbl;
601     ret->lpIActiveScriptSiteDebugVtbl          = &ActiveScriptSiteDebugVtbl;
602     ret->lpServiceProviderVtbl                 = &ASServiceProviderVtbl;
603     ret->ref = 1;
604     ret->window = window;
605     ret->script_state = SCRIPTSTATE_UNINITIALIZED;
606
607     ret->guid = *guid;
608     list_add_tail(&window->script_hosts, &ret->entry);
609
610     hres = CoCreateInstance(&ret->guid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
611             &IID_IActiveScript, (void**)&ret->script);
612     if(FAILED(hres))
613         WARN("Could not load script engine: %08x\n", hres);
614     else if(!init_script_engine(ret))
615         release_script_engine(ret);
616
617     return ret;
618 }
619
620 static void parse_text(ScriptHost *script_host, LPCWSTR text)
621 {
622     EXCEPINFO excepinfo;
623     VARIANT var;
624     HRESULT hres;
625
626     static const WCHAR script_endW[] = {'<','/','S','C','R','I','P','T','>',0};
627
628     TRACE("%s\n", debugstr_w(text));
629
630     VariantInit(&var);
631     memset(&excepinfo, 0, sizeof(excepinfo));
632     TRACE(">>>\n");
633     hres = IActiveScriptParse64_ParseScriptText(script_host->parse, text, windowW, NULL, script_endW,
634                                               0, 0, SCRIPTTEXT_ISVISIBLE|SCRIPTTEXT_HOSTMANAGESSOURCE,
635                                               &var, &excepinfo);
636     if(SUCCEEDED(hres))
637         TRACE("<<<\n");
638     else
639         WARN("<<< %08x\n", hres);
640
641 }
642
643 static void parse_extern_script(ScriptHost *script_host, LPCWSTR src)
644 {
645     IMoniker *mon;
646     char *buf;
647     WCHAR *text;
648     DWORD len, size=0;
649     HRESULT hres;
650
651     static const WCHAR wine_schemaW[] = {'w','i','n','e',':'};
652
653     if(strlenW(src) > sizeof(wine_schemaW)/sizeof(WCHAR) && !memcmp(src, wine_schemaW, sizeof(wine_schemaW)))
654         src += sizeof(wine_schemaW)/sizeof(WCHAR);
655
656     hres = CreateURLMoniker(NULL, src, &mon);
657     if(FAILED(hres))
658         return;
659
660     hres = bind_mon_to_buffer(script_host->window->doc, mon, (void**)&buf, &size);
661     IMoniker_Release(mon);
662     if(FAILED(hres))
663         return;
664
665     len = MultiByteToWideChar(CP_ACP, 0, buf, size, NULL, 0);
666     text = heap_alloc((len+1)*sizeof(WCHAR));
667     MultiByteToWideChar(CP_ACP, 0, buf, size, text, len);
668     heap_free(buf);
669     text[len] = 0;
670
671     parse_text(script_host, text);
672
673     heap_free(text);
674 }
675
676 static void parse_inline_script(ScriptHost *script_host, nsIDOMHTMLScriptElement *nsscript)
677 {
678     const PRUnichar *text;
679     nsAString text_str;
680     nsresult nsres;
681
682     nsAString_Init(&text_str, NULL);
683
684     nsres = nsIDOMHTMLScriptElement_GetText(nsscript, &text_str);
685
686     if(NS_SUCCEEDED(nsres)) {
687         nsAString_GetData(&text_str, &text);
688         parse_text(script_host, text);
689     }else {
690         ERR("GetText failed: %08x\n", nsres);
691     }
692
693     nsAString_Finish(&text_str);
694 }
695
696 static void parse_script_elem(ScriptHost *script_host, nsIDOMHTMLScriptElement *nsscript)
697 {
698     const PRUnichar *src;
699     nsAString src_str;
700     nsresult nsres;
701
702     nsAString_Init(&src_str, NULL);
703
704     nsres = nsIDOMHTMLScriptElement_GetSrc(nsscript, &src_str);
705     nsAString_GetData(&src_str, &src);
706
707     if(NS_FAILED(nsres))
708         ERR("GetSrc failed: %08x\n", nsres);
709     else if(*src)
710         parse_extern_script(script_host, src);
711     else
712         parse_inline_script(script_host, nsscript);
713
714     nsAString_Finish(&src_str);
715 }
716
717 static BOOL get_guid_from_type(LPCWSTR type, GUID *guid)
718 {
719     const WCHAR text_javascriptW[] =
720         {'t','e','x','t','/','j','a','v','a','s','c','r','i','p','t',0};
721
722     /* FIXME: Handle more types */
723     if(!strcmpiW(type, text_javascriptW)) {
724         *guid = CLSID_JScript;
725     }else {
726         FIXME("Unknown type %s\n", debugstr_w(type));
727         return FALSE;
728     }
729
730     return TRUE;
731 }
732
733 static BOOL get_guid_from_language(LPCWSTR type, GUID *guid)
734 {
735     HRESULT hres;
736
737     hres = CLSIDFromProgID(type, guid);
738     if(FAILED(hres))
739         return FALSE;
740
741     /* FIXME: Check CATID_ActiveScriptParse */
742
743     return TRUE;
744 }
745
746 static BOOL get_script_guid(nsIDOMHTMLScriptElement *nsscript, GUID *guid)
747 {
748     nsAString attr_str, val_str;
749     BOOL ret = FALSE;
750     nsresult nsres;
751
752     static const PRUnichar languageW[] = {'l','a','n','g','u','a','g','e',0};
753
754     nsAString_Init(&val_str, NULL);
755
756     nsres = nsIDOMHTMLScriptElement_GetType(nsscript, &val_str);
757     if(NS_SUCCEEDED(nsres)) {
758         const PRUnichar *type;
759
760         nsAString_GetData(&val_str, &type);
761         if(*type) {
762             ret = get_guid_from_type(type, guid);
763             nsAString_Finish(&val_str);
764             return ret;
765         }
766     }else {
767         ERR("GetType failed: %08x\n", nsres);
768     }
769
770     nsAString_InitDepend(&attr_str, languageW);
771     nsres = nsIDOMHTMLScriptElement_GetAttribute(nsscript, &attr_str, &val_str);
772     nsAString_Finish(&attr_str);
773     if(NS_SUCCEEDED(nsres)) {
774         const PRUnichar *language;
775
776         nsAString_GetData(&val_str, &language);
777
778         if(*language) {
779             ret = get_guid_from_language(language, guid);
780         }else {
781             *guid = CLSID_JScript;
782             ret = TRUE;
783         }
784     }else {
785         ERR("GetAttribute(language) failed: %08x\n", nsres);
786     }
787
788     nsAString_Finish(&val_str);
789
790     return ret;
791 }
792
793 static ScriptHost *get_script_host(HTMLWindow *window, const GUID *guid)
794 {
795     ScriptHost *iter;
796
797     if(IsEqualGUID(&CLSID_JScript, guid) && window->scriptmode != SCRIPTMODE_ACTIVESCRIPT) {
798         TRACE("Ignoring JScript\n");
799         return NULL;
800     }
801
802     LIST_FOR_EACH_ENTRY(iter, &window->script_hosts, ScriptHost, entry) {
803         if(IsEqualGUID(guid, &iter->guid))
804             return iter;
805     }
806
807     return create_script_host(window, guid);
808 }
809
810 void doc_insert_script(HTMLWindow *window, nsIDOMHTMLScriptElement *nsscript)
811 {
812     ScriptHost *script_host;
813     GUID guid;
814
815     if(!get_script_guid(nsscript, &guid)) {
816         WARN("Could not find script GUID\n");
817         return;
818     }
819
820     script_host = get_script_host(window, &guid);
821     if(!script_host)
822         return;
823
824     if(script_host->parse)
825         parse_script_elem(script_host, nsscript);
826 }
827
828 IDispatch *script_parse_event(HTMLWindow *window, LPCWSTR text)
829 {
830     ScriptHost *script_host;
831     GUID guid = CLSID_JScript;
832     const WCHAR *ptr;
833     IDispatch *disp;
834     HRESULT hres;
835
836     static const WCHAR delimiterW[] = {'\"',0};
837
838     for(ptr = text; isalnumW(*ptr); ptr++);
839     if(*ptr == ':') {
840         LPWSTR language;
841         BOOL b;
842
843         language = heap_alloc((ptr-text+1)*sizeof(WCHAR));
844         memcpy(language, text, (ptr-text)*sizeof(WCHAR));
845         language[ptr-text] = 0;
846
847         b = get_guid_from_language(language, &guid);
848
849         heap_free(language);
850
851         if(!b) {
852             WARN("Could not find language\n");
853             return NULL;
854         }
855
856         ptr++;
857     }else {
858         ptr = text;
859     }
860
861     script_host = get_script_host(window, &guid);
862     if(!script_host || !script_host->parse_proc)
863         return NULL;
864
865     hres = IActiveScriptParseProcedure64_ParseProcedureText(script_host->parse_proc, ptr, NULL, emptyW,
866             NULL, NULL, delimiterW, 0 /* FIXME */, 0,
867             SCRIPTPROC_HOSTMANAGESSOURCE|SCRIPTPROC_IMPLICIT_THIS|SCRIPTPROC_IMPLICIT_PARENTS, &disp);
868     if(FAILED(hres)) {
869         WARN("ParseProcedureText failed: %08x\n", hres);
870         return NULL;
871     }
872
873     TRACE("ret %p\n", disp);
874     return disp;
875 }
876
877 IDispatch *get_script_disp(ScriptHost *script_host)
878 {
879     IDispatch *disp;
880     HRESULT hres;
881
882     if(!script_host->script)
883         return NULL;
884
885     hres = IActiveScript_GetScriptDispatch(script_host->script, windowW, &disp);
886     if(FAILED(hres))
887         return NULL;
888
889     return disp;
890 }
891
892 BOOL find_global_prop(HTMLWindow *window, BSTR name, DWORD flags, ScriptHost **ret_host, DISPID *ret_id)
893 {
894     IDispatchEx *dispex;
895     IDispatch *disp;
896     ScriptHost *iter;
897     HRESULT hres;
898
899     LIST_FOR_EACH_ENTRY(iter, &window->script_hosts, ScriptHost, entry) {
900         disp = get_script_disp(iter);
901         if(!disp)
902             continue;
903
904         hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
905         if(SUCCEEDED(hres)) {
906             hres = IDispatchEx_GetDispID(dispex, name, flags & (~fdexNameEnsure), ret_id);
907             IDispatchEx_Release(dispex);
908         }else {
909             FIXME("No IDispatchEx\n");
910             hres = E_NOTIMPL;
911         }
912
913         IDispatch_Release(disp);
914         if(SUCCEEDED(hres)) {
915             *ret_host = iter;
916             return TRUE;
917         }
918     }
919
920     return FALSE;
921 }
922
923 static BOOL is_jscript_available(void)
924 {
925     static BOOL available, checked;
926
927     if(!checked) {
928         IUnknown *unk;
929         HRESULT hres = CoGetClassObject(&CLSID_JScript, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk);
930
931         if(SUCCEEDED(hres)) {
932             available = TRUE;
933             IUnknown_Release(unk);
934         }else {
935             available = FALSE;
936         }
937         checked = TRUE;
938     }
939
940     return available;
941 }
942
943 void set_script_mode(HTMLWindow *window, SCRIPTMODE mode)
944 {
945     nsIWebBrowserSetup *setup;
946     nsresult nsres;
947
948     if(mode == SCRIPTMODE_ACTIVESCRIPT && !is_jscript_available()) {
949         TRACE("jscript.dll not available\n");
950         window->scriptmode = SCRIPTMODE_GECKO;
951         return;
952     }
953
954     window->scriptmode = mode;
955
956     if(!window->doc_obj->nscontainer || !window->doc_obj->nscontainer->webbrowser)
957         return;
958
959     nsres = nsIWebBrowser_QueryInterface(window->doc_obj->nscontainer->webbrowser,
960             &IID_nsIWebBrowserSetup, (void**)&setup);
961     if(NS_SUCCEEDED(nsres)) {
962         nsres = nsIWebBrowserSetup_SetProperty(setup, SETUP_ALLOW_JAVASCRIPT,
963                 window->scriptmode == SCRIPTMODE_GECKO);
964         nsIWebBrowserSetup_Release(setup);
965     }
966
967     if(NS_FAILED(nsres))
968         ERR("JavaScript setup failed: %08x\n", nsres);
969 }
970
971 void release_script_hosts(HTMLWindow *window)
972 {
973     ScriptHost *iter;
974
975     while(!list_empty(&window->script_hosts)) {
976         iter = LIST_ENTRY(list_head(&window->script_hosts), ScriptHost, entry);
977
978         release_script_engine(iter);
979         list_remove(&iter->entry);
980         iter->window = NULL;
981         IActiveScript_Release(ACTSCPSITE(iter));
982     }
983 }