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