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