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