include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / mshtml / script.c
blob295c8a0dc15d18ad6a2caa72f209c05917ed5351
1 /*
2 * Copyright 2008 Jacek Caban for CodeWeavers
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.
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.
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
19 #include <stdarg.h>
21 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "ole2.h"
27 #include "activscp.h"
28 #include "activdbg.h"
29 #include "shlwapi.h"
31 #include "wine/debug.h"
33 #include "mshtml_private.h"
34 #include "htmlscript.h"
35 #include "pluginhost.h"
36 #include "htmlevent.h"
37 #include "binding.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
41 #ifdef _WIN64
43 #define CTXARG_T DWORDLONG
44 #define IActiveScriptSiteDebugVtbl IActiveScriptSiteDebug64Vtbl
46 #define IActiveScriptParse_Release IActiveScriptParse64_Release
47 #define IActiveScriptParse_InitNew IActiveScriptParse64_InitNew
48 #define IActiveScriptParse_ParseScriptText IActiveScriptParse64_ParseScriptText
49 #define IActiveScriptParseProcedure2_Release IActiveScriptParseProcedure2_64_Release
50 #define IActiveScriptParseProcedure2_ParseProcedureText IActiveScriptParseProcedure2_64_ParseProcedureText
52 #else
54 #define CTXARG_T DWORD
55 #define IActiveScriptSiteDebugVtbl IActiveScriptSiteDebug32Vtbl
57 #define IActiveScriptParse_Release IActiveScriptParse32_Release
58 #define IActiveScriptParse_InitNew IActiveScriptParse32_InitNew
59 #define IActiveScriptParse_ParseScriptText IActiveScriptParse32_ParseScriptText
60 #define IActiveScriptParseProcedure2_Release IActiveScriptParseProcedure2_32_Release
61 #define IActiveScriptParseProcedure2_ParseProcedureText IActiveScriptParseProcedure2_32_ParseProcedureText
63 #endif
65 /* See jscript.h in jscript.dll. */
66 #define SCRIPTLANGUAGEVERSION_HTML 0x400
67 #define SCRIPTLANGUAGEVERSION_ES5 0x102
68 #define SCRIPTLANGUAGEVERSION_ES6 0x103
70 struct ScriptHost {
71 IActiveScriptSite IActiveScriptSite_iface;
72 IActiveScriptSiteInterruptPoll IActiveScriptSiteInterruptPoll_iface;
73 IActiveScriptSiteWindow IActiveScriptSiteWindow_iface;
74 IActiveScriptSiteUIControl IActiveScriptSiteUIControl_iface;
75 IActiveScriptSiteDebug IActiveScriptSiteDebug_iface;
76 IServiceProvider IServiceProvider_iface;
77 IOleCommandTarget IOleCommandTarget_iface;
79 LONG ref;
81 IActiveScript *script;
82 IActiveScriptParse *parse;
83 IActiveScriptParseProcedure2 *parse_proc;
85 SCRIPTSTATE script_state;
87 HTMLInnerWindow *window;
89 GUID guid;
90 struct list entry;
93 static ScriptHost *get_elem_script_host(HTMLInnerWindow*,HTMLScriptElement*);
95 static BOOL set_script_prop(IActiveScript *script, DWORD property, VARIANT *val)
97 IActiveScriptProperty *script_prop;
98 HRESULT hres;
100 hres = IActiveScript_QueryInterface(script, &IID_IActiveScriptProperty,
101 (void**)&script_prop);
102 if(FAILED(hres)) {
103 WARN("Could not get IActiveScriptProperty iface: %08lx\n", hres);
104 return FALSE;
107 hres = IActiveScriptProperty_SetProperty(script_prop, property, NULL, val);
108 IActiveScriptProperty_Release(script_prop);
109 if(FAILED(hres)) {
110 WARN("SetProperty(%lx) failed: %08lx\n", property, hres);
111 return FALSE;
114 return TRUE;
117 static BOOL init_script_engine(ScriptHost *script_host, IActiveScript *script)
119 compat_mode_t compat_mode;
120 IObjectSafety *safety;
121 SCRIPTSTATE state;
122 DWORD supported_opts=0, enabled_opts=0, script_mode;
123 VARIANT var;
124 HRESULT hres;
126 hres = IActiveScript_QueryInterface(script, &IID_IActiveScriptParse, (void**)&script_host->parse);
127 if(FAILED(hres)) {
128 WARN("Could not get IActiveScriptParse: %08lx\n", hres);
129 return FALSE;
132 hres = IActiveScript_QueryInterface(script, &IID_IObjectSafety, (void**)&safety);
133 if(FAILED(hres)) {
134 FIXME("Could not get IObjectSafety: %08lx\n", hres);
135 return FALSE;
138 hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, &supported_opts, &enabled_opts);
139 if(FAILED(hres)) {
140 FIXME("GetInterfaceSafetyOptions failed: %08lx\n", hres);
141 }else if(!(supported_opts & INTERFACE_USES_DISPEX)) {
142 FIXME("INTERFACE_USES_DISPEX is not supported\n");
143 }else {
144 hres = IObjectSafety_SetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse,
145 INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER,
146 INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER);
147 if(FAILED(hres))
148 FIXME("SetInterfaceSafetyOptions failed: %08lx\n", hres);
151 IObjectSafety_Release(safety);
152 if(FAILED(hres))
153 return FALSE;
155 compat_mode = lock_document_mode(script_host->window->doc);
156 script_mode = compat_mode < COMPAT_MODE_IE8 ? SCRIPTLANGUAGEVERSION_5_7 : SCRIPTLANGUAGEVERSION_5_8;
157 if(IsEqualGUID(&script_host->guid, &CLSID_JScript)) {
158 if(compat_mode >= COMPAT_MODE_IE11)
159 script_mode = SCRIPTLANGUAGEVERSION_ES6;
160 else if(compat_mode >= COMPAT_MODE_IE9)
161 script_mode = SCRIPTLANGUAGEVERSION_ES5;
162 script_mode |= SCRIPTLANGUAGEVERSION_HTML;
164 V_VT(&var) = VT_I4;
165 V_I4(&var) = script_mode;
166 if(!set_script_prop(script, SCRIPTPROP_INVOKEVERSIONING, &var) && (script_mode & SCRIPTLANGUAGEVERSION_HTML)) {
167 /* If this failed, we're most likely using native jscript. */
168 WARN("Failed to set script mode to HTML version.\n");
169 V_I4(&var) = compat_mode < COMPAT_MODE_IE8 ? SCRIPTLANGUAGEVERSION_5_7 : SCRIPTLANGUAGEVERSION_5_8;
170 set_script_prop(script, SCRIPTPROP_INVOKEVERSIONING, &var);
173 V_VT(&var) = VT_BOOL;
174 V_BOOL(&var) = VARIANT_TRUE;
175 set_script_prop(script, SCRIPTPROP_HACK_TRIDENTEVENTSINK, &var);
177 hres = IActiveScriptParse_InitNew(script_host->parse);
178 if(FAILED(hres)) {
179 WARN("InitNew failed: %08lx\n", hres);
180 return FALSE;
183 hres = IActiveScript_SetScriptSite(script, &script_host->IActiveScriptSite_iface);
184 if(FAILED(hres)) {
185 WARN("SetScriptSite failed: %08lx\n", hres);
186 IActiveScript_Close(script);
187 return FALSE;
190 hres = IActiveScript_GetScriptState(script, &state);
191 if(FAILED(hres))
192 WARN("GetScriptState failed: %08lx\n", hres);
193 else if(state != SCRIPTSTATE_INITIALIZED)
194 FIXME("state = %x\n", state);
196 hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_STARTED);
197 if(FAILED(hres)) {
198 WARN("Starting script failed: %08lx\n", hres);
199 return FALSE;
202 hres = IActiveScript_AddNamedItem(script, L"window",
203 SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS);
204 if(SUCCEEDED(hres)) {
205 ScriptHost *first_host;
207 V_VT(&var) = VT_BOOL;
208 V_BOOL(&var) = VARIANT_TRUE;
210 LIST_FOR_EACH_ENTRY(first_host, &script_host->window->script_hosts, ScriptHost, entry) {
211 if(first_host->script) {
212 V_BOOL(&var) = VARIANT_FALSE;
213 break;
216 set_script_prop(script, SCRIPTPROP_ABBREVIATE_GLOBALNAME_RESOLUTION, &var);
218 /* if this was second engine initialized, also set it to first engine, since it used to be TRUE */
219 if(!V_BOOL(&var)) {
220 struct list *iter = &first_host->entry;
221 BOOL is_second_init = TRUE;
223 while((iter = list_next(&script_host->window->script_hosts, iter))) {
224 if(LIST_ENTRY(iter, ScriptHost, entry)->script) {
225 is_second_init = FALSE;
226 break;
229 if(is_second_init)
230 set_script_prop(first_host->script, SCRIPTPROP_ABBREVIATE_GLOBALNAME_RESOLUTION, &var);
232 }else {
233 WARN("AddNamedItem failed: %08lx\n", hres);
236 hres = IActiveScript_QueryInterface(script, &IID_IActiveScriptParseProcedure2,
237 (void**)&script_host->parse_proc);
238 if(FAILED(hres)) {
239 /* FIXME: QI for IActiveScriptParseProcedure */
240 WARN("Could not get IActiveScriptParseProcedure iface: %08lx\n", hres);
243 return TRUE;
246 static void release_script_engine(ScriptHost *This)
248 if(!This->script)
249 return;
251 switch(This->script_state) {
252 case SCRIPTSTATE_CONNECTED:
253 IActiveScript_SetScriptState(This->script, SCRIPTSTATE_DISCONNECTED);
255 case SCRIPTSTATE_STARTED:
256 case SCRIPTSTATE_DISCONNECTED:
257 case SCRIPTSTATE_INITIALIZED:
258 IActiveScript_Close(This->script);
260 default:
261 unlink_ref(&This->parse_proc);
262 unlink_ref(&This->parse);
265 IActiveScript_Release(This->script);
266 This->script = NULL;
267 This->script_state = SCRIPTSTATE_UNINITIALIZED;
270 void connect_scripts(HTMLInnerWindow *window)
272 ScriptHost *iter;
274 LIST_FOR_EACH_ENTRY(iter, &window->script_hosts, ScriptHost, entry) {
275 if(iter->script_state == SCRIPTSTATE_STARTED)
276 IActiveScript_SetScriptState(iter->script, SCRIPTSTATE_CONNECTED);
280 static inline ScriptHost *impl_from_IActiveScriptSite(IActiveScriptSite *iface)
282 return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSite_iface);
285 static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv)
287 ScriptHost *This = impl_from_IActiveScriptSite(iface);
289 *ppv = NULL;
291 if(IsEqualGUID(&IID_IUnknown, riid)) {
292 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
293 *ppv = &This->IActiveScriptSite_iface;
294 }else if(IsEqualGUID(&IID_IActiveScriptSite, riid)) {
295 TRACE("(%p)->(IID_IActiveScriptSite %p)\n", This, ppv);
296 *ppv = &This->IActiveScriptSite_iface;
297 }else if(IsEqualGUID(&IID_IActiveScriptSiteInterruptPoll, riid)) {
298 TRACE("(%p)->(IID_IActiveScriptSiteInterruprtPoll %p)\n", This, ppv);
299 *ppv = &This->IActiveScriptSiteInterruptPoll_iface;
300 }else if(IsEqualGUID(&IID_IActiveScriptSiteWindow, riid)) {
301 TRACE("(%p)->(IID_IActiveScriptSiteWindow %p)\n", This, ppv);
302 *ppv = &This->IActiveScriptSiteWindow_iface;
303 }else if(IsEqualGUID(&IID_IActiveScriptSiteUIControl, riid)) {
304 TRACE("(%p)->(IID_IActiveScriptSiteUIControl %p)\n", This, ppv);
305 *ppv = &This->IActiveScriptSiteUIControl_iface;
306 }else if(IsEqualGUID(&IID_IActiveScriptSiteDebug, riid)) {
307 TRACE("(%p)->(IID_IActiveScriptSiteDebug %p)\n", This, ppv);
308 *ppv = &This->IActiveScriptSiteDebug_iface;
309 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
310 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
311 *ppv = &This->IServiceProvider_iface;
312 }else if(IsEqualGUID(&IID_IOleCommandTarget, riid)) {
313 TRACE("(%p)->(IID_IOleCommandTarget %p)\n", This, ppv);
314 *ppv = &This->IOleCommandTarget_iface;
315 }else if(IsEqualGUID(&IID_ICanHandleException, riid)) {
316 TRACE("(%p)->(IID_ICanHandleException not supported %p)\n", This, ppv);
317 return E_NOINTERFACE;
318 }else {
319 FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
320 return E_NOINTERFACE;
323 IUnknown_AddRef((IUnknown*)*ppv);
324 return S_OK;
327 static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface)
329 ScriptHost *This = impl_from_IActiveScriptSite(iface);
330 LONG ref = InterlockedIncrement(&This->ref);
332 TRACE("(%p) ref=%ld\n", This, ref);
334 return ref;
337 static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface)
339 ScriptHost *This = impl_from_IActiveScriptSite(iface);
340 LONG ref = InterlockedDecrement(&This->ref);
342 TRACE("(%p) ref=%ld\n", This, ref);
344 if(!ref) {
345 release_script_engine(This);
346 if(This->window)
347 list_remove(&This->entry);
348 free(This);
351 return ref;
354 static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid)
356 ScriptHost *This = impl_from_IActiveScriptSite(iface);
358 TRACE("(%p)->(%p)\n", This, plcid);
360 *plcid = GetUserDefaultLCID();
361 return S_OK;
364 static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName,
365 DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti)
367 ScriptHost *This = impl_from_IActiveScriptSite(iface);
369 TRACE("(%p)->(%s %lx %p %p)\n", This, debugstr_w(pstrName), dwReturnMask, ppiunkItem, ppti);
371 if(dwReturnMask != SCRIPTINFO_IUNKNOWN) {
372 FIXME("Unsupported mask %lx\n", dwReturnMask);
373 return E_NOTIMPL;
376 *ppiunkItem = NULL;
378 if(wcscmp(pstrName, L"window"))
379 return DISP_E_MEMBERNOTFOUND;
381 if(!This->window || !This->window->base.outer_window)
382 return E_FAIL;
384 /* FIXME: Return proxy object */
385 *ppiunkItem = (IUnknown*)&This->window->base.outer_window->base.IHTMLWindow2_iface;
386 IUnknown_AddRef(*ppiunkItem);
388 return S_OK;
391 static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *pbstrVersion)
393 ScriptHost *This = impl_from_IActiveScriptSite(iface);
394 FIXME("(%p)->(%p)\n", This, pbstrVersion);
395 return E_NOTIMPL;
398 static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface,
399 const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo)
401 ScriptHost *This = impl_from_IActiveScriptSite(iface);
402 FIXME("(%p)->(%p %p)\n", This, pvarResult, pexcepinfo);
403 return E_NOTIMPL;
406 static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE ssScriptState)
408 ScriptHost *This = impl_from_IActiveScriptSite(iface);
410 TRACE("(%p)->(%x)\n", This, ssScriptState);
412 This->script_state = ssScriptState;
413 return S_OK;
416 static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror)
418 ScriptHost *This = impl_from_IActiveScriptSite(iface);
419 FIXME("(%p)->(%p)\n", This, pscripterror);
420 return E_NOTIMPL;
423 static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
425 ScriptHost *This = impl_from_IActiveScriptSite(iface);
427 TRACE("(%p)->()\n", This);
429 return S_OK;
432 static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface)
434 ScriptHost *This = impl_from_IActiveScriptSite(iface);
436 TRACE("(%p)->()\n", This);
438 return S_OK;
441 static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = {
442 ActiveScriptSite_QueryInterface,
443 ActiveScriptSite_AddRef,
444 ActiveScriptSite_Release,
445 ActiveScriptSite_GetLCID,
446 ActiveScriptSite_GetItemInfo,
447 ActiveScriptSite_GetDocVersionString,
448 ActiveScriptSite_OnScriptTerminate,
449 ActiveScriptSite_OnStateChange,
450 ActiveScriptSite_OnScriptError,
451 ActiveScriptSite_OnEnterScript,
452 ActiveScriptSite_OnLeaveScript
455 static inline ScriptHost *impl_from_IActiveScriptSiteInterruptPoll(IActiveScriptSiteInterruptPoll *iface)
457 return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSiteInterruptPoll_iface);
460 static HRESULT WINAPI ActiveScriptSiteInterruptPoll_QueryInterface(IActiveScriptSiteInterruptPoll *iface,
461 REFIID riid, void **ppv)
463 ScriptHost *This = impl_from_IActiveScriptSiteInterruptPoll(iface);
464 return IActiveScriptSite_QueryInterface(&This->IActiveScriptSite_iface, riid, ppv);
467 static ULONG WINAPI ActiveScriptSiteInterruptPoll_AddRef(IActiveScriptSiteInterruptPoll *iface)
469 ScriptHost *This = impl_from_IActiveScriptSiteInterruptPoll(iface);
470 return IActiveScriptSite_AddRef(&This->IActiveScriptSite_iface);
473 static ULONG WINAPI ActiveScriptSiteInterruptPoll_Release(IActiveScriptSiteInterruptPoll *iface)
475 ScriptHost *This = impl_from_IActiveScriptSiteInterruptPoll(iface);
476 return IActiveScriptSite_Release(&This->IActiveScriptSite_iface);
479 static HRESULT WINAPI ActiveScriptSiteInterruptPoll_QueryContinue(IActiveScriptSiteInterruptPoll *iface)
481 ScriptHost *This = impl_from_IActiveScriptSiteInterruptPoll(iface);
483 TRACE("(%p)\n", This);
485 return S_OK;
488 static const IActiveScriptSiteInterruptPollVtbl ActiveScriptSiteInterruptPollVtbl = {
489 ActiveScriptSiteInterruptPoll_QueryInterface,
490 ActiveScriptSiteInterruptPoll_AddRef,
491 ActiveScriptSiteInterruptPoll_Release,
492 ActiveScriptSiteInterruptPoll_QueryContinue
495 static inline ScriptHost *impl_from_IActiveScriptSiteWindow(IActiveScriptSiteWindow *iface)
497 return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSiteWindow_iface);
500 static HRESULT WINAPI ActiveScriptSiteWindow_QueryInterface(IActiveScriptSiteWindow *iface,
501 REFIID riid, void **ppv)
503 ScriptHost *This = impl_from_IActiveScriptSiteWindow(iface);
504 return IActiveScriptSite_QueryInterface(&This->IActiveScriptSite_iface, riid, ppv);
507 static ULONG WINAPI ActiveScriptSiteWindow_AddRef(IActiveScriptSiteWindow *iface)
509 ScriptHost *This = impl_from_IActiveScriptSiteWindow(iface);
510 return IActiveScriptSite_AddRef(&This->IActiveScriptSite_iface);
513 static ULONG WINAPI ActiveScriptSiteWindow_Release(IActiveScriptSiteWindow *iface)
515 ScriptHost *This = impl_from_IActiveScriptSiteWindow(iface);
516 return IActiveScriptSite_Release(&This->IActiveScriptSite_iface);
519 static HRESULT WINAPI ActiveScriptSiteWindow_GetWindow(IActiveScriptSiteWindow *iface, HWND *phwnd)
521 ScriptHost *This = impl_from_IActiveScriptSiteWindow(iface);
523 TRACE("(%p)->(%p)\n", This, phwnd);
525 if(!This->window || !This->window->base.outer_window)
526 return E_UNEXPECTED;
528 *phwnd = This->window->base.outer_window->browser->doc->hwnd;
529 return S_OK;
532 static HRESULT WINAPI ActiveScriptSiteWindow_EnableModeless(IActiveScriptSiteWindow *iface, BOOL fEnable)
534 ScriptHost *This = impl_from_IActiveScriptSiteWindow(iface);
535 FIXME("(%p)->(%x)\n", This, fEnable);
536 return S_OK;
539 static const IActiveScriptSiteWindowVtbl ActiveScriptSiteWindowVtbl = {
540 ActiveScriptSiteWindow_QueryInterface,
541 ActiveScriptSiteWindow_AddRef,
542 ActiveScriptSiteWindow_Release,
543 ActiveScriptSiteWindow_GetWindow,
544 ActiveScriptSiteWindow_EnableModeless
547 static inline ScriptHost *impl_from_IActiveScriptSiteUIControl(IActiveScriptSiteUIControl *iface)
549 return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSiteUIControl_iface);
552 static HRESULT WINAPI ActiveScriptSiteUIControl_QueryInterface(IActiveScriptSiteUIControl *iface, REFIID riid, void **ppv)
554 ScriptHost *This = impl_from_IActiveScriptSiteUIControl(iface);
555 return IActiveScriptSite_QueryInterface(&This->IActiveScriptSite_iface, riid, ppv);
558 static ULONG WINAPI ActiveScriptSiteUIControl_AddRef(IActiveScriptSiteUIControl *iface)
560 ScriptHost *This = impl_from_IActiveScriptSiteUIControl(iface);
561 return IActiveScriptSite_AddRef(&This->IActiveScriptSite_iface);
564 static ULONG WINAPI ActiveScriptSiteUIControl_Release(IActiveScriptSiteUIControl *iface)
566 ScriptHost *This = impl_from_IActiveScriptSiteUIControl(iface);
567 return IActiveScriptSite_Release(&This->IActiveScriptSite_iface);
570 static HRESULT WINAPI ActiveScriptSiteUIControl_GetUIBehavior(IActiveScriptSiteUIControl *iface, SCRIPTUICITEM UicItem,
571 SCRIPTUICHANDLING *pUicHandling)
573 ScriptHost *This = impl_from_IActiveScriptSiteUIControl(iface);
575 WARN("(%p)->(%d %p) semi-stub\n", This, UicItem, pUicHandling);
577 *pUicHandling = SCRIPTUICHANDLING_ALLOW;
578 return S_OK;
581 static const IActiveScriptSiteUIControlVtbl ActiveScriptSiteUIControlVtbl = {
582 ActiveScriptSiteUIControl_QueryInterface,
583 ActiveScriptSiteUIControl_AddRef,
584 ActiveScriptSiteUIControl_Release,
585 ActiveScriptSiteUIControl_GetUIBehavior
588 static inline ScriptHost *impl_from_IActiveScriptSiteDebug(IActiveScriptSiteDebug *iface)
590 return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSiteDebug_iface);
593 static HRESULT WINAPI ActiveScriptSiteDebug_QueryInterface(IActiveScriptSiteDebug *iface,
594 REFIID riid, void **ppv)
596 ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
597 return IActiveScriptSite_QueryInterface(&This->IActiveScriptSite_iface, riid, ppv);
600 static ULONG WINAPI ActiveScriptSiteDebug_AddRef(IActiveScriptSiteDebug *iface)
602 ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
603 return IActiveScriptSite_AddRef(&This->IActiveScriptSite_iface);
606 static ULONG WINAPI ActiveScriptSiteDebug_Release(IActiveScriptSiteDebug *iface)
608 ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
609 return IActiveScriptSite_Release(&This->IActiveScriptSite_iface);
612 static HRESULT WINAPI ActiveScriptSiteDebug_GetDocumentContextFromPosition(IActiveScriptSiteDebug *iface,
613 CTXARG_T dwSourceContext, ULONG uCharacterOffset, ULONG uNumChars, IDebugDocumentContext **ppsc)
615 ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
616 FIXME("(%p)->(%s %lu %lu %p)\n", This, wine_dbgstr_longlong(dwSourceContext), uCharacterOffset,
617 uNumChars, ppsc);
618 return E_NOTIMPL;
621 static HRESULT WINAPI ActiveScriptSiteDebug_GetApplication(IActiveScriptSiteDebug *iface, IDebugApplication **ppda)
623 ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
624 FIXME("(%p)->(%p)\n", This, ppda);
625 return E_NOTIMPL;
628 static HRESULT WINAPI ActiveScriptSiteDebug_GetRootApplicationNode(IActiveScriptSiteDebug *iface,
629 IDebugApplicationNode **ppdanRoot)
631 ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
632 FIXME("(%p)->(%p)\n", This, ppdanRoot);
633 return E_NOTIMPL;
636 static HRESULT WINAPI ActiveScriptSiteDebug_OnScriptErrorDebug(IActiveScriptSiteDebug *iface,
637 IActiveScriptErrorDebug *pErrorDebug, BOOL *pfEnterDebugger, BOOL *pfCallOnScriptErrorWhenContinuing)
639 ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
640 FIXME("(%p)->(%p %p %p)\n", This, pErrorDebug, pfEnterDebugger, pfCallOnScriptErrorWhenContinuing);
641 return E_NOTIMPL;
644 static const IActiveScriptSiteDebugVtbl ActiveScriptSiteDebugVtbl = {
645 ActiveScriptSiteDebug_QueryInterface,
646 ActiveScriptSiteDebug_AddRef,
647 ActiveScriptSiteDebug_Release,
648 ActiveScriptSiteDebug_GetDocumentContextFromPosition,
649 ActiveScriptSiteDebug_GetApplication,
650 ActiveScriptSiteDebug_GetRootApplicationNode,
651 ActiveScriptSiteDebug_OnScriptErrorDebug
654 static inline ScriptHost *impl_from_IServiceProvider(IServiceProvider *iface)
656 return CONTAINING_RECORD(iface, ScriptHost, IServiceProvider_iface);
659 static HRESULT WINAPI ASServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
661 ScriptHost *This = impl_from_IServiceProvider(iface);
662 return IActiveScriptSite_QueryInterface(&This->IActiveScriptSite_iface, riid, ppv);
665 static ULONG WINAPI ASServiceProvider_AddRef(IServiceProvider *iface)
667 ScriptHost *This = impl_from_IServiceProvider(iface);
668 return IActiveScriptSite_AddRef(&This->IActiveScriptSite_iface);
671 static ULONG WINAPI ASServiceProvider_Release(IServiceProvider *iface)
673 ScriptHost *This = impl_from_IServiceProvider(iface);
674 return IActiveScriptSite_Release(&This->IActiveScriptSite_iface);
677 static HRESULT WINAPI ASServiceProvider_QueryService(IServiceProvider *iface, REFGUID guidService,
678 REFIID riid, void **ppv)
680 ScriptHost *This = impl_from_IServiceProvider(iface);
682 if(!This->window || !This->window->doc)
683 return E_NOINTERFACE;
685 return IServiceProvider_QueryService(&This->window->doc->IServiceProvider_iface, guidService, riid, ppv);
688 static const IServiceProviderVtbl ASServiceProviderVtbl = {
689 ASServiceProvider_QueryInterface,
690 ASServiceProvider_AddRef,
691 ASServiceProvider_Release,
692 ASServiceProvider_QueryService
695 static inline ScriptHost *impl_from_IOleCommandTarget(IOleCommandTarget *iface)
697 return CONTAINING_RECORD(iface, ScriptHost, IOleCommandTarget_iface);
700 static HRESULT WINAPI OleCommandTarget_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv)
702 ScriptHost *This = impl_from_IOleCommandTarget(iface);
703 return IActiveScriptSite_QueryInterface(&This->IActiveScriptSite_iface, riid, ppv);
706 static ULONG WINAPI OleCommandTarget_AddRef(IOleCommandTarget *iface)
708 ScriptHost *This = impl_from_IOleCommandTarget(iface);
709 return IActiveScriptSite_AddRef(&This->IActiveScriptSite_iface);
712 static ULONG WINAPI OleCommandTarget_Release(IOleCommandTarget *iface)
714 ScriptHost *This = impl_from_IOleCommandTarget(iface);
715 return IActiveScriptSite_Release(&This->IActiveScriptSite_iface);
718 static HRESULT WINAPI OleCommandTarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
719 ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
721 ScriptHost *This = impl_from_IOleCommandTarget(iface);
723 FIXME("(%p)->(%s %ld %p %p)\n", This, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
725 return E_NOTIMPL;
728 static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
729 DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
731 ScriptHost *This = impl_from_IOleCommandTarget(iface);
733 TRACE("(%p)->(%s %ld %ld %s %p)\n", This, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, wine_dbgstr_variant(pvaIn), pvaOut);
735 if(!pguidCmdGroup) {
736 FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
737 return OLECMDERR_E_UNKNOWNGROUP;
740 if(IsEqualGUID(&CGID_ScriptSite, pguidCmdGroup)) {
741 switch(nCmdID) {
742 case CMDID_SCRIPTSITE_SECURITY_WINDOW:
743 if(!This->window || !This->window->base.outer_window) {
744 FIXME("No window\n");
745 return E_FAIL;
747 V_VT(pvaOut) = VT_DISPATCH;
748 V_DISPATCH(pvaOut) = (IDispatch*)&This->window->base.outer_window->base.IHTMLWindow2_iface;
749 IDispatch_AddRef(V_DISPATCH(pvaOut));
750 break;
752 default:
753 FIXME("Unsupported nCmdID %ld of CGID_ScriptSite group\n", nCmdID);
754 return OLECMDERR_E_NOTSUPPORTED;
756 return S_OK;
759 FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
760 return OLECMDERR_E_UNKNOWNGROUP;
763 static const IOleCommandTargetVtbl OleCommandTargetVtbl = {
764 OleCommandTarget_QueryInterface,
765 OleCommandTarget_AddRef,
766 OleCommandTarget_Release,
767 OleCommandTarget_QueryStatus,
768 OleCommandTarget_Exec
771 static ScriptHost *create_script_host(HTMLInnerWindow *window, const GUID *guid)
773 IActiveScript *script;
774 ScriptHost *ret;
775 HRESULT hres;
777 ret = calloc(1, sizeof(*ret));
778 if(!ret)
779 return NULL;
781 ret->IActiveScriptSite_iface.lpVtbl = &ActiveScriptSiteVtbl;
782 ret->IActiveScriptSiteInterruptPoll_iface.lpVtbl = &ActiveScriptSiteInterruptPollVtbl;
783 ret->IActiveScriptSiteWindow_iface.lpVtbl = &ActiveScriptSiteWindowVtbl;
784 ret->IActiveScriptSiteUIControl_iface.lpVtbl = &ActiveScriptSiteUIControlVtbl;
785 ret->IActiveScriptSiteDebug_iface.lpVtbl = &ActiveScriptSiteDebugVtbl;
786 ret->IServiceProvider_iface.lpVtbl = &ASServiceProviderVtbl;
787 ret->IOleCommandTarget_iface.lpVtbl = &OleCommandTargetVtbl;
788 ret->ref = 1;
789 ret->window = window;
790 ret->script_state = SCRIPTSTATE_UNINITIALIZED;
792 ret->guid = *guid;
793 list_add_tail(&window->script_hosts, &ret->entry);
795 hres = CoCreateInstance(&ret->guid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
796 &IID_IActiveScript, (void**)&script);
797 if(FAILED(hres))
798 WARN("Could not load script engine: %08lx\n", hres);
799 else {
800 BOOL succeeded = init_script_engine(ret, script);
801 ret->script = script;
802 if(!succeeded)
803 release_script_engine(ret);
806 return ret;
809 static void dispatch_script_readystatechange_event(HTMLScriptElement *script)
811 DOMEvent *event;
812 HRESULT hres;
814 if(script->readystate != READYSTATE_LOADED ||
815 dispex_compat_mode(&script->element.node.event_target.dispex) < COMPAT_MODE_IE10) {
816 hres = create_document_event(script->element.node.doc, EVENTID_READYSTATECHANGE, &event);
817 if(SUCCEEDED(hres)) {
818 dispatch_event(&script->element.node.event_target, event);
819 IDOMEvent_Release(&event->IDOMEvent_iface);
823 if(script->readystate == READYSTATE_LOADED) {
824 hres = create_document_event(script->element.node.doc, EVENTID_LOAD, &event);
825 if(SUCCEEDED(hres)) {
826 dispatch_event(&script->element.node.event_target, event);
827 IDOMEvent_Release(&event->IDOMEvent_iface);
832 typedef struct {
833 event_task_t header;
834 HTMLScriptElement *elem;
835 } fire_readystatechange_task_t;
837 static void fire_readystatechange_proc(event_task_t *_task)
839 fire_readystatechange_task_t *task = (fire_readystatechange_task_t*)_task;
841 if(!task->elem->pending_readystatechange_event)
842 return;
844 task->elem->pending_readystatechange_event = FALSE;
845 dispatch_script_readystatechange_event(task->elem);
848 static void fire_readystatechange_task_destr(event_task_t *_task)
850 fire_readystatechange_task_t *task = (fire_readystatechange_task_t*)_task;
852 IHTMLScriptElement_Release(&task->elem->IHTMLScriptElement_iface);
855 static void set_script_elem_readystate(HTMLScriptElement *script_elem, READYSTATE readystate)
857 script_elem->readystate = readystate;
859 if(readystate != READYSTATE_LOADED &&
860 dispex_compat_mode(&script_elem->element.node.event_target.dispex) >= COMPAT_MODE_IE11)
861 return;
863 if(readystate != READYSTATE_INTERACTIVE) {
864 if(!script_elem->element.node.doc->window->parser_callback_cnt) {
865 fire_readystatechange_task_t *task;
866 HRESULT hres;
868 if(script_elem->pending_readystatechange_event)
869 return;
871 task = malloc(sizeof(*task));
872 if(!task)
873 return;
875 IHTMLScriptElement_AddRef(&script_elem->IHTMLScriptElement_iface);
876 task->elem = script_elem;
878 hres = push_event_task(&task->header, script_elem->element.node.doc->window, fire_readystatechange_proc,
879 fire_readystatechange_task_destr, script_elem->element.node.doc->window->task_magic);
880 if(SUCCEEDED(hres))
881 script_elem->pending_readystatechange_event = TRUE;
882 }else {
883 script_elem->pending_readystatechange_event = FALSE;
884 dispatch_script_readystatechange_event(script_elem);
889 static void parse_elem_text(ScriptHost *script_host, HTMLScriptElement *script_elem, LPCWSTR text)
891 EXCEPINFO excepinfo;
892 VARIANT var;
893 HRESULT hres;
895 TRACE("%s\n", debugstr_w(text));
897 VariantInit(&var);
898 memset(&excepinfo, 0, sizeof(excepinfo));
899 TRACE(">>>\n");
900 hres = IActiveScriptParse_ParseScriptText(script_host->parse, text, L"window", NULL, L"</SCRIPT>",
901 0, 0, SCRIPTTEXT_ISVISIBLE|SCRIPTTEXT_HOSTMANAGESSOURCE,
902 &var, &excepinfo);
903 if(SUCCEEDED(hres))
904 TRACE("<<<\n");
905 else
906 WARN("<<< %08lx\n", hres);
909 typedef struct {
910 BSCallback bsc;
912 HTMLScriptElement *script_elem;
913 nsILoadGroup *load_group;
914 nsIRequest *request;
915 DWORD scheme;
917 DWORD size;
918 char *buf;
919 } ScriptBSC;
921 static HRESULT get_binding_text(ScriptBSC *bsc, WCHAR **ret)
923 UINT cp = CP_UTF8;
924 WCHAR *text;
926 if(!bsc->bsc.read) {
927 text = malloc(sizeof(WCHAR));
928 if(!text)
929 return E_OUTOFMEMORY;
930 *text = 0;
931 *ret = text;
932 return S_OK;
935 switch(bsc->bsc.bom) {
936 case BOM_UTF16:
937 if(bsc->bsc.read % sizeof(WCHAR)) {
938 FIXME("The buffer is not a valid utf16 string\n");
939 return E_FAIL;
942 text = malloc(bsc->bsc.read + sizeof(WCHAR));
943 if(!text)
944 return E_OUTOFMEMORY;
946 memcpy(text, bsc->buf, bsc->bsc.read);
947 text[bsc->bsc.read/sizeof(WCHAR)] = 0;
948 break;
950 default:
951 /* FIXME: Try to use charset from HTTP headers first */
952 cp = get_document_charset(bsc->script_elem->element.node.doc);
953 /* fall through */
954 case BOM_UTF8: {
955 DWORD len;
957 len = MultiByteToWideChar(cp, 0, bsc->buf, bsc->bsc.read, NULL, 0);
958 text = malloc((len + 1) * sizeof(WCHAR));
959 if(!text)
960 return E_OUTOFMEMORY;
962 MultiByteToWideChar(cp, 0, bsc->buf, bsc->bsc.read, text, len);
963 text[len] = 0;
967 *ret = text;
968 return S_OK;
971 static void script_file_available(ScriptBSC *bsc)
973 HTMLScriptElement *script_elem = bsc->script_elem;
974 HTMLInnerWindow *window = bsc->bsc.window;
975 ScriptHost *script_host;
976 nsIDOMNode *parent;
977 nsresult nsres;
978 HRESULT hres;
980 assert(window != NULL);
982 hres = get_binding_text(bsc, &script_elem->src_text);
983 if(FAILED(hres))
984 return;
986 script_host = get_elem_script_host(window, script_elem);
987 if(!script_host)
988 return;
990 if(window->parser_callback_cnt) {
991 script_queue_entry_t *queue;
993 TRACE("Adding to queue\n");
995 queue = malloc(sizeof(*queue));
996 if(!queue)
997 return;
999 IHTMLScriptElement_AddRef(&script_elem->IHTMLScriptElement_iface);
1000 queue->script = script_elem;
1002 list_add_tail(&window->script_queue, &queue->entry);
1003 return;
1006 nsres = nsIDOMElement_GetParentNode(script_elem->element.dom_element, &parent);
1007 if(NS_FAILED(nsres) || !parent) {
1008 TRACE("No parent, not executing\n");
1009 script_elem->parse_on_bind = TRUE;
1010 return;
1013 nsIDOMNode_Release(parent);
1015 script_host = get_elem_script_host(window, script_elem);
1016 if(!script_host)
1017 return;
1019 script_elem->parsed = TRUE;
1020 if(script_host->parse)
1021 parse_elem_text(script_host, script_elem, script_elem->src_text);
1024 static inline ScriptBSC *impl_from_BSCallback(BSCallback *iface)
1026 return CONTAINING_RECORD(iface, ScriptBSC, bsc);
1029 static void ScriptBSC_destroy(BSCallback *bsc)
1031 ScriptBSC *This = impl_from_BSCallback(bsc);
1033 if(This->script_elem) {
1034 IHTMLScriptElement_Release(&This->script_elem->IHTMLScriptElement_iface);
1035 This->script_elem = NULL;
1038 if(This->request) {
1039 ERR("Unfinished request\n");
1040 nsIRequest_Release(This->request);
1042 if(This->load_group)
1043 nsILoadGroup_Release(This->load_group);
1045 free(This->buf);
1046 free(This);
1049 static HRESULT ScriptBSC_init_bindinfo(BSCallback *bsc)
1051 return S_OK;
1054 static HRESULT ScriptBSC_start_binding(BSCallback *bsc)
1056 ScriptBSC *This = impl_from_BSCallback(bsc);
1057 nsresult nsres;
1059 This->script_elem->binding = &This->bsc;
1061 if(This->load_group) {
1062 nsres = create_onload_blocker_request(&This->request);
1063 if(NS_SUCCEEDED(nsres)) {
1064 nsres = nsILoadGroup_AddRequest(This->load_group, This->request, NULL);
1065 if(NS_FAILED(nsres))
1066 ERR("AddRequest failed: %08lx\n", nsres);
1070 /* FIXME: We should find a better to decide if 'loading' state is supposed to be used by the protocol. */
1071 if(This->scheme == URL_SCHEME_HTTPS || This->scheme == URL_SCHEME_HTTP)
1072 set_script_elem_readystate(This->script_elem, READYSTATE_LOADING);
1074 return S_OK;
1077 static HRESULT ScriptBSC_stop_binding(BSCallback *bsc, HRESULT result)
1079 ScriptBSC *This = impl_from_BSCallback(bsc);
1080 nsresult nsres;
1082 if(SUCCEEDED(result) && !This->script_elem)
1083 result = E_UNEXPECTED;
1085 assert(FAILED(result) || This->script_elem->binding == &This->bsc);
1086 This->script_elem->binding = NULL;
1088 if(This->script_elem->readystate == READYSTATE_LOADING)
1089 set_script_elem_readystate(This->script_elem, READYSTATE_LOADED);
1091 if(SUCCEEDED(result)) {
1092 script_file_available(This);
1093 }else {
1094 FIXME("binding failed %08lx\n", result);
1095 free(This->buf);
1096 This->buf = NULL;
1097 This->size = 0;
1100 if(This->request) {
1101 nsres = nsILoadGroup_RemoveRequest(This->load_group, This->request, NULL, NS_OK);
1102 if(NS_FAILED(nsres))
1103 ERR("RemoveRequest failed: %08lx\n", nsres);
1104 nsIRequest_Release(This->request);
1105 This->request = NULL;
1108 IHTMLScriptElement_Release(&This->script_elem->IHTMLScriptElement_iface);
1109 This->script_elem = NULL;
1110 return S_OK;
1113 static HRESULT ScriptBSC_read_data(BSCallback *bsc, IStream *stream)
1115 ScriptBSC *This = impl_from_BSCallback(bsc);
1116 DWORD read;
1117 HRESULT hres;
1119 if(!This->buf) {
1120 This->buf = malloc(128);
1121 if(!This->buf)
1122 return E_OUTOFMEMORY;
1123 This->size = 128;
1126 do {
1127 if(This->bsc.read >= This->size) {
1128 void *new_buf;
1129 new_buf = realloc(This->buf, This->size << 1);
1130 if(!new_buf)
1131 return E_OUTOFMEMORY;
1132 This->size <<= 1;
1133 This->buf = new_buf;
1136 hres = read_stream(&This->bsc, stream, This->buf+This->bsc.read, This->size-This->bsc.read, &read);
1137 }while(hres == S_OK);
1139 return S_OK;
1142 static HRESULT ScriptBSC_on_progress(BSCallback *bsc, ULONG progress, ULONG total, ULONG status_code, LPCWSTR status_text)
1144 return S_OK;
1147 static HRESULT ScriptBSC_on_response(BSCallback *bsc, DWORD response_code,
1148 LPCWSTR response_headers)
1150 return S_OK;
1153 static HRESULT ScriptBSC_beginning_transaction(BSCallback *bsc, WCHAR **additional_headers)
1155 return S_FALSE;
1158 static const BSCallbackVtbl ScriptBSCVtbl = {
1159 ScriptBSC_destroy,
1160 ScriptBSC_init_bindinfo,
1161 ScriptBSC_start_binding,
1162 ScriptBSC_stop_binding,
1163 ScriptBSC_read_data,
1164 ScriptBSC_on_progress,
1165 ScriptBSC_on_response,
1166 ScriptBSC_beginning_transaction
1170 HRESULT load_script(HTMLScriptElement *script_elem, const WCHAR *src, BOOL async)
1172 HTMLInnerWindow *window;
1173 ScriptBSC *bsc;
1174 IMoniker *mon;
1175 IUri *uri;
1176 HRESULT hres;
1178 static const WCHAR wine_schemaW[] = {'w','i','n','e',':'};
1180 if(lstrlenW(src) > ARRAY_SIZE(wine_schemaW) && !memcmp(src, wine_schemaW, sizeof(wine_schemaW)))
1181 src += ARRAY_SIZE(wine_schemaW);
1183 TRACE("(%p %s %x)\n", script_elem, debugstr_w(src), async);
1185 if(!script_elem->element.node.doc || !(window = script_elem->element.node.doc->window)) {
1186 ERR("no window\n");
1187 return E_UNEXPECTED;
1190 hres = create_uri(src, 0, &uri);
1191 if(FAILED(hres))
1192 return hres;
1194 hres = CreateURLMonikerEx2(NULL, uri, &mon, URL_MK_UNIFORM);
1195 if(FAILED(hres)) {
1196 IUri_Release(uri);
1197 return hres;
1200 bsc = calloc(1, sizeof(*bsc));
1201 if(!bsc) {
1202 IMoniker_Release(mon);
1203 IUri_Release(uri);
1204 return E_OUTOFMEMORY;
1207 init_bscallback(&bsc->bsc, &ScriptBSCVtbl, mon, async ? BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA : 0);
1208 IMoniker_Release(mon);
1210 hres = IUri_GetScheme(uri, &bsc->scheme);
1211 IUri_Release(uri);
1212 if(hres != S_OK)
1213 bsc->scheme = URL_SCHEME_UNKNOWN;
1215 IHTMLScriptElement_AddRef(&script_elem->IHTMLScriptElement_iface);
1216 bsc->script_elem = script_elem;
1218 if(window->bscallback && window->bscallback->nschannel &&
1219 window->bscallback->nschannel->load_group) {
1220 cpp_bool contains;
1221 nsresult nsres;
1223 nsres = nsIDOMNode_Contains(script_elem->element.node.doc->node.nsnode,
1224 script_elem->element.node.nsnode, &contains);
1225 if(NS_SUCCEEDED(nsres) && contains) {
1226 TRACE("script %p will block load event\n", script_elem);
1227 bsc->load_group = window->bscallback->nschannel->load_group;
1228 nsILoadGroup_AddRef(bsc->load_group);
1232 hres = start_binding(window, &bsc->bsc, NULL);
1234 IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
1235 return hres;
1238 static void parse_inline_script(ScriptHost *script_host, HTMLScriptElement *script_elem)
1240 const PRUnichar *text;
1241 nsAString text_str;
1242 nsresult nsres;
1244 nsAString_Init(&text_str, NULL);
1245 nsres = nsIDOMHTMLScriptElement_GetText(script_elem->nsscript, &text_str);
1246 nsAString_GetData(&text_str, &text);
1248 set_script_elem_readystate(script_elem, READYSTATE_INTERACTIVE);
1250 if(NS_FAILED(nsres)) {
1251 ERR("GetText failed: %08lx\n", nsres);
1252 }else if(*text) {
1253 parse_elem_text(script_host, script_elem, text);
1256 nsAString_Finish(&text_str);
1259 static BOOL parse_script_elem(ScriptHost *script_host, HTMLScriptElement *script_elem)
1261 nsAString src_str, event_str;
1262 BOOL is_complete = FALSE;
1263 const PRUnichar *src;
1264 nsresult nsres;
1266 nsAString_Init(&event_str, NULL);
1267 nsres = nsIDOMHTMLScriptElement_GetEvent(script_elem->nsscript, &event_str);
1268 if(NS_SUCCEEDED(nsres)) {
1269 const PRUnichar *event;
1271 nsAString_GetData(&event_str, &event);
1272 if(*event) {
1273 TRACE("deferring event %s script evaluation\n", debugstr_w(event));
1274 nsAString_Finish(&event_str);
1275 return FALSE;
1277 }else {
1278 ERR("GetEvent failed: %08lx\n", nsres);
1280 nsAString_Finish(&event_str);
1282 nsAString_Init(&src_str, NULL);
1283 nsres = nsIDOMHTMLScriptElement_GetSrc(script_elem->nsscript, &src_str);
1284 nsAString_GetData(&src_str, &src);
1286 if(NS_FAILED(nsres)) {
1287 ERR("GetSrc failed: %08lx\n", nsres);
1288 }else if(*src) {
1289 load_script(script_elem, src, FALSE);
1290 is_complete = script_elem->parsed;
1291 }else {
1292 parse_inline_script(script_host, script_elem);
1293 is_complete = TRUE;
1296 nsAString_Finish(&src_str);
1298 return is_complete;
1301 static GUID get_default_script_guid(HTMLInnerWindow *window)
1303 /* If not specified, we should use very first script host that was created for the page (or JScript if none) */
1304 return list_empty(&window->script_hosts)
1305 ? CLSID_JScript
1306 : LIST_ENTRY(list_head(&window->script_hosts), ScriptHost, entry)->guid;
1309 static BOOL get_guid_from_type(LPCWSTR type, GUID *guid)
1311 /* FIXME: Handle more types */
1312 if(!wcsicmp(type, L"text/javascript") || !wcsicmp(type, L"text/jscript")) {
1313 *guid = CLSID_JScript;
1314 }else if(!wcsicmp(type, L"text/vbscript")) {
1315 *guid = CLSID_VBScript;
1316 }else {
1317 FIXME("Unknown type %s\n", debugstr_w(type));
1318 return FALSE;
1321 return TRUE;
1324 static BOOL get_guid_from_language(LPCWSTR type, GUID *guid)
1326 HRESULT hres;
1328 hres = CLSIDFromProgID(type, guid);
1329 if(FAILED(hres))
1330 return FALSE;
1332 /* FIXME: Check CATID_ActiveScriptParse */
1334 return TRUE;
1337 static BOOL get_script_guid(HTMLInnerWindow *window, nsIDOMHTMLScriptElement *nsscript, GUID *guid)
1339 nsIDOMElement *nselem;
1340 const PRUnichar *language;
1341 nsAString val_str;
1342 BOOL ret = FALSE;
1343 nsresult nsres;
1345 nsAString_Init(&val_str, NULL);
1347 nsres = nsIDOMHTMLScriptElement_GetType(nsscript, &val_str);
1348 if(NS_SUCCEEDED(nsres)) {
1349 const PRUnichar *type;
1351 nsAString_GetData(&val_str, &type);
1352 if(*type) {
1353 ret = get_guid_from_type(type, guid);
1354 nsAString_Finish(&val_str);
1355 return ret;
1357 }else {
1358 ERR("GetType failed: %08lx\n", nsres);
1361 nsres = nsIDOMHTMLScriptElement_QueryInterface(nsscript, &IID_nsIDOMElement, (void**)&nselem);
1362 assert(nsres == NS_OK);
1364 nsres = get_elem_attr_value(nselem, L"language", &val_str, &language);
1365 nsIDOMElement_Release(nselem);
1366 if(NS_SUCCEEDED(nsres)) {
1367 if(*language) {
1368 ret = get_guid_from_language(language, guid);
1369 }else {
1370 *guid = get_default_script_guid(window);
1371 ret = TRUE;
1373 nsAString_Finish(&val_str);
1376 return ret;
1379 static ScriptHost *get_script_host(HTMLInnerWindow *window, const GUID *guid)
1381 ScriptHost *iter;
1383 LIST_FOR_EACH_ENTRY(iter, &window->script_hosts, ScriptHost, entry) {
1384 if(IsEqualGUID(guid, &iter->guid))
1385 return iter;
1388 return create_script_host(window, guid);
1391 void initialize_script_global(HTMLInnerWindow *script_global)
1393 ScriptHost *script_host;
1394 HRESULT hres;
1396 if(script_global->jscript)
1397 return;
1399 script_host = get_script_host(script_global, &CLSID_JScript);
1400 if(!script_host)
1401 return;
1403 hres = IActiveScript_QueryInterface(script_host->script, &IID_IWineJScript, (void **)&script_global->jscript);
1404 if(FAILED(hres))
1405 ERR("Could not get IWineJScript, don't use native jscript.dll\n");
1408 static ScriptHost *get_elem_script_host(HTMLInnerWindow *window, HTMLScriptElement *script_elem)
1410 GUID guid;
1412 if(!get_script_guid(window, script_elem->nsscript, &guid)) {
1413 WARN("Could not find script GUID\n");
1414 return NULL;
1417 if(IsEqualGUID(&CLSID_JScript, &guid) && (!window->doc->browser || window->doc->browser->script_mode != SCRIPTMODE_ACTIVESCRIPT)) {
1418 TRACE("Ignoring JScript\n");
1419 return NULL;
1422 return get_script_host(window, &guid);
1425 void doc_insert_script(HTMLInnerWindow *window, HTMLScriptElement *script_elem, BOOL from_parser)
1427 ScriptHost *script_host;
1428 BOOL is_complete = FALSE;
1430 script_host = get_elem_script_host(window, script_elem);
1431 if(!script_host)
1432 return;
1434 if(script_host->parse) {
1435 if(script_elem->src_text) {
1436 if(from_parser)
1437 set_script_elem_readystate(script_elem, READYSTATE_INTERACTIVE);
1438 script_elem->parsed = TRUE;
1439 parse_elem_text(script_host, script_elem, script_elem->src_text);
1440 is_complete = TRUE;
1441 }else if(!script_elem->binding) {
1442 is_complete = parse_script_elem(script_host, script_elem);
1446 if(is_complete)
1447 set_script_elem_readystate(script_elem, READYSTATE_COMPLETE);
1450 IDispatch *script_parse_event(HTMLInnerWindow *window, LPCWSTR text)
1452 ScriptHost *script_host;
1453 GUID guid;
1454 const WCHAR *ptr;
1455 IDispatch *disp;
1456 HRESULT hres;
1458 TRACE("%s\n", debugstr_w(text));
1460 for(ptr = text; iswalnum(*ptr); ptr++);
1461 if(*ptr == ':') {
1462 LPWSTR language;
1463 BOOL b;
1465 language = malloc((ptr - text + 1) * sizeof(WCHAR));
1466 if(!language)
1467 return NULL;
1469 memcpy(language, text, (ptr-text)*sizeof(WCHAR));
1470 language[ptr-text] = 0;
1472 b = get_guid_from_language(language, &guid);
1474 free(language);
1476 if(!b) {
1477 WARN("Could not find language\n");
1478 return NULL;
1481 ptr++;
1482 }else {
1483 ptr = text;
1484 guid = get_default_script_guid(window);
1487 if(IsEqualGUID(&CLSID_JScript, &guid)
1488 && (!window->doc->browser || window->doc->browser->script_mode != SCRIPTMODE_ACTIVESCRIPT)) {
1489 TRACE("Ignoring JScript\n");
1490 return NULL;
1493 script_host = get_script_host(window, &guid);
1494 if(!script_host || !script_host->parse_proc)
1495 return NULL;
1497 hres = IActiveScriptParseProcedure2_ParseProcedureText(script_host->parse_proc, ptr, NULL, L"",
1498 NULL, NULL, L"\"", 0 /* FIXME */, 0,
1499 SCRIPTPROC_HOSTMANAGESSOURCE|SCRIPTPROC_IMPLICIT_THIS|SCRIPTPROC_IMPLICIT_PARENTS, &disp);
1500 if(FAILED(hres)) {
1501 WARN("ParseProcedureText failed: %08lx\n", hres);
1502 return NULL;
1505 TRACE("ret %p\n", disp);
1506 return disp;
1509 HRESULT exec_script(HTMLInnerWindow *window, const WCHAR *code, const WCHAR *lang, VARIANT *ret)
1511 ScriptHost *script_host;
1512 EXCEPINFO ei;
1513 GUID guid;
1514 HRESULT hres;
1516 if(!get_guid_from_language(lang, &guid)) {
1517 WARN("Could not find script GUID\n");
1518 return CO_E_CLASSSTRING;
1521 script_host = get_script_host(window, &guid);
1522 if(!script_host) {
1523 FIXME("No script host\n");
1524 return E_FAIL;
1527 if(!script_host->parse) {
1528 FIXME("script_host->parse == NULL\n");
1529 return E_FAIL;
1532 memset(&ei, 0, sizeof(ei));
1533 TRACE(">>>\n");
1534 hres = IActiveScriptParse_ParseScriptText(script_host->parse, code, NULL, NULL, L"\"", 0, 0, SCRIPTTEXT_ISVISIBLE, ret, &ei);
1535 if(SUCCEEDED(hres))
1536 TRACE("<<<\n");
1537 else
1538 WARN("<<< %08lx\n", hres);
1540 return hres;
1543 IDispatch *get_script_disp(ScriptHost *script_host)
1545 IDispatch *disp;
1546 HRESULT hres;
1548 if(!script_host->script)
1549 return NULL;
1551 hres = IActiveScript_GetScriptDispatch(script_host->script, L"window", &disp);
1552 if(FAILED(hres))
1553 return NULL;
1555 return disp;
1558 IActiveScriptSite *get_first_script_site(HTMLInnerWindow *window)
1560 if(list_empty(&window->script_hosts)) {
1561 ScriptHost *script_host = create_script_host(window, &CLSID_JScript);
1562 if(!script_host)
1563 return NULL;
1565 return &LIST_ENTRY(list_head(&window->script_hosts), ScriptHost, entry)->IActiveScriptSite_iface;
1568 static EventTarget *find_event_target(HTMLDocumentNode *doc, HTMLScriptElement *script_elem)
1570 EventTarget *event_target = NULL;
1571 const PRUnichar *target_id;
1572 nsAString target_id_str;
1573 nsresult nsres;
1574 HRESULT hres;
1576 nsAString_Init(&target_id_str, NULL);
1577 nsres = nsIDOMHTMLScriptElement_GetHtmlFor(script_elem->nsscript, &target_id_str);
1578 if(NS_FAILED(nsres)) {
1579 ERR("GetScriptFor failed: %08lx\n", nsres);
1580 nsAString_Finish(&target_id_str);
1581 return NULL;
1584 nsAString_GetData(&target_id_str, &target_id);
1585 if(!*target_id) {
1586 FIXME("Empty for attribute\n");
1587 }else if(!wcscmp(target_id, L"document")) {
1588 event_target = &doc->node.event_target;
1589 IHTMLDOMNode_AddRef(&doc->node.IHTMLDOMNode_iface);
1590 }else if(!wcscmp(target_id, L"window")) {
1591 if(doc->window) {
1592 event_target = &doc->window->event_target;
1593 IWineJSDispatchHost_AddRef(&event_target->dispex.IWineJSDispatchHost_iface);
1595 }else {
1596 HTMLElement *target_elem;
1598 hres = get_doc_elem_by_id(doc, target_id, &target_elem);
1599 if(SUCCEEDED(hres) && target_elem) {
1600 event_target = &target_elem->node.event_target;
1604 nsAString_Finish(&target_id_str);
1605 return event_target;
1608 static BOOL parse_event_str(WCHAR *event, const WCHAR **args)
1610 WCHAR *ptr;
1612 TRACE("%s\n", debugstr_w(event));
1614 for(ptr = event; iswalnum(*ptr); ptr++);
1615 if(!*ptr) {
1616 *args = NULL;
1617 return TRUE;
1620 if(*ptr != '(')
1621 return FALSE;
1623 *ptr++ = 0;
1624 *args = ptr;
1625 while(iswalnum(*ptr) || iswspace(*ptr) || *ptr == ',')
1626 ptr++;
1628 if(*ptr != ')')
1629 return FALSE;
1631 *ptr++ = 0;
1632 return !*ptr;
1635 static IDispatch *parse_event_elem(HTMLDocumentNode *doc, HTMLScriptElement *script_elem, WCHAR **ret_event)
1637 ScriptHost *script_host;
1638 WCHAR *event = NULL;
1639 const WCHAR *args;
1640 nsAString nsstr;
1641 IDispatch *disp;
1642 nsresult nsres;
1643 HRESULT hres;
1645 if(script_elem->parsed)
1646 return NULL;
1648 script_host = get_elem_script_host(doc->window, script_elem);
1649 if(!script_host || !script_host->parse_proc)
1650 return NULL;
1652 nsAString_Init(&nsstr, NULL);
1653 nsres = nsIDOMHTMLScriptElement_GetEvent(script_elem->nsscript, &nsstr);
1654 if(NS_SUCCEEDED(nsres)) {
1655 const PRUnichar *event_val;
1657 nsAString_GetData(&nsstr, &event_val);
1658 event = wcsdup(event_val);
1660 nsAString_Finish(&nsstr);
1661 if(!event)
1662 return NULL;
1664 if(!parse_event_str(event, &args)) {
1665 WARN("parsing %s failed\n", debugstr_w(event));
1666 free(event);
1667 return NULL;
1670 nsAString_Init(&nsstr, NULL);
1671 nsres = nsIDOMHTMLScriptElement_GetText(script_elem->nsscript, &nsstr);
1672 if(NS_SUCCEEDED(nsres)) {
1673 const PRUnichar *text;
1675 nsAString_GetData(&nsstr, &text);
1676 hres = IActiveScriptParseProcedure2_ParseProcedureText(script_host->parse_proc, text, args,
1677 L"", NULL, NULL, L"</SCRIPT>", 0, 0,
1678 SCRIPTPROC_HOSTMANAGESSOURCE|SCRIPTPROC_IMPLICIT_THIS|SCRIPTPROC_IMPLICIT_PARENTS, &disp);
1679 if(FAILED(hres))
1680 disp = NULL;
1681 }else {
1682 ERR("GetText failed: %08lx\n", nsres);
1683 disp = NULL;
1685 nsAString_Finish(&nsstr);
1686 if(!disp) {
1687 free(event);
1688 return NULL;
1691 *ret_event = event;
1692 return disp;
1695 void bind_event_scripts(HTMLDocumentNode *doc)
1697 HTMLPluginContainer *plugin_container;
1698 nsIDOMHTMLScriptElement *nsscript;
1699 nsIDOMNodeList *node_list = NULL;
1700 HTMLScriptElement *script_elem;
1701 EventTarget *event_target;
1702 nsIDOMNode *script_node;
1703 nsAString selector_str;
1704 IDispatch *event_disp;
1705 UINT32 length, i;
1706 WCHAR *event;
1707 nsresult nsres;
1708 HRESULT hres;
1710 TRACE("%p\n", doc);
1712 if(!doc->dom_document)
1713 return;
1715 nsAString_InitDepend(&selector_str, L"script[event]");
1716 nsres = nsIDOMDocument_QuerySelectorAll(doc->dom_document, &selector_str, &node_list);
1717 nsAString_Finish(&selector_str);
1718 if(NS_FAILED(nsres)) {
1719 ERR("QuerySelectorAll failed: %08lx\n", nsres);
1720 if(node_list)
1721 nsIDOMNodeList_Release(node_list);
1722 return;
1725 if(!node_list)
1726 return;
1728 nsres = nsIDOMNodeList_GetLength(node_list, &length);
1729 assert(nsres == NS_OK);
1731 for(i=0; i < length; i++) {
1732 nsres = nsIDOMNodeList_Item(node_list, i, &script_node);
1733 if(NS_FAILED(nsres) || !script_node) {
1734 ERR("Item(%d) failed: %08lx\n", i, nsres);
1735 continue;
1738 nsres = nsIDOMNode_QueryInterface(script_node, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
1739 assert(nsres == NS_OK);
1740 nsIDOMNode_Release(script_node);
1742 hres = script_elem_from_nsscript(nsscript, &script_elem);
1743 nsIDOMHTMLScriptElement_Release(nsscript);
1744 if(FAILED(hres))
1745 continue;
1747 event_disp = parse_event_elem(doc, script_elem, &event);
1748 if(event_disp) {
1749 event_target = find_event_target(doc, script_elem);
1750 if(event_target) {
1751 hres = IWineJSDispatchHost_QueryInterface(&event_target->dispex.IWineJSDispatchHost_iface, &IID_HTMLPluginContainer,
1752 (void**)&plugin_container);
1753 if(SUCCEEDED(hres))
1754 bind_activex_event(doc, plugin_container, event, event_disp);
1755 else
1756 bind_target_event(doc, event_target, event, event_disp);
1758 IWineJSDispatchHost_Release(&event_target->dispex.IWineJSDispatchHost_iface);
1759 if(plugin_container)
1760 node_release(&plugin_container->element.node);
1763 free(event);
1764 IDispatch_Release(event_disp);
1767 IHTMLScriptElement_Release(&script_elem->IHTMLScriptElement_iface);
1770 nsIDOMNodeList_Release(node_list);
1773 BOOL find_global_prop(HTMLInnerWindow *window, const WCHAR *name, DWORD flags, ScriptHost **ret_host, DISPID *ret_id)
1775 IDispatchEx *dispex;
1776 IDispatch *disp;
1777 ScriptHost *iter;
1778 BSTR str;
1779 HRESULT hres;
1781 if(!(str = SysAllocString(name)))
1782 return E_OUTOFMEMORY;
1784 LIST_FOR_EACH_ENTRY(iter, &window->script_hosts, ScriptHost, entry) {
1785 disp = get_script_disp(iter);
1786 if(!disp)
1787 continue;
1789 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1790 if(SUCCEEDED(hres)) {
1791 hres = IDispatchEx_GetDispID(dispex, str, flags & (~fdexNameEnsure), ret_id);
1792 IDispatchEx_Release(dispex);
1793 }else {
1794 FIXME("No IDispatchEx\n");
1795 hres = E_NOTIMPL;
1798 IDispatch_Release(disp);
1799 if(SUCCEEDED(hres)) {
1800 SysFreeString(str);
1801 *ret_host = iter;
1802 return TRUE;
1806 SysFreeString(str);
1807 return FALSE;
1810 static BOOL is_jscript_available(void)
1812 static BOOL available, checked;
1814 if(!checked) {
1815 IUnknown *unk;
1816 HRESULT hres = CoGetClassObject(&CLSID_JScript, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk);
1818 if(SUCCEEDED(hres)) {
1819 available = TRUE;
1820 IUnknown_Release(unk);
1821 }else {
1822 available = FALSE;
1824 checked = TRUE;
1827 return available;
1830 static BOOL use_gecko_script(IUri *uri)
1832 BSTR display_uri;
1833 DWORD zone;
1834 HRESULT hres;
1836 hres = IUri_GetDisplayUri(uri, &display_uri);
1837 if(FAILED(hres))
1838 return FALSE;
1840 hres = IInternetSecurityManager_MapUrlToZone(get_security_manager(), display_uri, &zone, 0);
1841 if(FAILED(hres)) {
1842 WARN("Could not map %s to zone: %08lx\n", debugstr_w(display_uri), hres);
1843 SysFreeString(display_uri);
1844 return TRUE;
1847 SysFreeString(display_uri);
1848 TRACE("zone %ld\n", zone);
1849 return zone == URLZONE_UNTRUSTED;
1852 void update_browser_script_mode(GeckoBrowser *browser, IUri *uri)
1854 nsIWebBrowserSetup *setup;
1855 nsresult nsres;
1857 if(!is_jscript_available()) {
1858 TRACE("jscript.dll not available\n");
1859 browser->script_mode = SCRIPTMODE_GECKO;
1860 return;
1863 browser->script_mode = use_gecko_script(uri) ? SCRIPTMODE_GECKO : SCRIPTMODE_ACTIVESCRIPT;
1865 nsres = nsIWebBrowser_QueryInterface(browser->webbrowser, &IID_nsIWebBrowserSetup, (void**)&setup);
1866 if(NS_SUCCEEDED(nsres)) {
1867 nsres = nsIWebBrowserSetup_SetProperty(setup, SETUP_ALLOW_JAVASCRIPT,
1868 browser->script_mode == SCRIPTMODE_GECKO);
1870 if(NS_SUCCEEDED(nsres))
1871 nsres = nsIWebBrowserSetup_SetProperty(setup, SETUP_DISABLE_NOSCRIPT, TRUE);
1873 nsIWebBrowserSetup_Release(setup);
1876 if(NS_FAILED(nsres))
1877 ERR("JavaScript setup failed: %08lx\n", nsres);
1880 void release_script_hosts(HTMLInnerWindow *window)
1882 script_queue_entry_t *queue_iter;
1883 ScriptHost *iter;
1885 while(!list_empty(&window->script_queue)) {
1886 queue_iter = LIST_ENTRY(list_head(&window->script_queue), script_queue_entry_t, entry);
1888 list_remove(&queue_iter->entry);
1889 IHTMLScriptElement_Release(&queue_iter->script->IHTMLScriptElement_iface);
1890 free(queue_iter);
1893 while(!list_empty(&window->script_hosts)) {
1894 iter = LIST_ENTRY(list_head(&window->script_hosts), ScriptHost, entry);
1896 release_script_engine(iter);
1897 list_remove(&iter->entry);
1898 iter->window = NULL;
1899 IActiveScriptSite_Release(&iter->IActiveScriptSite_iface);